runtime/spawn_subprocess.py
changeset 2492 7dd551ac2fa0
parent 2322 7ce4e5cf6339
child 2537 eb4a4cc41914
equal deleted inserted replaced
2491:362039519454 2492:7dd551ac2fa0
     1 #!/usr/bin/env python
     1 #!/usr/bin/env python
     2 # -*- coding: utf-8 -*-
     2 # -*- coding: utf-8 -*-
     3 
     3 
     4 # subset of subprocess built-in module using posix_spawn rather than fork.
     4 # subset of subprocess built-in module using posix_spawn rather than fork.
     5 
     5 
     6 import posix_spawn
     6 from __future__ import absolute_import
     7 import os
     7 import os
     8 import signal
     8 import signal
       
     9 import posix_spawn
     9 
    10 
    10 PIPE = "42"
    11 PIPE = "42"
    11 
    12 
       
    13 
    12 class Popen(object):
    14 class Popen(object):
    13     def __init__(self, args,stdin=None, stdout=None):
    15     def __init__(self, args, stdin=None, stdout=None):
    14         self.returncode = None
    16         self.returncode = None
    15         self.stdout = None
    17         self.stdout = None
    16         self.stdin = None
    18         self.stdin = None
    17         # TODO: stderr
    19         # TODO: stderr
    18         file_actions = posix_spawn.FileActions()
    20         file_actions = posix_spawn.FileActions()
    38             self.stdin = os.fdopen(p2cwrite, 'w')
    40             self.stdin = os.fdopen(p2cwrite, 'w')
    39             os.close(p2cread)
    41             os.close(p2cread)
    40 
    42 
    41     def _wait(self):
    43     def _wait(self):
    42         if self.returncode is None:
    44         if self.returncode is None:
    43             self.returncode = os.waitpid(self.pid,0)[1]
    45             self.returncode = os.waitpid(self.pid, 0)[1]
    44 
    46 
    45     def communicate(self):
    47     def communicate(self):
    46         if self.stdin is not None:
    48         if self.stdin is not None:
    47             self.stdin.close()
    49             self.stdin.close()
    48             self.stdin = None
    50             self.stdin = None
    49         if self.stdout is not None:
    51         if self.stdout is not None:
    50             stdoutdata = self.stdout.read()
    52             stdoutdata = self.stdout.read()
    51         else:
    53         else:
    52             stdoutdata = ""
    54             stdoutdata = ""
    53         
    55 
    54         # TODO
    56         # TODO
    55         stderrdata = ""
    57         stderrdata = ""
    56 
    58 
    57         self._wait()
    59         self._wait()
    58         if self.stdout is not None:
    60         if self.stdout is not None:
    59             self.stdout.close()
    61             self.stdout.close()
    60             self.stdout = None
    62             self.stdout = None
    61         
    63 
    62         return (stdoutdata, stderrdata)
    64         return (stdoutdata, stderrdata)
    63 
    65 
    64     def wait(self):
    66     def wait(self):
    65         if self.stdin is not None:
    67         if self.stdin is not None:
    66             self.stdin.close()
    68             self.stdin.close()
    72         return self.returncode
    74         return self.returncode
    73 
    75 
    74     def poll(self):
    76     def poll(self):
    75         if self.returncode is None:
    77         if self.returncode is None:
    76             pid, ret = os.waitpid(self.pid, os.WNOHANG)
    78             pid, ret = os.waitpid(self.pid, os.WNOHANG)
    77             if (pid,ret) != (0,0):
    79             if (pid, ret) != (0, 0):
    78                 self.returncode = ret
    80                 self.returncode = ret
    79 
    81 
    80                 if self.stdin is not None:
    82                 if self.stdin is not None:
    81                     self.stdin.close()
    83                     self.stdin.close()
    82                     self.stdin = None
    84                     self.stdin = None
    83                 if self.stdout is not None:
    85                 if self.stdout is not None:
    84                     self.stdout.close()
    86                     self.stdout.close()
    85                     self.stdout = None
    87                     self.stdout = None
    86 
    88 
    87         return self.returncode
    89         return self.returncode
    88         
    90 
    89     def kill(self):
    91     def kill(self):
    90         os.kill(self.pid, signal.SIGKILL)
    92         os.kill(self.pid, signal.SIGKILL)
    91 
    93 
    92         if self.stdin is not None:
    94         if self.stdin is not None:
    93             self.stdin.close()
    95             self.stdin.close()
    94             self.stdin = None
    96             self.stdin = None
    95         if self.stdout is not None:
    97         if self.stdout is not None:
    96             self.stdout.close()
    98             self.stdout.close()
    97             self.stdout = None
    99             self.stdout = None
    98 
   100 
    99         
       
   100 
   101 
   101 def call(*args):
   102 def call(*args):
   102     cmd = []
   103     cmd = []
   103     if isinstance(args[0], str):
   104     if isinstance(args[0], str):
   104         if len(args)==1:
   105         if len(args) == 1:
   105             # oversimplified splitting of arguments,
   106             # oversimplified splitting of arguments,
   106             # TODO: care about use of simple and double quotes
   107             # TODO: care about use of simple and double quotes
   107             cmd = args[0].split()
   108             cmd = args[0].split()
   108         else:
   109         else:
   109             cmd = args
   110             cmd = args
   110     elif isinstance(args[0], list) and len(args)==1:
   111     elif isinstance(args[0], list) and len(args) == 1:
   111         cmd = args[0]
   112         cmd = args[0]
   112     else:
   113     else:
   113         raise Exception("Wrong arguments passed to subprocess.call")
   114         raise Exception("Wrong arguments passed to subprocess.call")
   114     pid = posix_spawn.posix_spawnp(cmd[0], cmd)
   115     pid = posix_spawn.posix_spawnp(cmd[0], cmd)
   115     return os.waitpid(pid,0)
   116     return os.waitpid(pid, 0)
       
   117 
   116 
   118 
   117 if __name__ == '__main__':
   119 if __name__ == '__main__':
   118     # unit test
   120     # unit test
   119 
   121 
   120     p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE)
   122     p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE)
   121     p.stdin.write("blah")
   123     p.stdin.write("blah")
   122     p.stdin.close()
   124     p.stdin.close()
   123     print p.stdout.read()
   125     print(p.stdout.read())
   124     p.wait()
   126     p.wait()
   125 
   127 
   126     p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE)
   128     p = Popen(["tr", "abc", "def"], stdin=PIPE, stdout=PIPE)
   127     p.stdin.write("blah")
   129     p.stdin.write("blah")
   128     print p.communicate()
   130     print(p.communicate())
   129 
   131 
   130     call("echo blah0")
   132     call("echo blah0")
   131     call(["echo", "blah1"])
   133     call(["echo", "blah1"])
   132     call("echo", "blah2")
   134     call("echo", "blah2")