aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/python/_epoll.pyx
blob: b8d6aa7f585bcd38f56168f77c507a4d81f44509 (plain)
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

"""
Interface to epoll I/O event notification facility.
"""

# NOTE: The version of Pyrex you are using probably _does not work_ with
# Python 2.5.  If you need to recompile this file, _make sure you are using
# a version of Pyrex which works with Python 2.5_.  I am using 0.9.4.1 from
# <http://codespeak.net/svn/lxml/pyrex/>. -exarkun

cdef extern from "stdio.h":
    cdef extern void *malloc(int)
    cdef extern void free(void *)
    cdef extern int close(int)

cdef extern from "errno.h":
    cdef extern int errno
    cdef extern char *strerror(int)

cdef extern from "string.h":
    cdef extern void *memset(void* s, int c, int n)

cdef extern from "stdint.h":
    ctypedef unsigned long uint32_t
    ctypedef unsigned long long uint64_t

cdef extern from "sys/epoll.h":

    cdef enum:
        EPOLL_CTL_ADD = 1
        EPOLL_CTL_DEL = 2
        EPOLL_CTL_MOD = 3

    cdef enum EPOLL_EVENTS:
        c_EPOLLIN "EPOLLIN" = 0x001
        c_EPOLLPRI "EPOLLPRI" = 0x002
        c_EPOLLOUT "EPOLLOUT" = 0x004
        c_EPOLLRDNORM "EPOLLRDNORM" = 0x040
        c_EPOLLRDBAND "EPOLLRDBAND" = 0x080
        c_EPOLLWRNORM "EPOLLWRNORM" = 0x100
        c_EPOLLWRBAND "EPOLLWRBAND" = 0x200
        c_EPOLLMSG "EPOLLMSG" = 0x400
        c_EPOLLERR "EPOLLERR" = 0x008
        c_EPOLLHUP "EPOLLHUP" = 0x010
        c_EPOLLET "EPOLLET" = (1 << 31)

    ctypedef union epoll_data_t:
        void *ptr
        int fd
        uint32_t u32
        uint64_t u64

    cdef struct epoll_event:
        uint32_t events
        epoll_data_t data

    int epoll_create(int size)
    int epoll_ctl(int epfd, int op, int fd, epoll_event *event)
    int epoll_wait(int epfd, epoll_event *events, int maxevents, int timeout)

cdef extern from "Python.h":
    ctypedef struct PyThreadState
    cdef extern PyThreadState *PyEval_SaveThread()
    cdef extern void PyEval_RestoreThread(PyThreadState*)

cdef call_epoll_wait(int fd, unsigned int maxevents, int timeout_msec):
    """
    Wait for an I/O event, wrap epoll_wait(2).

    @type fd: C{int}
    @param fd: The epoll file descriptor number.

    @type maxevents: C{int}
    @param maxevents: Maximum number of events returned.

    @type timeout_msec: C{int}
    @param timeout_msec: Maximum time in milliseconds waiting for events. 0
        makes it return immediately whereas -1 makes it wait indefinitely.

    @raise IOError: Raised if the underlying epoll_wait() call fails.
    """
    cdef epoll_event *events
    cdef int result
    cdef int nbytes
    cdef PyThreadState *_save

    nbytes = sizeof(epoll_event) * maxevents
    events = <epoll_event*>malloc(nbytes)
    memset(events, 0, nbytes)
    try:
        _save = PyEval_SaveThread()
        result = epoll_wait(fd, events, maxevents, timeout_msec)
        PyEval_RestoreThread(_save)

        if result == -1:
            raise IOError(errno, strerror(errno))
        results = []
        for i from 0 <= i < result:
            results.append((events[i].data.fd, <int>events[i].events))
        return results
    finally:
        free(events)

cdef class epoll:
    """
    Represent a set of file descriptors being monitored for events.
    """

    cdef int fd
    cdef int initialized

    def __init__(self, int size=1023):
        """
        The constructor arguments are compatible with select.poll.__init__.
        """
        self.fd = epoll_create(size)
        if self.fd == -1:
            raise IOError(errno, strerror(errno))
        self.initialized = 1

    def __dealloc__(self):
        if self.initialized:
            close(self.fd)
            self.initialized = 0

    def close(self):
        """
        Close the epoll file descriptor.
        """
        if self.initialized:
            if close(self.fd) == -1:
                raise IOError(errno, strerror(errno))
            self.initialized = 0

    def fileno(self):
        """
        Return the epoll file descriptor number.
        """
        return self.fd

    def register(self, int fd, int events):
        """
        Add (register) a file descriptor to be monitored by self.

        This method is compatible with select.epoll.register in Python 2.6.

        Wrap epoll_ctl(2).

        @type fd: C{int}
        @param fd: File descriptor to modify

        @type events: C{int}
        @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.

        @raise IOError: Raised if the underlying epoll_ctl() call fails.
        """
        cdef int result
        cdef epoll_event evt
        evt.events = events
        evt.data.fd = fd
        result = epoll_ctl(self.fd, CTL_ADD, fd, &evt)
        if result == -1:
            raise IOError(errno, strerror(errno))

    def unregister(self, int fd):
        """
        Remove (unregister) a file descriptor monitored by self.

        This method is compatible with select.epoll.unregister in Python 2.6.

        Wrap epoll_ctl(2).

        @type fd: C{int}
        @param fd: File descriptor to modify

        @raise IOError: Raised if the underlying epoll_ctl() call fails.
        """
        cdef int result
        cdef epoll_event evt
        # We don't have to fill evt.events for CTL_DEL.
        evt.data.fd = fd
        result = epoll_ctl(self.fd, CTL_DEL, fd, &evt)
        if result == -1:
            raise IOError(errno, strerror(errno))

    def modify(self, int fd, int events):
        """
        Modify the modified state of a file descriptor monitored by self.

        This method is compatible with select.epoll.modify in Python 2.6.

        Wrap epoll_ctl(2).

        @type fd: C{int}
        @param fd: File descriptor to modify

        @type events: C{int}
        @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.

        @raise IOError: Raised if the underlying epoll_ctl() call fails.
        """
        cdef int result
        cdef epoll_event evt
        evt.events = events
        evt.data.fd = fd
        result = epoll_ctl(self.fd, CTL_MOD, fd, &evt)
        if result == -1:
            raise IOError(errno, strerror(errno))

    def _control(self, int op, int fd, int events):
        """
        Modify the monitored state of a particular file descriptor.

        Wrap epoll_ctl(2).

        @type op: C{int}
        @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD

        @type fd: C{int}
        @param fd: File descriptor to modify

        @type events: C{int}
        @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.

        @raise IOError: Raised if the underlying epoll_ctl() call fails.
        """
        cdef int result
        cdef epoll_event evt
        evt.events = events
        evt.data.fd = fd
        result = epoll_ctl(self.fd, op, fd, &evt)
        if result == -1:
            raise IOError(errno, strerror(errno))

    def wait(self, unsigned int maxevents, int timeout):
        """
        Wait for an I/O event, wrap epoll_wait(2).

        @type maxevents: C{int}
        @param maxevents: Maximum number of events returned.

        @type timeout: C{int}
        @param timeout: Maximum time in milliseconds waiting for events. 0
            makes it return immediately whereas -1 makes it wait indefinitely.

        @raise IOError: Raised if the underlying epoll_wait() call fails.
        """
        return call_epoll_wait(self.fd, maxevents, timeout)

    def poll(self, float timeout=-1, unsigned int maxevents=1024):
        """
        Wait for an I/O event, wrap epoll_wait(2).

        This method is compatible with select.epoll.poll in Python 2.6.

        @type maxevents: C{int}
        @param maxevents: Maximum number of events returned.

        @type timeout: C{int}
        @param timeout: Maximum time waiting for events. 0 makes it return
            immediately whereas -1 makes it wait indefinitely.

        @raise IOError: Raised if the underlying epoll_wait() call fails.
        """
        return call_epoll_wait(self.fd, maxevents, <int>(timeout * 1000.0))


CTL_ADD = EPOLL_CTL_ADD
CTL_DEL = EPOLL_CTL_DEL
CTL_MOD = EPOLL_CTL_MOD

IN = EPOLLIN = c_EPOLLIN
OUT = EPOLLOUT = c_EPOLLOUT
PRI = EPOLLPRI = c_EPOLLPRI
ERR = EPOLLERR = c_EPOLLERR
HUP = EPOLLHUP = c_EPOLLHUP
ET = EPOLLET = c_EPOLLET

RDNORM = EPOLLRDNORM = c_EPOLLRDNORM
RDBAND = EPOLLRDBAND = c_EPOLLRDBAND
WRNORM = EPOLLWRNORM = c_EPOLLWRNORM
WRBAND = EPOLLWRBAND = c_EPOLLWRBAND
MSG = EPOLLMSG = c_EPOLLMSG