180 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			180 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|  | # | ||
|  | # 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 os | ||
|  | import threading | ||
|  | import Queue | ||
|  | 
 | ||
|  | # Windows import  | ||
|  | import win32file | ||
|  | import win32pipe | ||
|  | import win32api | ||
|  | import win32con | ||
|  | import win32security | ||
|  | import win32process | ||
|  | import win32event | ||
|  | 
 | ||
|  | class 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() |