OLD | NEW |
| (Empty) |
1 # Copyright (c) 2001-2006 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 EPOLLIN = 0x001 | |
38 EPOLLPRI = 0x002 | |
39 EPOLLOUT = 0x004 | |
40 EPOLLRDNORM = 0x040 | |
41 EPOLLRDBAND = 0x080 | |
42 EPOLLWRNORM = 0x100 | |
43 EPOLLWRBAND = 0x200 | |
44 EPOLLMSG = 0x400 | |
45 EPOLLERR = 0x008 | |
46 EPOLLHUP = 0x010 | |
47 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 class epoll: | |
69 """ | |
70 Represent a set of file descriptors being monitored for events. | |
71 """ | |
72 | |
73 cdef int fd | |
74 cdef int initialized | |
75 | |
76 def __init__(self, int size): | |
77 self.fd = epoll_create(size) | |
78 if self.fd == -1: | |
79 raise IOError(errno, strerror(errno)) | |
80 self.initialized = 1 | |
81 | |
82 def __dealloc__(self): | |
83 if self.initialized: | |
84 close(self.fd) | |
85 self.initialized = 0 | |
86 | |
87 def close(self): | |
88 """ | |
89 Close the epoll file descriptor. | |
90 """ | |
91 if self.initialized: | |
92 if close(self.fd) == -1: | |
93 raise IOError(errno, strerror(errno)) | |
94 self.initialized = 0 | |
95 | |
96 def fileno(self): | |
97 """ | |
98 Return the epoll file descriptor number. | |
99 """ | |
100 return self.fd | |
101 | |
102 def _control(self, int op, int fd, int events): | |
103 """ | |
104 Modify the monitored state of a particular file descriptor. | |
105 | |
106 Wrap epoll_ctl(2). | |
107 | |
108 @type op: C{int} | |
109 @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD | |
110 | |
111 @type fd: C{int} | |
112 @param fd: File descriptor to modify | |
113 | |
114 @type events: C{int} | |
115 @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET. | |
116 | |
117 @raise IOError: Raised if the underlying epoll_ctl() call fails. | |
118 """ | |
119 cdef int result | |
120 cdef epoll_event evt | |
121 evt.events = events | |
122 evt.data.fd = fd | |
123 result = epoll_ctl(self.fd, op, fd, &evt) | |
124 if result == -1: | |
125 raise IOError(errno, strerror(errno)) | |
126 | |
127 def wait(self, unsigned int maxevents, int timeout): | |
128 """ | |
129 Wait for an I/O event, wrap epoll_wait(2). | |
130 | |
131 @type maxevents: C{int} | |
132 @param maxevents: Maximum number of events returned. | |
133 | |
134 @type timeout: C{int} | |
135 @param timeout: Maximum time waiting for events. 0 makes it return | |
136 immediately whereas -1 makes it wait indefinitely. | |
137 | |
138 @raise IOError: Raised if the underlying epoll_wait() call fails. | |
139 """ | |
140 cdef epoll_event *events | |
141 cdef int result | |
142 cdef int nbytes | |
143 cdef int fd | |
144 cdef PyThreadState *_save | |
145 | |
146 nbytes = sizeof(epoll_event) * maxevents | |
147 events = <epoll_event*>malloc(nbytes) | |
148 memset(events, 0, nbytes) | |
149 try: | |
150 fd = self.fd | |
151 | |
152 _save = PyEval_SaveThread() | |
153 result = epoll_wait(fd, events, maxevents, timeout) | |
154 PyEval_RestoreThread(_save) | |
155 | |
156 if result == -1: | |
157 raise IOError(errno, strerror(errno)) | |
158 results = [] | |
159 for i from 0 <= i < result: | |
160 results.append((events[i].data.fd, <int>events[i].events)) | |
161 return results | |
162 finally: | |
163 free(events) | |
164 | |
165 CTL_ADD = EPOLL_CTL_ADD | |
166 CTL_DEL = EPOLL_CTL_DEL | |
167 CTL_MOD = EPOLL_CTL_MOD | |
168 | |
169 IN = EPOLLIN | |
170 OUT = EPOLLOUT | |
171 PRI = EPOLLPRI | |
172 ERR = EPOLLERR | |
173 HUP = EPOLLHUP | |
174 ET = EPOLLET | |
175 | |
176 RDNORM = EPOLLRDNORM | |
177 RDBAND = EPOLLRDBAND | |
178 WRNORM = EPOLLWRNORM | |
179 WRBAND = EPOLLWRBAND | |
180 MSG = EPOLLMSG | |
181 | |
OLD | NEW |