Index: configure =================================================================== --- configure (Revision 59566) +++ configure (Arbeitskopie) @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 59533 . +# From configure.in Revision: 59558 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61 for python 2.6. # @@ -5416,13 +5416,14 @@ + for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \ fcntl.h grp.h \ io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \ shadow.h signal.h stdint.h stropts.h termios.h thread.h \ unistd.h utime.h \ -sys/audioio.h sys/bsdtty.h sys/file.h sys/loadavg.h sys/lock.h sys/mkdev.h \ -sys/modem.h \ +sys/audioio.h sys/bsdtty.h sys/epoll.h sys/file.h sys/loadavg.h sys/lock.h \ +sys/mkdev.h sys/modem.h \ sys/param.h sys/poll.h sys/select.h sys/socket.h sys/statvfs.h sys/stat.h \ sys/time.h \ sys/times.h sys/types.h sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \ @@ -15644,7 +15645,57 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: checking for epoll" >&5 +echo $ECHO_N "checking for epoll... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +void *x=epoll_create + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then +cat >>confdefs.h <<\_ACEOF +#define HAVE_EPOLL 1 +_ACEOF + + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # On some systems (eg. FreeBSD 5), we would find a definition of the # functions ctermid_r, setgroups in the library, but no prototype # (e.g. because we use _XOPEN_SOURCE). See whether we can take their Index: configure.in =================================================================== --- configure.in (Revision 59566) +++ configure.in (Arbeitskopie) @@ -1100,8 +1100,8 @@ io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \ shadow.h signal.h stdint.h stropts.h termios.h thread.h \ unistd.h utime.h \ -sys/audioio.h sys/bsdtty.h sys/file.h sys/loadavg.h sys/lock.h sys/mkdev.h \ -sys/modem.h \ +sys/audioio.h sys/bsdtty.h sys/epoll.h sys/file.h sys/loadavg.h sys/lock.h \ +sys/mkdev.h sys/modem.h \ sys/param.h sys/poll.h sys/select.h sys/socket.h sys/statvfs.h sys/stat.h \ sys/time.h \ sys/times.h sys/types.h sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \ @@ -2358,7 +2358,12 @@ AC_MSG_RESULT(yes), AC_MSG_RESULT(no) ) - +AC_MSG_CHECKING(for epoll) +AC_TRY_COMPILE([#include ], void *x=epoll_create, + AC_DEFINE(HAVE_EPOLL, 1, Define if you have the 'epoll' functions.) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) +) # On some systems (eg. FreeBSD 5), we would find a definition of the # functions ctermid_r, setgroups in the library, but no prototype # (e.g. because we use _XOPEN_SOURCE). See whether we can take their Index: Doc/library/select.rst =================================================================== --- Doc/library/select.rst (Revision 59566) +++ Doc/library/select.rst (Arbeitskopie) @@ -7,10 +7,11 @@ This module provides access to the :cfunc:`select` and :cfunc:`poll` functions -available in most operating systems. Note that on Windows, it only works for -sockets; on other operating systems, it also works for other file types (in -particular, on Unix, it works on pipes). It cannot be used on regular files to -determine whether a file has grown since it was last read. +available in most operating systems and :cfunc:`epoll` available on Linux 2.5+. +Note that on Windows, it only works for sockets; on other operating systems, +it also works for other file types (in particular, on Unix, it works on pipes). +It cannot be used on regular files to determine whether a file has grown since +it was last read. The module defines the following: @@ -22,6 +23,16 @@ string, as would be printed by the C function :cfunc:`perror`. +.. function:: epoll(sizehint) + + (Only supported on Linux 2.5.44 and newer.) Returns an edge polling + object, which can be used as Edge or Level Triggered interface for I/O + events; see section :ref:`epoll-objects` below for the methods supported + by epolling objects. + + .. versionadded:: 2.6 + + .. function:: poll() (Not supported by all operating systems.) Returns a polling object, which @@ -69,6 +80,74 @@ not handle file descriptors that don't originate from WinSock. +.. _epoll-objects: + +Edge and Level Trigger Polling (epoll) Objects +---------------------------------------------- + + *eventmask* + + +------------------------+-----------------------------------------------+ + | Constant | Meaning | + +========================+===============================================+ + | :const:`EPOLL_IN` | Available for read | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_OUT` | Available for write | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_PRI` | Urgent data for read | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_ERR` | Error condition happend on the assoc. fd | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_HUP` | Hang up happend on the assoc. fd | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_ET` | Set Edge Trigger behavior, the default is | + | | Level Trigger behavior + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_ONESHOT` | Set one-shot behavior. After one event is | + | | pulled out, the fd is internally disabled | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_RDNORM` | ??? | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_RDBAND` | ??? | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_WRNORM` | ??? | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_WRBAND` | ??? | + +------------------------+-----------------------------------------------+ + | :const:`EPOLL_MSG` | ??? | + +------------------------+-----------------------------------------------+ + + +.. method:: epoll.close() + + Close the control file descriptor of the epoll object. + + +.. method:: epoll.fileno() + + Return the file descriptor number of the control fd. + + +.. method:: epoll.register(fd[, eventmask]) + + Register a fd descriptor with the epoll object. + + +.. method:: epoll.modify(fd, eventmask) + + Modify a register file descriptor. + + +.. method:: epoll.unregister(fd) + + Remove a registered file descriptor from the epoll object. + + +.. method:: epoll.wait(maxevents, timeout) + + Wait for events. + + .. _poll-objects: Polling Objects Index: Lib/test/test_epoll.py =================================================================== --- Lib/test/test_epoll.py (Revision 0) +++ Lib/test/test_epoll.py (Revision 0) @@ -0,0 +1,191 @@ +# Copyright (c) 2001-2006 Twisted Matrix Laboratories. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" +Tests for epoll wrapper. +""" +import socket, errno, time, select +import unittest + +class EPoll(unittest.TestCase): + """ + Tests for the low-level epoll bindings. + """ + def setUp(self): + """ + Create a listening server port and a list with which to keep track + of created sockets. + """ + self.serverSocket = socket.socket() + self.serverSocket.bind(('127.0.0.1', 0)) + self.serverSocket.listen(1) + self.connections = [self.serverSocket] + + + def tearDown(self): + """ + Close any sockets which were opened by the test. + """ + for skt in self.connections: + skt.close() + + + def _connected_pair(self): + """ + Return the two sockets which make up a new TCP connection. + """ + client = socket.socket() + client.setblocking(False) + try: + client.connect(('127.0.0.1', self.serverSocket.getsockname()[1])) + except socket.error, e: + self.assertEquals(e.args[0], errno.EINPROGRESS) + else: + raise AssertionError("Connect should have raised EINPROGRESS") + server, addr = self.serverSocket.accept() + + self.connections.extend((client, server)) + return client, server + + + def test_create(self): + """ + Test the creation of an epoll object. + """ + try: + ep = select.epoll(16) + except OSError, e: + raise AssertionError(str(e)) + self.assert_(ep.fileno() > 0, ep.fileno()) + self.assert_(not ep.closed) + ep.close() + self.assert_(ep.closed) + self.assertRaises(ValueError, ep.fileno) + + def test_badcreate(self): + """ + Test that attempting to create an epoll object with some random + objects raises a TypeError. + """ + self.assertRaises(TypeError, select.epoll, 1, 2, 3) + self.assertRaises(TypeError, select.epoll, 'foo') + self.assertRaises(TypeError, select.epoll, None) + self.assertRaises(TypeError, select.epoll, ()) + self.assertRaises(TypeError, select.epoll, ['foo']) + self.assertRaises(TypeError, select.epoll, {}) + self.assertRaises(TypeError, select.epoll) + + + def test_add(self): + """ + Test adding a socket to an epoll object. + """ + server, client = self._connected_pair() + + ep = select.epoll(2) + try: + ep.register(server.fileno(), select.EPOLL_IN | select.EPOLL_OUT) + ep.register(client.fileno(), select.EPOLL_IN | select.EPOLL_OUT) + finally: + ep.close() + + + def test_control_and_wait(self): + """ + Test waiting on an epoll object which has had some sockets added to + it. + """ + client, server = self._connected_pair() + + ep = select.epoll(16) + ep.register(server.fileno(), + select.EPOLL_IN | select.EPOLL_OUT | select.EPOLL_ET) + ep.register(client.fileno(), + select.EPOLL_IN | select.EPOLL_OUT | select.EPOLL_ET) + + now = time.time() + events = ep.wait(4, 1000) + then = time.time() + self.failIf(then - now > 0.1, then - now) + + events.sort() + expected = [(client.fileno(), select.EPOLL_OUT), + (server.fileno(), select.EPOLL_OUT)] + expected.sort() + + self.assertEquals(events, expected) + self.failIf(then - now > 0.01, then - now) + + now = time.time() + events = ep.wait(4, 200) + then = time.time() + self.failIf(events) + + client.send("Hello!") + server.send("world!!!") + + now = time.time() + events = ep.wait(4, 1000) + then = time.time() + self.failIf(then - now > 0.01) + + events.sort() + expected = [(client.fileno(), select.EPOLL_IN | select.EPOLL_OUT), + (server.fileno(), select.EPOLL_IN | select.EPOLL_OUT)] + expected.sort() + + self.assertEquals(events, expected) + + ep.unregister(client.fileno()) + ep.modify(server.fileno(), select.EPOLL_OUT) + now = time.time() + events = ep.wait(4, 1000) + then = time.time() + self.failIf(then - now > 0.01) + + expected = [(server.fileno(), select.EPOLL_OUT)] + self.assertEquals(events, expected) + + + def test_errors(self): + """ + Test some error conditions of epoll methods. + """ + self.assertRaises(IOError, select.epoll, -1) + self.assertRaises(IOError, select.epoll(1).register, -1, + select.EPOLL_IN) + +if not hasattr(select, "epoll") is None: + EPoll.skip = "select.epoll unavailable" +else: + try: + e = select.epoll(16) + except IOError, exc: + if exc.errno == errno.ENOSYS: + del exc + EPoll.skip = "epoll support missing from platform" + else: + raise + else: + e.close() + del e + +if __name__ == '__main__': + unittest.main() Eigenschaftsänderungen: Lib/test/test_epoll.py ___________________________________________________________________ Name: svn:keywords + 'Id Revision' Name: svn:eol-style + native Index: Modules/selectmodule.c =================================================================== --- Modules/selectmodule.c (Revision 59566) +++ Modules/selectmodule.c (Arbeitskopie) @@ -31,6 +31,10 @@ #include #endif +#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL) +#include +#endif + #ifdef __sgi /* This is missing from unistd.h */ extern void bzero(void *, int); @@ -483,9 +487,9 @@ return NULL; /* call poll() */ - Py_BEGIN_ALLOW_THREADS; + Py_BEGIN_ALLOW_THREADS poll_result = poll(self->ufds, self->ufd_len, timeout); - Py_END_ALLOW_THREADS; + Py_END_ALLOW_THREADS if (poll_result < 0) { PyErr_SetFromErrno(SelectError); @@ -646,6 +650,339 @@ #endif /* HAVE_POLL */ +#ifdef HAVE_EPOLL +/* epoll support + */ + +typedef struct { + PyObject_HEAD + int epfd; +} PyEpoll_Object; + +static PyTypeObject PyEpoll_Type; +#define PyEpoll_CHECK(op) (PyObject_TypeCheck((op), &PyEpoll_Type)) + +static PyObject * +pyepoll_err_closed(void) +{ + PyErr_SetString(PyExc_ValueError, "I/O operation on closed epoll fd"); + return NULL; +} + +static int +pyepoll_internal_close(PyEpoll_Object *self) +{ + int save_errno = 0; + if (self->epfd >= 0) { + int epfd = self->epfd; + self->epfd = -1; + Py_BEGIN_ALLOW_THREADS + if (close(epfd) < 0) + save_errno = errno; + Py_END_ALLOW_THREADS + } + return save_errno; +} + +static PyObject * +pyepoll_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyEpoll_Object *self; + int size; + static char *kwlist[] = {"size", NULL}; + + assert(type != NULL && type->tp_alloc != NULL); + + self = (PyEpoll_Object *) type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:epoll", kwlist, &size)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + self->epfd = epoll_create(size); + Py_END_ALLOW_THREADS + if (self->epfd < 0) { + Py_DECREF(self); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return (PyObject *)self; +} + +static void +pyepoll_dealloc(PyEpoll_Object *self) +{ + (void)pyepoll_internal_close(self); +} + +static PyObject* +pyepoll_close(PyEpoll_Object *self) +{ + errno = pyepoll_internal_close(self); + if (errno < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pyepoll_close_doc, +"close() -> None\n\ +\n\ +Close the epoll control file descriptor. Further operations on the epoll\n\ +object will raise an exception."); + +static PyObject* +pyepoll_get_closed(PyEpoll_Object *self) +{ + if (self->epfd < 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject* +pyepoll_fileno(PyEpoll_Object *self) +{ + if (self->epfd < 0) + return pyepoll_err_closed(); + return PyLong_FromLong((long)self->epfd); +} + +PyDoc_STRVAR(pyepoll_fileno_doc, +"fileno() -> int\n\ +\n\ +Return the epoll control file descriptor."); + +static PyObject * +pyepoll_internal_ctl(int epfd, int op, int fd, unsigned int events) +{ + struct epoll_event ev; + int result; + + if (epfd < 0) + return pyepoll_err_closed(); + + switch(op) { + case EPOLL_CTL_ADD: + case EPOLL_CTL_MOD: + ev.events = events; + ev.data.fd = fd; + Py_BEGIN_ALLOW_THREADS + result = epoll_ctl(epfd, op, fd, &ev); + Py_END_ALLOW_THREADS + break; + case EPOLL_CTL_DEL: + /* In kernel versions before 2.6.9, the EPOLL_CTL_DEL + * operation required a non-NULL pointer in event, even + * though this argument is ignored. */ + Py_BEGIN_ALLOW_THREADS + result = epoll_ctl(epfd, op, fd, &ev); + Py_END_ALLOW_THREADS + break; + default: + result = -1; + errno = EINVAL; + } + + if (result < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +pyepoll_register(PyEpoll_Object *self, PyObject *args, PyObject *kwds) +{ + int fd; + unsigned int events = EPOLLIN | EPOLLOUT | EPOLLPRI; + static char *kwlist[] = {"fd", "eventmask", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|I:control", kwlist, + &fd, &events)) + return NULL; + return pyepoll_internal_ctl(self->epfd, EPOLL_CTL_ADD, fd, events); +} + +PyDoc_STRVAR(pyepoll_register_doc, +"register(fd[, eventmask]) -> None\n\ +\n\ +fd is the target file descriptor of the operation\n\ +events is a bit set composed of the various EPOLL constants, the default\n\ +is EPOLL_IN | EPOLL_OUT | EPOLL_PRI.\n\ +\n\ +The epoll interface supports all file descriptors that support poll."); + +static PyObject * +pyepoll_modify(PyEpoll_Object *self, PyObject *args, PyObject *kwds) +{ + int fd; + unsigned int events; + static char *kwlist[] = {"fd", "eventmask", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "iI:control", kwlist, + &fd, &events)) + return NULL; + return pyepoll_internal_ctl(self->epfd, EPOLL_CTL_MOD, fd, events); +} + +PyDoc_STRVAR(pyepoll_modify_doc, +"modify(fd, eventmask) -> None\n\ +\n\ +fd is the target file descriptor of the operation\n\ +events is a bit set composed of the various EPOLL constants"); + +static PyObject * +pyepoll_unregister(PyEpoll_Object *self, PyObject *args, PyObject *kwds) +{ + int fd; + static char *kwlist[] = {"fd", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:control", kwlist, + &fd)) + return NULL; + return pyepoll_internal_ctl(self->epfd, EPOLL_CTL_DEL, fd, 0); +} + +PyDoc_STRVAR(pyepoll_unregister_doc, +"unregister(fd) -> None\n\ +\n\ +fd is the target file descriptor of the operation."); + +static PyObject * +pyepoll_wait(PyEpoll_Object *self, PyObject *args, PyObject *kwds) +{ + int timeout, nfds, maxevents, size, i; + struct epoll_event *evs; + PyObject *elist = NULL, *etuple = NULL; + static char *kwlist[] = {"maxevents", "timeout", NULL}; + + if (self->epfd < 0) + return pyepoll_err_closed(); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii:wait", kwlist, + &maxevents, &timeout)) + return NULL; + + size = maxevents * sizeof(struct epoll_event); + evs = (struct epoll_event*) PyMem_Malloc(size); + if (evs == NULL) { + PyErr_SetString(PyExc_MemoryError, + "failed to allocate memory for events"); + return NULL; + } + memset(evs, 0, size); + + Py_BEGIN_ALLOW_THREADS + nfds = epoll_wait(self->epfd, evs, maxevents, timeout); + Py_END_ALLOW_THREADS + if (nfds < 0) { + PyErr_SetFromErrno(PyExc_IOError); + goto error; + } + + elist = PyList_New(nfds); + if (elist == NULL) { + goto error; + } + + for (i = 0; i < nfds; i++) { + etuple = Py_BuildValue("iI", evs[i].data.fd, evs[i].events); + if (etuple == NULL) { + goto error; + } + PyList_SET_ITEM(elist, i, etuple); + } + + if (0) { + error: + Py_CLEAR(elist); + Py_XDECREF(etuple); + } + PyMem_Free(evs); + return elist; +} + +PyDoc_STRVAR(pyepoll_wait_doc, +"wait(maxevents, timeout) -> [(fd, events), (...)]\n\ +\n\ +Wait for events on the epoll file descriptor for a maximum time of timeout\n\ +milliseconds. Up to maxevents are returned to the caller."); + +static PyMethodDef pyepoll_methods[] = { + {"close", (PyCFunction)pyepoll_close, METH_NOARGS, + pyepoll_close_doc}, + {"fileno", (PyCFunction)pyepoll_fileno, METH_NOARGS, + pyepoll_fileno_doc}, + {"modify", (PyCFunction)pyepoll_modify, + METH_VARARGS | METH_KEYWORDS, pyepoll_modify_doc}, + {"register", (PyCFunction)pyepoll_register, + METH_VARARGS | METH_KEYWORDS, pyepoll_register_doc}, + {"unregister", (PyCFunction)pyepoll_unregister, + METH_VARARGS | METH_KEYWORDS, pyepoll_unregister_doc}, + {"wait", (PyCFunction)pyepoll_wait, + METH_VARARGS | METH_KEYWORDS, pyepoll_wait_doc}, + {NULL, NULL}, +}; + +static PyGetSetDef pyepoll_getsetlist[] = { + {"closed", (getter)pyepoll_get_closed, NULL, + "True if the epoll handler is closed"}, + {0}, +}; + +PyDoc_STRVAR(pyepoll_doc, +"select.epoll(sizehint)\n\ +\n\ +Returns an epolling object"); + +static PyTypeObject PyEpoll_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "select.epoll", /* tp_name */ + sizeof(PyEpoll_Object), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)pyepoll_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + pyepoll_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pyepoll_methods, /* tp_methods */ + 0, /* tp_members */ + pyepoll_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + pyepoll_new, /* tp_new */ + 0, /* tp_free */ +}; + +#endif /* HAVE_EPOLL */ + PyDoc_STRVAR(select_doc, "select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)\n\ \n\ @@ -730,4 +1067,32 @@ #endif } #endif /* HAVE_POLL */ +#ifdef HAVE_EPOLL + Py_TYPE(&PyEpoll_Type) = &PyType_Type; + if (PyType_Ready(&PyEpoll_Type) < 0) + return; + PyModule_AddObject(m, "epoll", (PyObject *) &PyEpoll_Type); + + PyModule_AddIntConstant(m, "EPOLL_IN", EPOLLIN); + PyModule_AddIntConstant(m, "EPOLL_OUT", EPOLLOUT); + PyModule_AddIntConstant(m, "EPOLL_PRI", EPOLLPRI); + PyModule_AddIntConstant(m, "EPOLL_ERR", EPOLLERR); + PyModule_AddIntConstant(m, "EPOLL_HUP", EPOLLHUP); + PyModule_AddIntConstant(m, "EPOLL_ET", EPOLLET); +#ifdef EPOLLONESHOT + /* Kernel 2.6.2+ */ + PyModule_AddIntConstant(m, "EPOLL_ONESHOT", EPOLLONESHOT); +#endif + /* PyModule_AddIntConstant(m, "EPOLL_RDHUP", EPOLLRDHUP); */ + PyModule_AddIntConstant(m, "EPOLL_RDNORM", EPOLLRDNORM); + PyModule_AddIntConstant(m, "EPOLL_RDBAND", EPOLLRDBAND); + PyModule_AddIntConstant(m, "EPOLL_WRNORM", EPOLLWRNORM); + PyModule_AddIntConstant(m, "EPOLL_WRBAND", EPOLLWRBAND); + PyModule_AddIntConstant(m, "EPOLL_MSG", EPOLLMSG); + + PyModule_AddIntConstant(m, "EPOLL_CTL_ADD", EPOLL_CTL_ADD); + PyModule_AddIntConstant(m, "EPOLL_CTL_MOD", EPOLL_CTL_MOD); + PyModule_AddIntConstant(m, "EPOLL_CTL_DEL", EPOLL_CTL_DEL); + +#endif /* HAVE_EPOLL */ } Index: pyconfig.h.in =================================================================== --- pyconfig.h.in (Revision 59566) +++ pyconfig.h.in (Arbeitskopie) @@ -138,6 +138,9 @@ /* Defined when any dynamic module loading is enabled. */ #undef HAVE_DYNAMIC_LOADING +/* Define if you have the 'epoll' functions. */ +#undef HAVE_EPOLL + /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H @@ -612,6 +615,9 @@ */ #undef HAVE_SYS_DIR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_EPOLL_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H @@ -1040,4 +1046,3 @@ #endif /*Py_PYCONFIG_H*/ -