| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 | ## File      : win32spawn.py# This file is part of RT-Thread RTOS# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team##  This program is free software; you can redistribute it and/or modify#  it under the terms of the GNU General Public License as published by#  the Free Software Foundation; either version 2 of the License, or#  (at your option) any later version.##  This program is distributed in the hope that it will be useful,#  but WITHOUT ANY WARRANTY; without even the implied warranty of#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the#  GNU General Public License for more details.##  You should have received a copy of the GNU General Public License along#  with this program; if not, write to the Free Software Foundation, Inc.,#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.## Change Logs:# Date           Author       Notes# 2015-01-20     Bernard      Add copyright information#import osimport threadingimport Queue# Windows import import win32fileimport win32pipeimport win32apiimport win32conimport win32securityimport win32processimport win32eventclass Win32Spawn(object):    def __init__(self, cmd, shell=False):        self.queue = Queue.Queue()        self.is_terminated = False        self.wake_up_event = win32event.CreateEvent(None, 0, 0, None)                exec_dir = os.getcwd()        comspec = os.environ.get("COMSPEC", "cmd.exe")        cmd = comspec + ' /c ' + cmd                win32event.ResetEvent(self.wake_up_event)        currproc = win32api.GetCurrentProcess()        sa = win32security.SECURITY_ATTRIBUTES()        sa.bInheritHandle = 1        child_stdout_rd, child_stdout_wr = win32pipe.CreatePipe(sa, 0)        child_stdout_rd_dup = win32api.DuplicateHandle(currproc, child_stdout_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)        win32file.CloseHandle(child_stdout_rd)        child_stderr_rd, child_stderr_wr = win32pipe.CreatePipe(sa, 0)        child_stderr_rd_dup = win32api.DuplicateHandle(currproc, child_stderr_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)        win32file.CloseHandle(child_stderr_rd)        child_stdin_rd, child_stdin_wr = win32pipe.CreatePipe(sa, 0)        child_stdin_wr_dup = win32api.DuplicateHandle(currproc, child_stdin_wr, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)        win32file.CloseHandle(child_stdin_wr)        startup_info = win32process.STARTUPINFO()        startup_info.hStdInput = child_stdin_rd        startup_info.hStdOutput = child_stdout_wr        startup_info.hStdError = child_stderr_wr        startup_info.dwFlags = win32process.STARTF_USESTDHANDLES        cr_flags = 0        cr_flags = win32process.CREATE_NEW_PROCESS_GROUP        env = os.environ.copy()        self.h_process, h_thread, dw_pid, dw_tid = win32process.CreateProcess(None, cmd, None, None, 1,                                                                              cr_flags, env, os.path.abspath(exec_dir),                                                                              startup_info)         win32api.CloseHandle(h_thread)        win32file.CloseHandle(child_stdin_rd)        win32file.CloseHandle(child_stdout_wr)        win32file.CloseHandle(child_stderr_wr)        self.__child_stdout = child_stdout_rd_dup        self.__child_stderr = child_stderr_rd_dup        self.__child_stdin = child_stdin_wr_dup        self.exit_code = -1    def close(self):        win32file.CloseHandle(self.__child_stdout)        win32file.CloseHandle(self.__child_stderr)        win32file.CloseHandle(self.__child_stdin)        win32api.CloseHandle(self.h_process)        win32api.CloseHandle(self.wake_up_event)    def kill_subprocess():        win32event.SetEvent(self.wake_up_event)    def sleep(secs):        win32event.ResetEvent(self.wake_up_event)        timeout = int(1000 * secs)        val = win32event.WaitForSingleObject(self.wake_up_event, timeout)        if val == win32event.WAIT_TIMEOUT:            return True        else:            # The wake_up_event must have been signalled            return False        def get(self, block=True, timeout=None):        return self.queue.get(block=block, timeout=timeout)    def qsize(self):        return self.queue.qsize()    def __wait_for_child(self):        # kick off threads to read from stdout and stderr of the child process        threading.Thread(target=self.__do_read, args=(self.__child_stdout, )).start()        threading.Thread(target=self.__do_read, args=(self.__child_stderr, )).start()        while True:            # block waiting for the process to finish or the interrupt to happen            handles = (self.wake_up_event, self.h_process)            val = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)            if val >= win32event.WAIT_OBJECT_0 and val < win32event.WAIT_OBJECT_0 + len(handles):                handle = handles[val - win32event.WAIT_OBJECT_0]                if handle == self.wake_up_event:                    win32api.TerminateProcess(self.h_process, 1)                    win32event.ResetEvent(self.wake_up_event)                    return False                elif handle == self.h_process:                    # the process has ended naturally                    return True                else:                    assert False, "Unknown handle fired"            else:                assert False, "Unexpected return from WaitForMultipleObjects"    # Wait for job to finish. Since this method blocks, it can to be called from another thread.    # If the application wants to kill the process, it should call kill_subprocess().    def wait(self):        if not self.__wait_for_child():            # it's been killed            result = False        else:            # normal termination            self.exit_code = win32process.GetExitCodeProcess(self.h_process)            result = self.exit_code == 0        self.close()        self.is_terminated = True                return result    # This method gets called on a worker thread to read from either a stderr    # or stdout thread from the child process.    def __do_read(self, handle):        bytesToRead = 1024        while 1:            try:                finished = 0                hr, data = win32file.ReadFile(handle, bytesToRead, None)                if data:                    self.queue.put_nowait(data)            except win32api.error:                finished = 1            if finished:                return    def start_pipe(self):        def worker(pipe):            return pipe.wait()                thrd = threading.Thread(target=worker, args=(self, ))        thrd.start()
 |