diff -r 0a3103cd825d -r 7ce4e5cf6339 runtime/spawn_subprocess.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runtime/spawn_subprocess.py Tue Oct 23 16:13:34 2018 +0200 @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# subset of subprocess built-in module using posix_spawn rather than fork. + +import posix_spawn +import os +import signal + +PIPE = "42" + +class Popen(object): + def __init__(self, args,stdin=None, stdout=None): + self.returncode = None + self.stdout = None + self.stdin = None + # TODO: stderr + file_actions = posix_spawn.FileActions() + if stdout is not None: + # child's stdout, child 2 parent pipe + c2pread, c2pwrite = os.pipe() + # attach child's stdout to writing en of c2p pipe + file_actions.add_dup2(c2pwrite, 1) + # close other end + file_actions.add_close(c2pread) + if stdin is not None: + # child's stdin, parent to child pipe + p2cread, p2cwrite = os.pipe() + # attach child's stdin to reading en of p2c pipe + file_actions.add_dup2(p2cread, 0) + # close other end + file_actions.add_close(p2cwrite) + self.pid = posix_spawn.posix_spawnp(args[0], args, file_actions=file_actions) + if stdout is not None: + self.stdout = os.fdopen(c2pread) + os.close(c2pwrite) + if stdin is not None: + self.stdin = os.fdopen(p2cwrite, 'w') + os.close(p2cread) + + def _wait(self): + if self.returncode is None: + self.returncode = os.waitpid(self.pid,0)[1] + + def communicate(self): + if self.stdin is not None: + self.stdin.close() + self.stdin = None + if self.stdout is not None: + stdoutdata = self.stdout.read() + else: + stdoutdata = "" + + # TODO + stderrdata = "" + + self._wait() + if self.stdout is not None: + self.stdout.close() + self.stdout = None + + return (stdoutdata, stderrdata) + + def wait(self): + if self.stdin is not None: + self.stdin.close() + self.stdin = None + self._wait() + if self.stdout is not None: + self.stdout.close() + self.stdout = None + return self.returncode + + def poll(self): + if self.returncode is None: + pid, ret = os.waitpid(self.pid, os.WNOHANG) + if (pid,ret) != (0,0): + self.returncode = ret + + if self.stdin is not None: + self.stdin.close() + self.stdin = None + if self.stdout is not None: + self.stdout.close() + self.stdout = None + + return self.returncode + + def kill(self): + os.kill(self.pid, signal.SIGKILL) + + if self.stdin is not None: + self.stdin.close() + self.stdin = None + if self.stdout is not None: + self.stdout.close() + self.stdout = None + + + +def call(*args): + cmd = [] + if isinstance(args[0], str): + if len(args)==1: + # oversimplified splitting of arguments, + # TODO: care about use of simple and double quotes + cmd = args[0].split() + else: + cmd = args + elif isinstance(args[0], list) and len(args)==1: + cmd = args[0] + else: + raise Exception("Wrong arguments passed to subprocess.call") + pid = posix_spawn.posix_spawnp(cmd[0], cmd) + return os.waitpid(pid,0) + +if __name__ == '__main__': + # unit test + + p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE) + p.stdin.write("blah") + p.stdin.close() + print p.stdout.read() + p.wait() + + p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE) + p.stdin.write("blah") + print p.communicate() + + call("echo blah0") + call(["echo", "blah1"]) + call("echo", "blah2")