[Twisted-Python] _dumbwin32proc and PIPE_NOWAIT

Manlio Perillo manlio_perillo at libero.it
Sat Sep 30 05:06:03 MDT 2006


glyph at divmod.com ha scritto:
> [...]
> 
> "threads are bad"
> 

But they are used in twisted.enterprise.adbapi, and as I can see several
developers prefer to use threads to interact with "foreign" APIs instead
of develope native asyncronous API.

>> The solution is simple.
>> Windows *do not* supports POSIX ;-).
> 
> It does, however, support standard IO, at least well enough for a large
> chunk of applications.  Although it's not as well supported as on
> "POSIX" platforms, there are plenty of programs that produce output
> which Twisted can happily parse semi-asynchronously using the current
> strategy.  Why on earth would you want to remove it?  It serves a
> purpose (cross-platform multi-process communication and control), it
> works, it's tested.
> 

This is true, for sockets it works well, but for pipes it uses an
inefficient implementation.

> [...]

>> One needs to write a specializd abstract.FileDescriptor class, that use
>> the Overlapped structure for I/O.
> 
> You mean like twisted.internet.iocpreactor.abstract.ConnectedSocket? 
> Have you even read this code?
> 

Yes, but as the name suggests it works only for Sockets(?).

The problem is simple:
if I want to do asyncronous I/O with Windows I don't have an unique
'interface'.

Only sockets are really integrated with the reactor.
serialport has some specialized code for win32eventreactor integration,
but if I want to use, as an example, named pipe, I have to write my own
support
(but it seems this is an issue for broken POSIX implementations, too).


>> [snip more oblique allusions to various win32 APIs]
> 
> Frankly, I don't think you know what you're talking about.  

This is very likely ;-)

> If you know
> enough to make iocpreactor, or even win32eventreactor, work on Windows
> with SSL and GUI support, great, do that and contribute it, and we can
> discuss the patch.  If not, we're not going to break the *only* working,
> tested Windows reactor because you think one day it should be different.
> 

Is win32eventreactor not working and not tested?
You did not mention it in the "removing unsupported reactors in twisted"
thread.

>> This should allow one to easily use asyncronous I/O support of Window,
>> not only for sockets, but on all (not many...) 'handles' that support
>> the asyncronous I/O API.
> 
> If it's easy, feel free to do it :).
> 

I have write it, now stdio works ;-).

Unfortunately it is not very efficient since:
- it uses _pollingfile (not a real porblem)
- it reads raw keyboard input and have to do all low level stuff like
  '\b' handling, '\r' conversion, and so


Here is the main code.
I suspect such a thing will never be accepted into Twisted ;-):


class _PollableConsoleReader(_PollableResource):
    # XXX TODO add support for Window events (resize)
    implements(IPushProducer)

    def __init__(self, con, receivedCallback, lostCallback):
        self.con = con
        self.receivedCallback = receivedCallback
        self.lostCallback = lostCallback
        self.cp = "cp%d" % win32console.GetConsoleCP()

        # We need this
        self._stdout = win32console.GetStdHandle(
	                   win32console.STD_OUTPUT_HANDLE
                        )

    def checkWork(self):
        finished = 0
        fullDataRead = []

        info = self._stdout.GetConsoleScreenBufferInfo()
        Y = info["CursorPosition"].Y

        while 1:
            try:
                n = self.con.GetNumberOfConsoleInputEvents()
                if n == 0:
                    break

                records = self.con.ReadConsoleInput(n)

                # We need to process input
                # XXX check me
                # XXX TODO rewrite in C(?), now this is very inefficient
                for record in records:
                    if record.EventType != win32console.KEY_EVENT \
                            or not record.KeyDown:
                        continue

                    char = record.Char
                    if char == '\b':
                        # We need to handle this
                        info = self._stdout.GetConsoleScreenBufferInfo()
                        rowSize = info["MaximumWindowSize"].X
                        cursorPosition = info["CursorPosition"]

                        # Move the cursor
                        if cursorPosition.X == 0:
                            if cursorPosition.Y > Y:
                                cursorPosition.Y -= 1
                                cursorPosition.X = rowSize - 1
                        else:
                            cursorPosition.X -= 1

                        self._stdout.SetConsoleCursorPosition(
                            cursorPosition
                         )
                        self._stdout.WriteConsoleOutputCharacter(' ',
                                                      cursorPosition)
                        continue
                    elif char == '\0':
                        continue
                    elif char == '\r':
                        char = '\n'

                    char = char * record.RepeatCount
                    data = char.encode(self.cp)
                    self._stdout.WriteConsole(data) # Do echo

                    fullDataRead.append(data)
            except pywintypes.error:
                raise
                # XXX this should not happen
                finished = 1
                break

        dataBuf = ''.join(fullDataRead)
        if dataBuf:
            self.receivedCallback(dataBuf)
        if finished:
            self.cleanup()

        return len(dataBuf)

   ...

The ConsoleWriter does not need to support asyncronous I/O, so it is a
simple wrapper for ConsoleWrite.

This code still have some problems[1]...
For now I have added this to _pollingfile module.

The _win32stdio module can simply check if the stdin is attached to a
terminal, so it (hopefully) can support both pipes and consoles.


Many things can be added, like an emulation of POSIX terminal, callbacks
for resize events, support for focus in/out, colored output, history
editing, ...


[1]
How can be tested such a thing?



Regards  Manlio Perillo




More information about the Twisted-Python mailing list