pty difficulties

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Justin Dubs

    pty difficulties

    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(arg v[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(connecti ons.keys(), [], [])[0]
    for f in readable:
    data = read(f.fileno() , 1024)
    connections[f].write(data)
    connections[f].flush()
    except (OSError, IOError):
    exit(0)
  • Josiah Carlson

    #2
    Re: pty difficulties

    > while True:[color=blue]
    > readable = select(connecti ons.keys(), [], [])[0]
    > for f in readable:
    > data = read(f.fileno() , 1024)
    > connections[f].write(data)
    > connections[f].flush()[/color]

    I believe your problem exists in the write and flush. All you seem to
    be doing is checking to see if your reading file handles are capable of
    reading, you never check to see if you can write to anything. Your lisp
    interpreter showcases the fact that it is not ready to get a write while
    it is interpreting, by failing. I believe the following should fix you up:

    while True:
    readable = select(connecti ons.keys(), [], [])[0]
    for f in readable:
    if select([], [connections[f]], [], 0)[1]:
    data = read(f.fileno() , 1024)
    connections[f].write(data)
    connections[f].flush()

    - Josiah

    Comment

    • Justin Dubs

      #3
      Re: pty difficulties

      Josiah Carlson <jcarlson@nospa m.uci.edu> wrote in message news:<butccm$2u n$1@news.servic e.uci.edu>...[color=blue][color=green]
      > > while True:
      > > readable = select(connecti ons.keys(), [], [])[0]
      > > for f in readable:
      > > data = read(f.fileno() , 1024)
      > > connections[f].write(data)
      > > connections[f].flush()[/color]
      >
      > I believe your problem exists in the write and flush. All you seem to
      > be doing is checking to see if your reading file handles are capable of
      > reading, you never check to see if you can write to anything. Your lisp
      > interpreter showcases the fact that it is not ready to get a write while
      > it is interpreting, by failing. I believe the following should fix you up:
      >
      > while True:
      > readable = select(connecti ons.keys(), [], [])[0]
      > for f in readable:
      > if select([], [connections[f]], [], 0)[1]:
      > data = read(f.fileno() , 1024)
      > connections[f].write(data)
      > connections[f].flush()[/color]

      Thanks for the suggestions, but this didn't help. I should have
      mentioned that I had tried this before. Here's the code I had used:

      while True:
      readable, writeable, ignore = select(connecti ons.keys(),
      connections.val ues(), [])
      for f in readable:
      if connections[f] in writeable:
      data = read(f.fileno() , 1024)
      connections[f].write(data)
      connections[f].flush()

      I don't think checking for writeable status /should/ help because the
      write call I am using blocks. So, if the stream isn't writeable, it
      should just block until it is. I think.

      Justin Dubs

      Comment

      • Josiah Carlson

        #4
        Re: pty difficulties

        > I don't think checking for writeable status /should/ help because the[color=blue]
        > write call I am using blocks. So, if the stream isn't writeable, it
        > should just block until it is. I think.[/color]

        Hrm. Perhaps you should just leave the sleep in there. One second
        seems a bit much, but maybe .01 or .001 seconds is sufficient. You
        could reasonably still get 100K-1M/second. One would hope that would be
        enough for most tasks.

        - Josiah

        Comment

        Working...