Skip to content

Instantly share code, notes, and snippets.

@sophacles
Last active September 13, 2015 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sophacles/996f1b18a5ac4263c5b5 to your computer and use it in GitHub Desktop.
Save sophacles/996f1b18a5ac4263c5b5 to your computer and use it in GitHub Desktop.
a posix forkpty implementation for gevent - works with pexpect nicely
# Make a forkpty wrapper that works nicely with gevent.
# This only wraps the process properly, the same way gevent.os.fork() does,
# and doesn't do anything special for dealing with the pty file descriptor.
#
# This was originally intended to work with pexpect, and does so nicely, since the
# head version of pexpect uses select.select and time.sleep in many places, effectively
# "geventifying" the expect interactions.
#
# Other things using forkpty and doing reads and writes via the pty will need to
# take a look at doing proper gevent wrapping of operations on the fd for now.
#
# N.B. - This almost certainly does not work on windows. If it does, your code is
# probably wrong, and the accident of it working is not to be counted on even
# across boots on the same machine
import gevent
import os
import gevent.os
from gevent import monkey
_real_forkpty = os.forkpty
def forkpty_and_watch(callback=None, loop=None, ref=False, fork=None):
"""
This is the same as gevent.forkpty_and_watch, except it wraps
os.forkpty rather than os.fork.
"""
# note result is a pair of (pid, fd)
# the value of pid is the same as if fork ahd been called
# fd is the appropriate pty device fd (master or slave as needed by parent or child)
result = _real_forkpty()
# act like gevent_fork was called
if not result[0]:
gevent.reinit()
return result
pid = result[0]
# direct copy of fork_and_watch, transliterated for not being deep in gevent
if pid:
# parent
loop = gevent.get_hub().loop
watcher = loop.child(pid)
gevent.os._watched_children[pid] = watcher
watcher.start(gevent.os._on_child, watcher, callback)
# return value is the (pid, fd) pair as forkpty() returns
return result
# just patch forkpty as if gevent.monkey.patch_os or patch_all had done it
monkey.patch_item(os, 'forkpty', forkpty_and_watch)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment