1 from qmsk.net.lib.event2.event cimport * |
1 from qmsk.net.lib.event2.event cimport * |
2 from qmsk.net.lib.event2.base cimport event_base |
2 from qmsk.net.lib.event2.base cimport event_base |
|
3 cimport qmsk.net.py as py |
3 |
4 |
4 cdef lib.timeval* build_timeout (lib.timeval *tv, object timeout = None) except? <lib.timeval *>-1 : |
5 cdef lib.timeval* build_timeout (lib.timeval *tv, object timeout = None) except? <lib.timeval *>-1 : |
5 """ |
6 """ |
6 If a timeout is given, it is treated as a float and stored in *tv, which is returned. Otherwise, simply returns |
7 If a timeout is given, it is treated as a float and stored in *tv, which is returned. Otherwise, simply returns |
7 NULL. |
8 NULL. |
30 """ |
31 """ |
31 |
32 |
32 # unpack opaque arg |
33 # unpack opaque arg |
33 cdef event ev = <event>arg |
34 cdef event ev = <event>arg |
34 |
35 |
|
36 # drop self-ref if not pending anymore (keep the local ref) |
|
37 # XXX: does the event show up as non-pending here? :/ |
|
38 ev._unmark() |
|
39 |
35 # invoke |
40 # invoke |
36 # XXX: logging? |
41 # XXX: logging? |
37 ev(fd, mask) |
42 ev(fd, mask) |
38 |
43 |
39 |
44 |
40 cdef class event : |
45 cdef class event : |
41 |
46 |
42 def __init__ (self, event_base base not None, lib.evutil_socket_t fd, short events) : |
47 def __init__ (self, event_base base not None, lib.evutil_socket_t fd, short events) : |
|
48 # we don't hold a self-reference yet |
|
49 self.alive = False |
43 |
50 |
44 # libevent seems to segfault otherwise... |
51 # libevent seems to segfault otherwise... |
45 if events & (lib.EV_READ | lib.EV_WRITE) and fd < 0 : |
52 if events & (lib.EV_READ | lib.EV_WRITE) and fd < 0 : |
46 raise ValueError(fd) |
53 raise ValueError(fd) |
47 |
54 |
56 """ |
63 """ |
57 Re-assign our event parameters to the given ones. |
64 Re-assign our event parameters to the given ones. |
58 |
65 |
59 It is illegal to call this method after calling .add() but before del()/callback! |
66 It is illegal to call this method after calling .add() but before del()/callback! |
60 """ |
67 """ |
|
68 |
|
69 if self.alive : |
|
70 raise RuntimeError("Cannot change event while active") |
61 |
71 |
62 # interesting... no error return code |
72 # interesting... no error return code |
63 lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, <void *>self) |
73 lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, <void *>self) |
64 |
74 |
65 |
75 |
77 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 |
87 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 |
78 """ |
88 """ |
79 |
89 |
80 cdef lib.timeval tv |
90 cdef lib.timeval tv |
81 |
91 |
|
92 # aquire self-ref |
|
93 self._mark() |
|
94 |
82 if lib.event_add(self.ev, build_timeout(&tv, timeout)) < 0 : |
95 if lib.event_add(self.ev, build_timeout(&tv, timeout)) < 0 : |
83 raise Exception("event_new") |
96 raise Exception("event_new") |
84 |
97 |
85 |
98 |
86 def delete (self) : |
99 def delete (self) : |
88 Remove this event from our event_base's set of monitored events. |
101 Remove this event from our event_base's set of monitored events. |
89 |
102 |
90 If this event has already executed or has never been added this call with have no effect. |
103 If this event has already executed or has never been added this call with have no effect. |
91 """ |
104 """ |
92 |
105 |
|
106 |
93 if lib.event_del(self.ev) < 0 : |
107 if lib.event_del(self.ev) < 0 : |
94 raise Exception("event_del") |
108 raise Exception("event_del") |
95 |
109 |
|
110 # release self-ref |
|
111 self._unmark() |
|
112 |
96 |
113 |
97 def activate (self, int fd, short mask) : |
114 def activate (self, int fd, short mask) : |
98 """ |
115 """ |
99 'Fake' this event as active, triggering the callback. |
116 'Fake' this event as active, triggering the callback. |
100 """ |
117 """ |
|
118 |
|
119 # aquire self-ref |
|
120 self._mark() |
101 |
121 |
102 lib.event_active(self.ev, fd, mask) |
122 lib.event_active(self.ev, fd, mask) |
103 |
123 |
104 |
124 |
105 def pending (self, short mask = 0xffff) : |
125 cpdef pending (self, short mask = 0xffff) : |
106 """ |
126 """ |
107 Returns a bool indicating if this event is pending (that is, has been .add()'d). |
127 Returns a bool indicating if this event is pending (that is, has been .add()'d). |
108 |
128 |
109 For convenience, this defaults to testing all possible flags, and so will return true if any events are |
129 For convenience, this defaults to testing all possible flags, and so will return true if any events are |
110 pending. |
130 pending. |
112 XXX: support returning timeout value? |
132 XXX: support returning timeout value? |
113 """ |
133 """ |
114 |
134 |
115 return bool(lib.event_pending(self.ev, mask, NULL)) |
135 return bool(lib.event_pending(self.ev, mask, NULL)) |
116 |
136 |
|
137 |
|
138 cdef object _mark (self) : |
|
139 """ |
|
140 Refcount magic. Aquires an internal reference *if we don't have one yet*. |
|
141 """ |
|
142 |
|
143 if not self.alive : |
|
144 self.alive = True |
|
145 |
|
146 py.Py_INCREF(self) |
|
147 |
|
148 |
|
149 cdef object _unmark (self) : |
|
150 """ |
|
151 Refcout magic. Releses the internal reference *if we have one* and libevent doesn't think this event is |
|
152 pending anymore. |
|
153 |
|
154 XXX: this might cause ourselves to be destroyed... we can't break if that happens. |
|
155 """ |
|
156 |
|
157 if self.alive and not self.pending() : |
|
158 py.Py_DECREF(self) |
|
159 |
|
160 self.alive = False |
|
161 |
117 |
162 |
118 property fd : |
163 property fd : |
119 def __get__ (self) : |
164 def __get__ (self) : |
120 """ |
165 """ |
121 Get the OS file descriptor associated with this event. |
166 Get the OS file descriptor associated with this event. |