diff -r f0fc793a3754 -r 075eaafa80a7 qmsk/net/lib/event2/event.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/lib/event2/event.pyx Fri Aug 28 21:58:47 2009 +0300 @@ -0,0 +1,136 @@ +from qmsk.net.lib.event2.event cimport * +from qmsk.net.lib.event2.base cimport event_base + +cdef lib.timeval* build_timeout (lib.timeval *tv, object timeout = None) except? -1 : + """ + If a timeout is given, it is treated as a float and stored in *tv, which is returned. Otherwise, simply returns + NULL. + """ + + cdef double t + + if timeout : + t = timeout + + tv.tv_sec = (t) + tv.tv_usec = ((t - t) * 100000) + + return tv + + else : + return NULL + + +# our shared callback handler +# this must aquire the GIL before invoking the python object +# this means that the libevent loop *must* be run with the GIL released! +cdef void ev_callback (lib.evutil_socket_t fd, short mask, void *arg) with gil : + """ + Proxy event back to event object passed as arg + """ + + # unpack opaque arg + cdef event ev = arg + + # invoke + # XXX: logging? + ev(fd, mask) + + +cdef class event : + + def __init__ (self, event_base base, lib.evutil_socket_t fd, short events) : + + # construct event using our internal callback, with self as the arg + self.ev = lib.event_new(base.ev_base, fd, events, ev_callback, self) + + if self.ev == NULL : + raise Exception("event_new") + + + def assign (self, event_base base, lib.evutil_socket_t fd, short events) : + """ + Re-assign our event parameters to the given ones. + + It is illegal to call this method after calling .add() but before del()/callback! + """ + + # interesting... no error return code + lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, self) + + + def add (self, timeout = None) : + """ + Add this event to our event_base's set of monitored events. + + This event will be executed if any of the events specified in 'events' occurs, or the given timeout + expires. If no timeout is given, no timeout will occur. + + If this event already has a shceduled timeout, the old timeout will be replaced by the new one. + + timeout - a float representing the timeout length + + XXX: "The event in the ev argument must be already initialized by event_set() and may not be used in calls to event_set() until it has timed out or been removed with event_del()" -- enforce + """ + + cdef lib.timeval tv + + if lib.event_add(self.ev, build_timeout(&tv, timeout)) < 0 : + raise Exception("event_new") + + + def delete (self) : + """ + Remove this event from our event_base's set of monitored events. + + If this event has already executed or has never been added this call with have no effect. + """ + + if lib.event_del(self.ev) < 0 : + raise Exception("event_del") + + + def activate (self, int fd, short mask) : + """ + 'Fake' this event as active, triggering the callback. + """ + + lib.event_active(self.ev, fd, mask) + + + def pending (self, short mask) : + """ + Returns a bool indicating if this event is pending (that is, has been .add()'d). + + XXX: support returning timeout value? + """ + + return bool(lib.event_pending(self.ev, mask, NULL)) + + + property fd : + def __get__ (self) : + """ + Get the OS file descriptor associated with this event. + """ + + return lib.event_get_fd(self.ev) + + + def __call__ (self, lib.evutil_socket_t fd, short mask) : + """ + The method invoked by the internal libevent callback. + """ + + pass + + + def __dealloc__ (self) : + """ + Release the event object usign event_free. This should be completely safe as regards out event_base. + + XXX: what happens if event_base's __dealloc__ is triggered, but there are still event objects alive? + """ + + lib.event_free(self.ev) +