pty difficulties

Justin Dubs jtdubs at eos.ncsu.edu
Sat Jan 24 07:02:55 CET 2004


I'm writing a utility that runs a program inside of a pseudo-tty and
then multiplexes both stdin and a fifo to the child's pty via a select
loop.

In other words, you run my program, tell it the name of the program to
run and the name of the fifo to use and then you can interact with the
program as per usual.  However, you can also send data into the fifo
and the program will see it as input just as if you'd typed it on the
keyboard.

As a test I'm running sbcl (a lisp interpreter) through my python
program.  It works like a charm in normal usage.  However, if I dump
more than 2K or so of code into the FIFO, sbcl gets the first K fine,
but then seems to miss a chunk, get another character or two and then
freeze.  After that I am unable to interact with it via either stdin
or the fifo even though the select loop is still running.  The pty
just seems to be dead, eating input and giving nothing back.  So, I
tried running a different Lisp interpreter (openmcl) instead, but the
problem persisted.  So, I just ran vim through it and it handled the
2K of text just fine.

However, vim is just sending the text into a buffer where-as sbcl is
parsing and compiling it.  If I add a sleep(1.0) after data is sent
from the fifo to the pty then the problem goes away.  So, it seems
like if the child process can't pull things out of it's stdin as fast
as I'm putting it in, something goes awry.

Has anyone seen similar behavior?  Does anyone have any idea why this
would be happening?

Any help would be greatly appreciated.  Thanks everyone.  The code is
below.

Justin Dubs


Here's the code:

from time    import sleep
from pty     import spawn, fork
from sys     import stdin, stdout, stderr, exit, argv
from os      import fdopen, open, read, write, O_RDONLY, O_NONBLOCK
from select  import select
from termios import tcgetattr, tcsetattr, tcdrain, ECHO, TCSADRAIN
from tty     import setraw

if (len(argv) != 3):
    print "usage: vee.py program pipe"
    exit(0)

pid, childID = fork()

if pid == 0:
    spawn(argv[1])
else:
    fifo  = fdopen(open(argv[2], O_RDONLY | O_NONBLOCK), 'r')
    child = fdopen(childID, 'r+')

    attribs = tcgetattr(stdin)
    attribs[3] = attribs[3] & ~ECHO
    tcsetattr(stdin, TCSADRAIN, attribs)

    setraw(stdin)

    connections = { child : stdout, stdin : child, fifo : child }

    try:
        while True:
            readable = select(connections.keys(), [], [])[0]
            for f in readable:
                data = read(f.fileno(), 1024)
                connections[f].write(data)
                connections[f].flush()
    except (OSError, IOError):
        exit(0)



More information about the Python-list mailing list