# Copyright (c) 2001-2006 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 # . -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: EPOLLIN = 0x001 EPOLLPRI = 0x002 EPOLLOUT = 0x004 EPOLLRDNORM = 0x040 EPOLLRDBAND = 0x080 EPOLLWRNORM = 0x100 EPOLLWRBAND = 0x200 EPOLLMSG = 0x400 EPOLLERR = 0x008 EPOLLHUP = 0x010 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 class epoll: """ Represent a set of file descriptors being monitored for events. """ cdef int fd cdef int initialized def __init__(self, int size): 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 _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 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 int fd cdef PyThreadState *_save nbytes = sizeof(epoll_event) * maxevents events = malloc(nbytes) memset(events, 0, nbytes) try: fd = self.fd _save = PyEval_SaveThread() result = epoll_wait(fd, events, maxevents, timeout) PyEval_RestoreThread(_save) if result == -1: raise IOError(errno, strerror(errno)) results = [] for i from 0 <= i < result: results.append((events[i].data.fd, events[i].events)) return results finally: free(events) CTL_ADD = EPOLL_CTL_ADD CTL_DEL = EPOLL_CTL_DEL CTL_MOD = EPOLL_CTL_MOD IN = EPOLLIN OUT = EPOLLOUT PRI = EPOLLPRI ERR = EPOLLERR HUP = EPOLLHUP ET = EPOLLET RDNORM = EPOLLRDNORM RDBAND = EPOLLRDBAND WRNORM = EPOLLWRNORM WRBAND = EPOLLWRBAND MSG = EPOLLMSG