pty difficulties
Justin Dubs
jtdubs at eos.ncsu.edu
Sat Jan 24 01:02:55 EST 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