Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / python / _epoll.pyx
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Interface to epoll I/O event notification facility.
6 """
7
8 # NOTE: The version of Pyrex you are using probably _does not work_ with
9 # Python 2.5.  If you need to recompile this file, _make sure you are using
10 # a version of Pyrex which works with Python 2.5_.  I am using 0.9.4.1 from
11 # <http://codespeak.net/svn/lxml/pyrex/>. -exarkun
12
13 cdef extern from "stdio.h":
14     cdef extern void *malloc(int)
15     cdef extern void free(void *)
16     cdef extern int close(int)
17
18 cdef extern from "errno.h":
19     cdef extern int errno
20     cdef extern char *strerror(int)
21
22 cdef extern from "string.h":
23     cdef extern void *memset(void* s, int c, int n)
24
25 cdef extern from "stdint.h":
26     ctypedef unsigned long uint32_t
27     ctypedef unsigned long long uint64_t
28
29 cdef extern from "sys/epoll.h":
30
31     cdef enum:
32         EPOLL_CTL_ADD = 1
33         EPOLL_CTL_DEL = 2
34         EPOLL_CTL_MOD = 3
35
36     cdef enum EPOLL_EVENTS:
37         c_EPOLLIN "EPOLLIN" = 0x001
38         c_EPOLLPRI "EPOLLPRI" = 0x002
39         c_EPOLLOUT "EPOLLOUT" = 0x004
40         c_EPOLLRDNORM "EPOLLRDNORM" = 0x040
41         c_EPOLLRDBAND "EPOLLRDBAND" = 0x080
42         c_EPOLLWRNORM "EPOLLWRNORM" = 0x100
43         c_EPOLLWRBAND "EPOLLWRBAND" = 0x200
44         c_EPOLLMSG "EPOLLMSG" = 0x400
45         c_EPOLLERR "EPOLLERR" = 0x008
46         c_EPOLLHUP "EPOLLHUP" = 0x010
47         c_EPOLLET "EPOLLET" = (1 << 31)
48
49     ctypedef union epoll_data_t:
50         void *ptr
51         int fd
52         uint32_t u32
53         uint64_t u64
54
55     cdef struct epoll_event:
56         uint32_t events
57         epoll_data_t data
58
59     int epoll_create(int size)
60     int epoll_ctl(int epfd, int op, int fd, epoll_event *event)
61     int epoll_wait(int epfd, epoll_event *events, int maxevents, int timeout)
62
63 cdef extern from "Python.h":
64     ctypedef struct PyThreadState
65     cdef extern PyThreadState *PyEval_SaveThread()
66     cdef extern void PyEval_RestoreThread(PyThreadState*)
67
68 cdef call_epoll_wait(int fd, unsigned int maxevents, int timeout_msec):
69     """
70     Wait for an I/O event, wrap epoll_wait(2).
71
72     @type fd: C{int}
73     @param fd: The epoll file descriptor number.
74
75     @type maxevents: C{int}
76     @param maxevents: Maximum number of events returned.
77
78     @type timeout_msec: C{int}
79     @param timeout_msec: Maximum time in milliseconds waiting for events. 0
80         makes it return immediately whereas -1 makes it wait indefinitely.
81
82     @raise IOError: Raised if the underlying epoll_wait() call fails.
83     """
84     cdef epoll_event *events
85     cdef int result
86     cdef int nbytes
87     cdef PyThreadState *_save
88
89     nbytes = sizeof(epoll_event) * maxevents
90     events = <epoll_event*>malloc(nbytes)
91     memset(events, 0, nbytes)
92     try:
93         _save = PyEval_SaveThread()
94         result = epoll_wait(fd, events, maxevents, timeout_msec)
95         PyEval_RestoreThread(_save)
96
97         if result == -1:
98             raise IOError(errno, strerror(errno))
99         results = []
100         for i from 0 <= i < result:
101             results.append((events[i].data.fd, <int>events[i].events))
102         return results
103     finally:
104         free(events)
105
106 cdef class epoll:
107     """
108     Represent a set of file descriptors being monitored for events.
109     """
110
111     cdef int fd
112     cdef int initialized
113
114     def __init__(self, int size=1023):
115         """
116         The constructor arguments are compatible with select.poll.__init__.
117         """
118         self.fd = epoll_create(size)
119         if self.fd == -1:
120             raise IOError(errno, strerror(errno))
121         self.initialized = 1
122
123     def __dealloc__(self):
124         if self.initialized:
125             close(self.fd)
126             self.initialized = 0
127
128     def close(self):
129         """
130         Close the epoll file descriptor.
131         """
132         if self.initialized:
133             if close(self.fd) == -1:
134                 raise IOError(errno, strerror(errno))
135             self.initialized = 0
136
137     def fileno(self):
138         """
139         Return the epoll file descriptor number.
140         """
141         return self.fd
142
143     def register(self, int fd, int events):
144         """
145         Add (register) a file descriptor to be monitored by self.
146
147         This method is compatible with select.epoll.register in Python 2.6.
148
149         Wrap epoll_ctl(2).
150
151         @type fd: C{int}
152         @param fd: File descriptor to modify
153
154         @type events: C{int}
155         @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.
156
157         @raise IOError: Raised if the underlying epoll_ctl() call fails.
158         """
159         cdef int result
160         cdef epoll_event evt
161         evt.events = events
162         evt.data.fd = fd
163         result = epoll_ctl(self.fd, CTL_ADD, fd, &evt)
164         if result == -1:
165             raise IOError(errno, strerror(errno))
166
167     def unregister(self, int fd):
168         """
169         Remove (unregister) a file descriptor monitored by self.
170
171         This method is compatible with select.epoll.unregister in Python 2.6.
172
173         Wrap epoll_ctl(2).
174
175         @type fd: C{int}
176         @param fd: File descriptor to modify
177
178         @raise IOError: Raised if the underlying epoll_ctl() call fails.
179         """
180         cdef int result
181         cdef epoll_event evt
182         # We don't have to fill evt.events for CTL_DEL.
183         evt.data.fd = fd
184         result = epoll_ctl(self.fd, CTL_DEL, fd, &evt)
185         if result == -1:
186             raise IOError(errno, strerror(errno))
187
188     def modify(self, int fd, int events):
189         """
190         Modify the modified state of a file descriptor monitored by self.
191
192         This method is compatible with select.epoll.modify in Python 2.6.
193
194         Wrap epoll_ctl(2).
195
196         @type fd: C{int}
197         @param fd: File descriptor to modify
198
199         @type events: C{int}
200         @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.
201
202         @raise IOError: Raised if the underlying epoll_ctl() call fails.
203         """
204         cdef int result
205         cdef epoll_event evt
206         evt.events = events
207         evt.data.fd = fd
208         result = epoll_ctl(self.fd, CTL_MOD, fd, &evt)
209         if result == -1:
210             raise IOError(errno, strerror(errno))
211
212     def _control(self, int op, int fd, int events):
213         """
214         Modify the monitored state of a particular file descriptor.
215
216         Wrap epoll_ctl(2).
217
218         @type op: C{int}
219         @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD
220
221         @type fd: C{int}
222         @param fd: File descriptor to modify
223
224         @type events: C{int}
225         @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.
226
227         @raise IOError: Raised if the underlying epoll_ctl() call fails.
228         """
229         cdef int result
230         cdef epoll_event evt
231         evt.events = events
232         evt.data.fd = fd
233         result = epoll_ctl(self.fd, op, fd, &evt)
234         if result == -1:
235             raise IOError(errno, strerror(errno))
236
237     def wait(self, unsigned int maxevents, int timeout):
238         """
239         Wait for an I/O event, wrap epoll_wait(2).
240
241         @type maxevents: C{int}
242         @param maxevents: Maximum number of events returned.
243
244         @type timeout: C{int}
245         @param timeout: Maximum time in milliseconds waiting for events. 0
246             makes it return immediately whereas -1 makes it wait indefinitely.
247
248         @raise IOError: Raised if the underlying epoll_wait() call fails.
249         """
250         return call_epoll_wait(self.fd, maxevents, timeout)
251
252     def poll(self, float timeout=-1, unsigned int maxevents=1024):
253         """
254         Wait for an I/O event, wrap epoll_wait(2).
255
256         This method is compatible with select.epoll.poll in Python 2.6.
257
258         @type maxevents: C{int}
259         @param maxevents: Maximum number of events returned.
260
261         @type timeout: C{int}
262         @param timeout: Maximum time waiting for events. 0 makes it return
263             immediately whereas -1 makes it wait indefinitely.
264
265         @raise IOError: Raised if the underlying epoll_wait() call fails.
266         """
267         return call_epoll_wait(self.fd, maxevents, <int>(timeout * 1000.0))
268
269
270 CTL_ADD = EPOLL_CTL_ADD
271 CTL_DEL = EPOLL_CTL_DEL
272 CTL_MOD = EPOLL_CTL_MOD
273
274 IN = EPOLLIN = c_EPOLLIN
275 OUT = EPOLLOUT = c_EPOLLOUT
276 PRI = EPOLLPRI = c_EPOLLPRI
277 ERR = EPOLLERR = c_EPOLLERR
278 HUP = EPOLLHUP = c_EPOLLHUP
279 ET = EPOLLET = c_EPOLLET
280
281 RDNORM = EPOLLRDNORM = c_EPOLLRDNORM
282 RDBAND = EPOLLRDBAND = c_EPOLLRDBAND
283 WRNORM = EPOLLWRNORM = c_EPOLLWRNORM
284 WRBAND = EPOLLWRBAND = c_EPOLLWRBAND
285 MSG = EPOLLMSG = c_EPOLLMSG