Index: twisted/internet/kqreactor.py =================================================================== --- twisted/internet/kqreactor.py (revision 28812) +++ twisted/internet/kqreactor.py (working copy) @@ -10,51 +10,43 @@ | from twisted.internet import kqreactor | kqreactor.install() -This reactor only works on FreeBSD and requires PyKQueue 1.3, which is -available at: U{http://people.freebsd.org/~dwhite/PyKQueue/} +This reactor only works on FreeBSD and requires Python 2.6 and above select.kqueue +module or the backport of it for Python 2.5 U{http://pypi.python.org/pypi/select26/0.1a3} +You're going to need to patch select26:: +# HG changeset patch -- Bitbucket.org +# Project select26 +# URL http://bitbucket.org/psykidellic/select26/overview/ +# User psykidellic +# Date 1268883306 25200 +# Node ID aefd0e6a228b32cb4673e32806fcb415ff79152f +# Parent d79af7cb2ea63803bcd621a11aaa3739f882d135 +Apply the patch -You're going to need to patch PyKqueue:: +--- a/select26module.c ++++ b/select26module.c +@@ -861,7 +861,7 @@ kqueue_queue_control(kqueue_queue_Object + if (nevents < 0) { + PyErr_Format(PyExc_ValueError, + "Length of eventlist must be 0 or positive, got %d", +- nchanges); ++ nevents); + return NULL; + } + +@@ -927,7 +927,7 @@ kqueue_queue_control(kqueue_queue_Object + "select26.kevent objects"); + goto error; + } else { +- chl[i] = ((kqueue_event_Object *)ei)->e; ++ chl[i++] = ((kqueue_event_Object *)ei)->e; + } + Py_DECREF(ei); + } - ===================================================== - --- PyKQueue-1.3/kqsyscallmodule.c Sun Jan 28 21:59:50 2001 - +++ PyKQueue-1.3/kqsyscallmodule.c.new Tue Jul 30 18:06:08 2002 - @@ -137,7 +137,7 @@ - } - - statichere PyTypeObject KQEvent_Type = { - - PyObject_HEAD_INIT(NULL) - + PyObject_HEAD_INIT(&PyType_Type) - 0, // ob_size - "KQEvent", // tp_name - sizeof(KQEventObject), // tp_basicsize - @@ -291,13 +291,14 @@ - - /* Build timespec for timeout */ - totimespec.tv_sec = timeout / 1000; - - totimespec.tv_nsec = (timeout % 1000) * 100000; - + totimespec.tv_nsec = (timeout % 1000) * 1000000; - - // printf("timespec: sec=%d nsec=%d\\n", totimespec.tv_sec, totimespec.tv_nsec); - - /* Make the call */ - - - + Py_BEGIN_ALLOW_THREADS - gotNumEvents = kevent (self->fd, changelist, haveNumEvents, triggered, wantNumEvents, &totimespec); - + Py_END_ALLOW_THREADS - - /* Don't need the input event list anymore, so get rid of it */ - free (changelist); - @@ -361,7 +362,7 @@ - statichere PyTypeObject KQueue_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - - PyObject_HEAD_INIT(NULL) - + PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ - "KQueue", /*tp_name*/ - sizeof(KQueueObject), /*tp_basicsize*/ +A complete repo with the change is available at: +U{http://bitbucket.org/psykidellic/select26/} """ @@ -62,9 +54,11 @@ from zope.interface import implements -from kqsyscall import EVFILT_READ, EVFILT_WRITE, EV_DELETE, EV_ADD -from kqsyscall import kqueue, kevent - +try: + import select26 as select +except ImportError: + import select + from twisted.internet.interfaces import IReactorFDSet from twisted.python import log, failure @@ -102,7 +96,7 @@ Initialize kqueue object, file descriptor tracking dictionaries, and the base class. """ - self._kq = kqueue() + self._kq = select.kqueue() self._reads = {} self._writes = {} self._selectables = {} @@ -110,7 +104,7 @@ def _updateRegistration(self, *args): - self._kq.kevent([kevent(*args)], 0, 0) + self._kq.control([select.kevent(*args)], 0, 0) def addReader(self, reader): """Add a FileDescriptor for notification of data available to read. @@ -119,7 +113,7 @@ if fd not in self._reads: self._selectables[fd] = reader self._reads[fd] = 1 - self._updateRegistration(fd, EVFILT_READ, EV_ADD) + self._updateRegistration(fd, select.KQ_FILTER_READ, select.KQ_EV_ADD) def addWriter(self, writer): """Add a FileDescriptor for notification of data available to write. @@ -128,7 +122,7 @@ if fd not in self._writes: self._selectables[fd] = writer self._writes[fd] = 1 - self._updateRegistration(fd, EVFILT_WRITE, EV_ADD) + self._updateRegistration(fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD) def removeReader(self, reader): """Remove a Selectable for notification of data available to read. @@ -138,7 +132,7 @@ del self._reads[fd] if fd not in self._writes: del self._selectables[fd] - self._updateRegistration(fd, EVFILT_READ, EV_DELETE) + self._updateRegistration(fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE) def removeWriter(self, writer): """Remove a Selectable for notification of data available to write. @@ -148,7 +142,7 @@ del self._writes[fd] if fd not in self._reads: del self._selectables[fd] - self._updateRegistration(fd, EVFILT_WRITE, EV_DELETE) + self._updateRegistration(fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE) def removeAll(self): """ @@ -169,13 +163,13 @@ def doKEvent(self, timeout): """Poll the kqueue for new events.""" - if timeout is None: - timeout = 1000 - else: - timeout = int(timeout * 1000) # convert seconds to milliseconds + #if timeout is None: + # timeout = 1000 + #else: + # timeout = int(timeout * 1000) # convert seconds to milliseconds try: - l = self._kq.kevent([], len(self._selectables), timeout) + l = self._kq.control([], len(self._selectables), timeout) except OSError, e: if e[0] == errno.EINTR: return @@ -195,9 +189,9 @@ def _doWriteOrRead(self, selectable, fd, filter): try: - if filter == EVFILT_READ: + if filter == select.KQ_FILTER_READ: why = selectable.doRead() - if filter == EVFILT_WRITE: + if filter == select.KQ_FILTER_WRITE: why = selectable.doWrite() if not selectable.fileno() == fd: why = main.CONNECTION_LOST