[Twisted-Python] Understanding the IOCP reactor and adding spawnProcess
pp64 at codelock.com
Mon Jul 11 16:49:04 EDT 2005
On Mon, 11 Jul 2005 10:52:14 -0500
Justin Johnson <justinjohnson at gmail.com> wrote:
> I am attempting to add spawnProcess to iocpreactor. In order to begin
> task I've had to do a lot of reading on Windows network programming,
> specifically the various Windows I/O methods, to attempt to understand
> win32eventreactor and iocpreactor are doing, and also just increase my
> understanding of how reactors work in general. To understand the
> Winsock 2 methods that both of these reactors rely upon, I read
> of Network Programming for Microsoft Windows.
> Before actually attempting to add spawnProcess, I would like to
> I think iocpreactor works and how I think I should add spawnProcess,
> hopefully be corrected or confirmed in my understanding. If I'm too
> there's a good chance it's because I don't understand it very well.
> feel free to point out things that you might think are obvious but
> sure I understand.
> How iocpreactor works
> 1. Create an IO Completion Port.
> 2. Create a socket and associate it with the IOCP. This is the
> we will call AcceptEx (a non-blocking accept) on. The association
> IOCP is made via CreateIoCompletionPort.
> 3. Setup any scheduled tasks on the reactor.
> 4. Call AcceptEx (which doesn't block) on the socket. AcceptEx
> an overlapped structure as a parameter. Before making the call, we
> attributes of the struct: the callback and callback_args which will
> called when an accept event completes on the socket. The Winsock 2
> don't actually call the callback. The Winsock 2 methods handle
> related to the network event that occurred on the socket into the
> structure and making that overlapped structure available to
> GetQueuedCompletionStatus. So when we handle events on sockets via
> GetQueuedCompletionStatus from within doIteration, we have access
> data related to the event as well as the callback and callback_args
> to handle that event. The callbacks are setup in the xxxOp classes
> ops.py and always result in some transport method getting called
> as readDone, connectionDone, etc).
> 5. From within doIteration, call GetQueuedCompletionStatus (which
> block) with a timeout of the time until the next scheduled task
needs to be
> run. If any event occurs on the sockets currently associated with
> before that time expires, GetQueuedCompletionStatus will return
> blocking). Now we have access to the overlapped structure
> associated with the event which was copied into the overlapped
> buffer, such as data received from WSARecv calls, as well as the
> and callback_args. From within doIteration we call the callbacks
> the data related to the event. Depending on the events we are
> may create new sockets (e.g. end point sockets in TCP connections)
> associate them with the IOCP as well. All Winsock 2 API calls made
> non-blocking accept for GetQueuedCompletionStatus.
> 6. Step 5 continues until the reactor stops.
This sounds about right. Note how this is different from the usual
reactor thing -- iocp notifies you when the operation is _finished_,
not when it can success without blocking.
> How to add spawnProcess
> 1. Create the processes via Windows APIs and associate their
> stdout/err with with the IOCP via CreateIoCompletionPort calls.
> 2. Close stdin.
> 3. Notify the ProcessProtocol via protocol.makeConnection (not sure
> why, looking at win32eventreactor)
> 4. Receive data from stdout/err via the completion port by calling
> GetQueuedCompletionStatus from within doIteration. Is this really
> ProcessProtocol's methods won't get called appropriately by letting
> existing callbacks in ops.py make calls to the transport (e.g.
> connectionDone, readDone)?
Hrm. Not quite. In iocp, you always have a read call pending
(ReadFileEx, for stdout/err handles). When it completes, you get a
notification in GetQueuedCompletionStatus, pass the data to your
Protocol and schedule the read again.
Do that for stdout and stderr.
ops.py already has a wrapper for ReadFile, but it always calls readDone
and readErr on your transport. You'll need to fix that.
More information about the Twisted-Python