1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
|
#
# event.pyx
#
# libevent Python bindings
#
# Copyright (c) 2004 Dug Song <dugsong@monkey.org>
# Copyright (c) 2003 Martin Murray <murrayma@citi.umich.edu>
#
# $Id: event.pyx 59 2009-06-25 06:30:14Z dugsong $
"""event library
This module provides a mechanism to execute a function when a
specific event on a file handle, file descriptor, or signal occurs,
or after a given time has passed.
"""
__author__ = ( 'Dug Song <dugsong@monkey.org>',
'Martin Murray <mmurray@monkey.org>' )
__copyright__ = ( 'Copyright (c) 2004 Dug Song',
'Copyright (c) 2003 Martin Murray' )
__license__ = 'BSD'
__url__ = 'http://monkey.org/~dugsong/pyevent/'
__version__ = '0.4'
import sys
cdef extern from "sys/types.h":
ctypedef unsigned char u_char
cdef extern from "Python.h":
void Py_INCREF(object o)
void Py_DECREF(object o)
object PyString_FromStringAndSize(char *v, int len)
object PyString_FromString(char *v)
int PyObject_AsCharBuffer(object obj, char **buffer, int *buffer_len)
ctypedef void (*event_handler)(int fd, short evtype, void *arg)
cdef extern from "event.h":
struct timeval:
unsigned int tv_sec
unsigned int tv_usec
struct event_t "event":
int ev_fd
int ev_flags
void *ev_arg
void event_init()
void event_set(event_t *ev, int fd, short event,
event_handler handler, void *arg)
void evtimer_set(event_t *ev, event_handler handler, void *arg)
int event_add(event_t *ev, timeval *tv)
int event_del(event_t *ev)
int event_dispatch() nogil
int event_loop(int loop) nogil
int event_pending(event_t *ev, short, timeval *tv)
int EVLOOP_ONCE
int EVLOOP_NONBLOCK
EV_TIMEOUT = 0x01
EV_READ = 0x02
EV_WRITE = 0x04
EV_SIGNAL = 0x08
EV_PERSIST = 0x10
__event_exc = None
cdef int __event_sigcb():
return -1
cdef void __event_abort():
global __event_exc
cdef extern int event_gotsig
cdef extern int (*event_sigcb)()
__event_exc = sys.exc_info()
if __event_exc[0] is None:
__event_exc = None
event_sigcb = __event_sigcb
event_gotsig = 1
cdef void __event_handler(int fd, short evtype, void *arg) with gil:
(<object>arg).__callback(evtype)
cdef void __simple_event_handler(int fd, short evtype, void *arg) with gil:
(<object>arg).__simple_callback(evtype)
cdef class event:
"""event(callback, arg=None, evtype=0, handle=None) -> event object
Create a new event object with a user callback.
Arguments:
callback -- user callback with (ev, handle, evtype, arg) prototype
arg -- optional callback arguments
evtype -- bitmask of EV_READ or EV_WRITE, or EV_SIGNAL
handle -- for EV_READ or EV_WRITE, a file handle, descriptor, or socket
for EV_SIGNAL, a signal number
"""
cdef event_t ev
cdef object handle, evtype, callback, args
cdef float timeout
cdef timeval tv
def __init__(self, callback, arg=None, short evtype=0, handle=-1,
simple=0):
cdef event_handler handler
self.callback = callback
self.args = arg
self.evtype = evtype
self.handle = handle
if simple:
handler = __simple_event_handler
else:
handler = __event_handler
if evtype == 0 and not handle:
evtimer_set(&self.ev, handler, <void *>self)
else:
if not isinstance(handle, int):
handle = handle.fileno()
event_set(&self.ev, handle, evtype, handler, <void *>self)
def __simple_callback(self, short evtype):
try:
if self.callback(*self.args) != None:
if self.tv.tv_sec or self.tv.tv_usec:
event_add(&self.ev, &self.tv)
else:
event_add(&self.ev, NULL)
except:
__event_abort()
# XXX - account for event.signal() EV_PERSIST
if not (evtype & EV_SIGNAL) and \
not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_DECREF(self)
def __callback(self, short evtype):
try:
self.callback(self, self.handle, evtype, self.args)
except:
__event_abort()
if not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_DECREF(self)
def add(self, float timeout=-1):
"""Add event to be executed after an optional timeout.
Arguments:
timeout -- seconds after which the event will be executed
"""
if not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT,
NULL):
Py_INCREF(self)
self.timeout = timeout
if timeout >= 0.0:
self.tv.tv_sec = <long>timeout
self.tv.tv_usec = <unsigned int>((timeout - <float>self.tv.tv_sec) * 1000000.0)
event_add(&self.ev, &self.tv)
else:
self.tv.tv_sec = self.tv.tv_usec = 0
event_add(&self.ev, NULL)
def pending(self):
"""Return 1 if the event is scheduled to run, or else 0."""
return event_pending(&self.ev, EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE, NULL)
def delete(self):
"""Remove event from the event queue."""
if self.pending():
event_del(&self.ev)
Py_DECREF(self)
def __dealloc__(self):
self.delete()
def __repr__(self):
return '<event flags=0x%x, handle=%s, callback=%s, arg=%s>' % \
(self.ev.ev_flags, self.handle, self.callback, self.args)
def init():
"""Initialize event queue."""
event_init()
def dispatch():
"""Dispatch all events on the event queue.
Returns -1 on error, 0 on success, and 1 if no events are registered.
"""
cdef int ret
global __event_exc
with nogil:
ret = event_dispatch()
if __event_exc:
t = __event_exc
__event_exc = None
raise t[0], t[1], t[2]
return ret
def loop(nonblock=False):
"""Dispatch all pending events on queue in a single pass.
Returns -1 on error, 0 on success, and 1 if no events are registered."""
cdef int flags, ret
global __event_exc
flags = EVLOOP_ONCE
if nonblock:
flags = EVLOOP_ONCE|EVLOOP_NONBLOCK
with nogil:
ret = event_loop(flags)
if __event_exc:
t = __event_exc
__event_exc = None
raise t[0], t[1], t[2]
return ret
def abort():
"""Abort event dispatch loop."""
__event_abort()
include "simple.pxi"
include "bufferevent.pxi"
include "evdns.pxi"
include "evhttp.pxi"
# XXX - make sure event queue is always initialized.
init()
|