[Twisted-Python] Win32 events main loop

Hi all, Here is the first *rough* cut of the Twisted main loop using Win32 events, based upon internet.poll. It seems to be okay for simpleserv.py, but I haven't tested it for anything else. I'll leave that to a day when I'm not feeling so ill... I pretty much guarantee it is mostly broken -- think of it as a proof of concept. I think if I experiment with MsgWaitForMultipleObjects instead of WaitForMultipleObjects, I can make it respond to Win32 window messages properly; e.g. Ctrl-C and stopping when running as a service might work nicely -- COM stuff would probably benefit too. Enjoy! -Andrew. --- win32.py --- # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """A win32event based implementation of the twisted main loop. To install the event loop (and you should do this before any connections, listeners or connectors are added): from twisted.internet import win32 win32.install() """ # Win32 imports from win32file import WSAEventSelect, FD_READ, FD_WRITE, FD_CLOSE, \ FD_ACCEPT, FD_CONNECT from win32event import CreateEvent, WaitForMultipleObjects, \ WAIT_OBJECT_0, WAIT_TIMEOUT, INFINITE # Twisted imports from twisted.python import log, threadable import main # globals reads = {} writes = {} events = {} def _addEvent(fd, why, events=events): print '_addEvent:', fd, why event = CreateEvent(None, 0, 0, None) WSAEventSelect(fd, event, why) events[event] = (fd, why) return event def addReader(reader, reads=reads): """Add a FileDescriptor for notification of data available to read. """ print 'addReader:', reader if not reads.has_key(reader): reads[reader] = _addEvent(reader, FD_READ|FD_ACCEPT|FD_CONNECT) def addWriter(writer, writes=writes): """Add a FileDescriptor for notification of data available to write. """ print 'addWriter:', writer if not writes.has_key(writer): writes[writer] =_addEvent(writer, FD_WRITE) def removeReader(reader): """Remove a Selectable for notification of data available to read. """ if reads.has_key(reader): del events[reads[reader]] del reads[reader] def removeWriter(writer, writes=writes): """Remove a Selectable for notification of data available to write. """ if writes.has_key(writer): del events[writes[writer]] del writes[writer] def removeAll(): """Remove all selectables, and return a list of them.""" result = reads.keys() + writes.keys() reads.clear() writes.clear() events.clear() return result def doWaitForMultipleEvents(timeout, reads=reads, writes=writes): if timeout is None: #timeout = INFINITE timeout = 5000 else: timeout = timeout * 1000 print 'timeout is:', timeout handles = events.keys() val = WaitForMultipleObjects(handles, 0, timeout) print 'WaitForMultipleObjects returned:', val if val == WAIT_TIMEOUT: return elif val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles): print 'Here' fd, why = events[handles[val - WAIT_OBJECT_0]] print fd, why log.logOwner.own(fd) try: if why & FD_READ|FD_ACCEPT|FD_CONNECT: fd.doRead() elif why == FD_WRITE: fd.doWrite() except: log.deferr() why = FD_CLOSE if why == FD_CLOSE: removeReader(fd) removeWriter(fd) try: fd.connectionLost() except: log.deferr() log.logOwner.disown(fd) def install(): """Install the poll()-based event loop.""" main.addReader = addReader main.addWriter = addWriter main.removeReader = removeReader main.removeWriter = removeWriter #main.doSelect = doPoll main.doSelect = doWaitForMultipleEvents main.removeAll = removeAll def initThreads(): """Do initialization for threads.""" if main.wakerInstalled: # make sure waker is registered with us removeReader(main.waker) addReader(main.waker) threadable.whenThreaded(initThreads) __all__ = ["install"]

Andrew Bennetts wrote:
Here is the first *rough* cut of the Twisted main loop using Win32 events, based upon internet.poll.
Cool! I'll test it a bit and then check it in, and maybe we should talk to glyph about giving you CVS write access :) The next stage, one it's stable and more or less bug free, is probably making it more generic, so you can use it with things that aren't sockets (e.g. stdin/stdout, pipes, files, etc.) Also integration with the win32 GUI event loop win32all exposes, which I think uses the same subsystem.

On Sun, Mar 03, 2002 at 06:37:30PM -0500, Itamar Shtull-Trauring wrote:
Yeah. I'm not certain about how to do that, but it should be feasible.
the win32 GUI event loop win32all exposes, which I think uses the same subsystem.
Yeah; that means using MsgWaitForMultipleObjects instead of WaitForMultipleObjects, basically (and checking for an extra possible return value...). I believe more than strictly GUI stuff will require this, in fact -- I suspect COM will not function properly in a thread that is blocked in WaitForMultipleObjects, from what I have read. -Andrew.

Andrew Bennetts wrote:
Here is the first *rough* cut of the Twisted main loop using Win32 events, based upon internet.poll.
Cool! I'll test it a bit and then check it in, and maybe we should talk to glyph about giving you CVS write access :) The next stage, one it's stable and more or less bug free, is probably making it more generic, so you can use it with things that aren't sockets (e.g. stdin/stdout, pipes, files, etc.) Also integration with the win32 GUI event loop win32all exposes, which I think uses the same subsystem.

On Sun, Mar 03, 2002 at 06:37:30PM -0500, Itamar Shtull-Trauring wrote:
Yeah. I'm not certain about how to do that, but it should be feasible.
the win32 GUI event loop win32all exposes, which I think uses the same subsystem.
Yeah; that means using MsgWaitForMultipleObjects instead of WaitForMultipleObjects, basically (and checking for an extra possible return value...). I believe more than strictly GUI stuff will require this, in fact -- I suspect COM will not function properly in a thread that is blocked in WaitForMultipleObjects, from what I have read. -Andrew.
participants (2)
-
Andrew Bennetts
-
Itamar Shtull-Trauring