Package qm :: Module executable
[hide private]
[frames] | no frames]

Source Code for Module qm.executable

   1  ######################################################################## 
   2  # 
   3  # File:   executable.py 
   4  # Author: Mark Mitchell 
   5  # Date:   11/14/2002 
   6  # 
   7  # Contents: 
   8  #   Executable, RedirectedExecutable 
   9  # 
  10  # Copyright (c) 2002, 2003 by CodeSourcery, LLC.  All rights reserved.  
  11  # 
  12  ######################################################################## 
  13   
  14  ######################################################################## 
  15  # Imports 
  16  ####################################################################### 
  17   
  18  import os 
  19  import qm.common 
  20  import signal 
  21  import string 
  22  import sys 
  23  import time 
  24   
  25  # The classes in this module are implemented differently depending on 
  26  # the operating system in use. 
  27  if sys.platform == "win32": 
  28      import msvcrt 
  29      import pywintypes 
  30      from   threading import * 
  31      import win32api 
  32      import win32con 
  33      import win32event 
  34      import win32file 
  35      import win32pipe 
  36      import win32process 
  37  else: 
  38      import cPickle 
  39      import fcntl 
  40      import select 
  41      import qm.sigmask 
  42       
  43  ######################################################################## 
  44  # Classes 
  45  ####################################################################### 
  46   
47 -class Executable(object):
48 """An 'Executable' is a program that the operating system can run. 49 50 'Exectuable' (and classes derived from it) create child processes. 51 The 'Spawn' function creates child processes that execute 52 asynchronously. The 'Run' function creates child processes that 53 execute synchrounously, i.e,. the 'Run' function does not return 54 until the child process has completed its execution. 55 56 It is safe to reuse a particular 'Executable' instance (by calling 57 'Spawn' or 'Run' more than once), so long as the uses are not 58 interleaved.""" 59
60 - def Spawn(self, arguments=[], environment = None, dir = None, 61 path = None, exception_pipe = None):
62 """Spawn the program. 63 64 'arguments' -- The sequence of arguments that should be passed 65 to the executable. The first argument provided in this 66 sequence will be 'argv[0]'; that is also the value used for 67 the path to the executable. 68 69 'environment' -- If not 'None', a dictionary giving the 70 environment that should be provided to the child. 71 72 'dir' -- If not 'None', the directory in which the child 73 should begin execution. If 'None', the child will execute in 74 the same directory as the parent. 75 76 'path' -- If not 'None', the path to the program to run. If 77 'None', 'arguments[0]' is used. 78 79 'exception_pipe' -- If not 'None', a pipe that the child can 80 use to communicate an exception to the parent. This pipe is 81 only used on UNIX systems. The write end of the pipe will be 82 closed by this function. 83 84 returns -- The PID of the child. 85 86 Before creating the child, the parent will call 87 'self._InitializeParent'. On UNIX systems, the child will 88 call 'self._InitializeChild' after 'fork', but before 'exec'. 89 On non-UNIX systems, 'self._InitializeChild' will never be 90 called. 91 92 After creating the child, 'self._HandleChild' is called in the 93 parent. This hook should be used to handle tasks that must be 94 performed after the child is running. 95 96 If the path to the program is absolute, or contains no 97 separator characters, it is not modified. Otherwise the path 98 to the program is relative, it is transformed into an absolute 99 path using 'dir' as the base, or the current directory if 100 'dir' is not set.""" 101 102 # Remember the directory in which the execution will occur. 103 self.__dir = dir 104 105 # The path to the executable is the first argument, if not 106 # explicitly specified. 107 if not path: 108 path = arguments[0] 109 110 # Normalize the path name. At the conclusion of this 111 # processing, the path is either an absolute path, or contains 112 # no directory seperators. 113 if os.path.isabs(path): 114 # An absolute path. 115 pass 116 elif (os.sep in path or (os.altsep and os.altsep in path)): 117 # A relative path name, like "./program". 118 if dir: 119 path = os.path.normpath(os.path.join(dir, path)) 120 if not os.path.isabs(path): 121 path = os.path.abspath(path) 122 else: 123 path = os.path.abspath(path) 124 else: 125 # A path with no directory separators. The program to 126 # execute will be found by searching the PATH environment 127 # variable. 128 pass 129 130 # Initialize the parent. 131 startupinfo = self._InitializeParent() 132 133 # Initialize self.__child so that if "fork" or "CreateProcess" 134 # throws an exception our caller can tell that there is no 135 # child process to kill. 136 self.__child = None 137 138 if sys.platform == "win32": 139 # Compute the command line. The Windows API uses a single 140 # string as the command line, rather than an array of 141 # arguments. 142 command_line = self.__CreateCommandLine(arguments) 143 144 # If the path is not absolute, then we need to search the 145 # PATH. Since CreateProcess only searches the PATH if its 146 # first argument is None, we clear path here. 147 if not os.path.isabs(path): 148 path = None 149 150 # Windows supports wide-characters in the environment, but 151 # the Win32 extensions to Python require that all of the 152 # entries in the environment be of the same type, 153 # i.e,. that either all of them be of type StringType or 154 # of type UnicodeType. Therefore, if we find any elements 155 # that are Unicode strings, convert all of them to Unicode 156 # strings. 157 if environment is not None: 158 # See if there any Unicode strings in the environment. 159 uses_unicode = 0 160 for (k, v) in environment.iteritems(): 161 if (isinstance(k, unicode) 162 or isinstance(v, unicode)): 163 uses_unicode = 1 164 break 165 # If there are Unicode strings in the environment, 166 # convert all of the key-value pairs to Unicode. 167 if uses_unicode: 168 new_environment = {} 169 for (k, v) in environment.iteritems(): 170 new_environment[unicode(k)] = unicode(v) 171 environment = new_environment 172 173 # Create the child process. 174 self.__child \ 175 = win32process.CreateProcess(path, 176 command_line, 177 None, 178 None, 179 1, 180 0, 181 environment, 182 self.__dir, 183 startupinfo)[0] 184 else: 185 # Fork. 186 self.__child = os.fork() 187 188 if self.__child == 0: 189 try: 190 # Close the read end of the pipe. 191 if exception_pipe: 192 os.close(exception_pipe[0]) 193 # Initialize the child. 194 self._InitializeChild() 195 # Exec the program. 196 if environment: 197 os.execvpe(path, arguments, environment) 198 else: 199 os.execvp(path, arguments) 200 except: 201 if exception_pipe: 202 # Get the exception information. 203 exc_info = sys.exc_info() 204 # Write it to the pipe. The traceback object 205 # cannot be pickled, unfortunately, so we 206 # cannot communicate that information. 207 cPickle.dump(exc_info[:2], 208 os.fdopen(exception_pipe[1], "w"), 209 1) 210 # Exit without running cleanups. 211 os._exit(1) 212 213 # This code should never be reached. 214 assert None 215 216 # Nothing will be written to the exception pipe in the parent. 217 if exception_pipe: 218 os.close(exception_pipe[1]) 219 220 # Let the parent take any actions required after creating the 221 # child. 222 self._HandleChild() 223 224 return self.__child
225 226
227 - def Run(self, arguments=[], environment = None, dir = None, 228 path = None):
229 """Spawn the program and wait for it to finish. 230 231 'arguments' -- The sequence of arguments that should be passed 232 to the executable. The first argument provided in this 233 sequence will be 'argv[0]'. 234 235 'environment' -- If not 'None', a dictionary giving the 236 environment that should be provided to the child. If 'None', 237 the child will inherit the parents environment. 238 239 'dir' -- If not 'None', the directory in which the child 240 should begin execution. If 'None', the child will execute in 241 the same directory as the parent. 242 243 'path' -- If not 'None', the path to the program to run. If 244 'None', 'arguments[0]' is used. 245 246 returns -- The status returned by the program. Under UNIX, 247 this is the value returned by 'waitpid'; under Windows, it is 248 the value returned by 'GetExitCodeProcess'. 249 250 After invoking 'Spawn', this function invokes '_DoParent' to 251 allow the parent process to perform whatever actions are 252 required. After that function returns, the parent waits for 253 the child process to exit.""" 254 255 # If fork succeeds, but the exec fails, we want information 256 # about *why* it failed. The exit code from the subprocess is 257 # not nearly as illuminating as the exception raised by exec. 258 # Therefore, we create a pipe between the parent and child; 259 # the child writes the exception into the pipe to communicate 260 # it to the parent. 261 if sys.platform != "win32": 262 exception_pipe = os.pipe() 263 # Mark the write end as close-on-exec so that the file 264 # descriptor is not passed on to the child. 265 qm.common.close_file_on_exec(exception_pipe[1]) 266 else: 267 exception_pipe = None 268 269 # Start the program. 270 child = self.Spawn(arguments, environment, dir, path, exception_pipe) 271 272 # Give the parent a chance to do whatever it needs to do. 273 self._DoParent() 274 275 # Wait for the child to exit. 276 if sys.platform == "win32": 277 win32event.WaitForSingleObject(child, win32event.INFINITE) 278 # Get its exit code. 279 return win32process.GetExitCodeProcess(child) 280 else: 281 status = os.waitpid(child, 0)[1] 282 # See if an exception was pushed back up the pipe. 283 data = os.fdopen(exception_pipe[0]).read() 284 # If any data was read, then it is data corresponding to 285 # the exception thrown by exec. 286 if data: 287 # Unpickle the data. 288 exc_info = cPickle.loads(data) 289 # And raise it here. 290 raise exc_info[0], exc_info[1] 291 292 return status
293 294
295 - def _InitializeParent(self):
296 """Initialize the parent process. 297 298 Before spawning the child, this method is invoked to give the 299 parent a chance to initialize itself. 300 301 returns -- Under Windows, a 'PySTARTUPINFO' structure 302 explaining how the child should be initialized. On other 303 systems, the return value is ignored.""" 304 305 if sys.platform == "win32": 306 return win32process.STARTUPINFO()
307 308
309 - def Kill(self):
310 """Kill the child process. 311 312 The child process is killed in a way that does not permit an 313 orderly shutdown. In other words, 'SIGKILL' is used under 314 UNIX, not 'SIGTERM'. On Windows, 'TerminateProcess' is used, 315 and the exit code from the child process will be '1'.""" 316 317 if sys.platform == "win32": 318 win32process.TerminateProcess(self._GetChildPID(), 1) 319 else: 320 os.kill(self._GetChildPID(), signal.SIGKILL)
321 322
323 - def _HandleChild(self):
324 """Run in the parent process after the child has been created. 325 326 The child process has been spawned; its PID is avialable via 327 '_GetChildPID'. Take any actions in the parent that are 328 required now that the child exists. 329 330 Derived class versions must call this method.""" 331 332 pass
333 334
335 - def _InitializeChild(self):
336 """Initialize the child process. 337 338 After 'fork' is called this method is invoked to give the 339 child a chance to initialize itself. '_InitializeParent' will 340 already have been called in the parent process. 341 342 This method is not used under Windows.""" 343 344 assert sys.platform != "win32" 345 346 # The way Python's threading support works, every thread except 347 # the main thread always has all signals blocked. This is fine 348 # for the threads themselves, but it causes problems if we 349 # 'fork' from a child thread; the new process starts with all 350 # signals blocked, which is probably not what you want! 351 # Arguably this is a bug in Python, but for the meantime, work 352 # around this by setting the new process's signal mask to match 353 # the signal mask that QMTest was started with. 354 qm.sigmask.restore_mask() 355 356 if self.__dir: 357 os.chdir(self.__dir)
358 359
360 - def _DoParent(self):
361 """Perform actions required in the parent after 'Spawn'.""" 362 363 pass
364 365
366 - def _GetChildPID(self):
367 """Return the process ID for the child process. 368 369 returns -- The process ID for the child process. (On Windows, 370 the value returned is the process handle.) Returns 'None' if 371 the child has not yet been created, or if something went awry 372 when creating it. For example, if 'os.fork' throws an 373 exception, this value will return 'None'.""" 374 375 return self.__child
376 377
378 - def __CreateCommandLine(self, arguments):
379 """Return a string giving the process command line. 380 381 arguments -- A sequence of arguments (including argv[0]) 382 indicating the command to be run. 383 384 returns -- A string that could be provided to the shell in 385 order to run the command.""" 386 387 command = "" 388 need_space = 0 389 for a in arguments: 390 # Add a space between arguments. 391 if need_space: 392 command += " " 393 else: 394 need_space = 1 395 # If the argument contains whitespace characters, enclose 396 # it in quotes. Similarly, an empty argument must be 397 # enclosed in quotes. 398 if not a: 399 command += '""' 400 continue 401 whitespace = 0 402 for c in string.whitespace: 403 if c in a: 404 whitespace = 1 405 break 406 if whitespace: 407 command += '"' + a + '"' 408 else: 409 command += a 410 411 return command
412 413 414
415 -class TimeoutExecutable(Executable):
416 """A 'TimeoutExecutable' runs for a limited time. 417 418 If the timer expires, the child process is killed and 419 self.timedout is set to 1. Otherwise, self.timedout is set to 0. 420 421 In order to implement this functionality under UNIX, the child 422 process is placed into its own process group. An additional 423 monitoring process is created whose sole job is to kill the 424 primary child's process group if the timeout expires. Process 425 groups are used so that if the child process spawns additional 426 processes they are killed too. A separate monitoring process is 427 used so as not to block the parent. 428 429 Under Windows, a monitoring thread is created. When the timer 430 expires, the child process is terminated. However, the child 431 process is not placed into a separate process group, so 432 granchildren kare not terminated. In the future, when Python 433 provides access to 'CreateJobObject' and related functions, jobs 434 will be used to provide functionality similar to UNIX process 435 groups. 436 437 The 'Run' method will automatically start the monitoring process. 438 The 'Spawn' method does not start the monitoring process. User's 439 of 'Spawn' should invoke '_DoParent' in order to start the 440 monitoring process. Derived class '_DoParent' functions should 441 call the version defined in this class.""" 442
443 - def __init__(self, timeout = -1):
444 """Construct a new 'TimeoutExecutable'. 445 446 'timeout' -- The number of seconds that the child is permitted 447 to run. This value may be a floating-point value. However, 448 the value may be rounded to an integral value on some systems. 449 Once the timeout expires, the child and its entire process 450 group is killed. (The processes in the process group are sent 451 the 'SIGKILL' signal.) If the 'timeout' is -2, the child is 452 allowed to run forever, but when it terminates the child's 453 process group is killed. 454 455 If the 'timeout' is -1, this class behaves exactly like 456 'Executable'.""" 457 458 super(TimeoutExecutable, self).__init__() 459 self.__timeout = float(timeout)
460 461
462 - def _InitializeChild(self):
463 464 # Put the child into its own process group. This step is 465 # performed in both the parent and the child; therefore both 466 # processes can safely assume that the creation of the process 467 # group has taken place. 468 if self.__UseSeparateProcessGroupForChild(): 469 os.setpgid(0, 0) 470 471 super(TimeoutExecutable, self)._InitializeChild()
472 473
474 - def _HandleChild(self):
475 476 super(TimeoutExecutable, self)._HandleChild() 477 478 if self.__UseSeparateProcessGroupForChild(): 479 # Put the child into its own process group. This step is 480 # performed in both the parent and the child; therefore both 481 # processes can safely assume that the creation of the process 482 # group has taken place. 483 child_pid = self._GetChildPID() 484 try: 485 os.setpgid(child_pid, child_pid) 486 except: 487 # The call to setpgid may fail if the child has exited, 488 # or has already called 'exec'. In that case, we are 489 # guaranteed that the child has already put itself in the 490 # desired process group. 491 pass 492 493 # Create the monitoring process. 494 # 495 # If the monitoring process is in parent's process group and 496 # kills the child after waitpid has returned in the parent, we 497 # may end up trying to kill a process group other than the one 498 # that we intend to kill. Therefore, we put the monitoring 499 # process in the same process group as the child; that ensures 500 # that the process group will persist until the monitoring 501 # process kills it. 502 self.__monitor_pid = os.fork() 503 if self.__monitor_pid != 0: 504 # Make sure that the monitoring process is placed into the 505 # child's process group before the parent process calls 506 # 'waitpid'. In this way, we are guaranteed that the process 507 # group as the child 508 os.setpgid(self.__monitor_pid, child_pid) 509 else: 510 # Put the monitoring process into the child's process 511 # group. We know the process group still exists at 512 # this point because either (a) we are in the process 513 # group, or (b) the parent has not yet called waitpid. 514 os.setpgid(0, child_pid) 515 516 # Close all open file descriptors. They are not needed 517 # in the monitor process. Furthermore, when the parent 518 # closes the write end of the stdin pipe to the child, 519 # we do not want the pipe to remain open; leaving the 520 # pipe open in the monitor process might cause the child 521 # to block waiting for additional input. 522 try: 523 max_fds = os.sysconf("SC_OPEN_MAX") 524 except: 525 max_fds = 256 526 for fd in xrange(max_fds): 527 try: 528 os.close(fd) 529 except: 530 pass 531 532 try: 533 if self.__timeout >= 0: 534 # Give the child time to run. 535 time.sleep (self.__timeout) 536 # Kill all processes in the child process group. 537 os.kill(0, signal.SIGKILL) 538 else: 539 # This call to select will never terminate. 540 select.select ([], [], []) 541 finally: 542 # Exit. This code is in a finally clause so that 543 # we are guaranteed to get here no matter what. 544 os._exit(0) 545 elif self.__timeout >= 0 and sys.platform == "win32": 546 # Create a monitoring thread. 547 self.__monitor_thread = Thread(target = self.__Monitor) 548 self.__monitor_thread.start()
549 550
551 - def Run(self, arguments=[], environment = None, dir = None, 552 path = None):
553 554 if self.__UseSeparateProcessGroupForChild(): 555 self.__monitor_pid = None 556 elif self.__timeout >= 0 and sys.platform == "win32": 557 self.__monitor_thread = None 558 559 # Run the process. 560 try: 561 status = super(TimeoutExecutable, self).Run(arguments, 562 environment, 563 dir, 564 path) 565 finally: 566 if self.__UseSeparateProcessGroupForChild(): 567 # Clean up the monitoring program; it is no longer needed. 568 child_pid = self._GetChildPID() 569 if child_pid is not None: 570 os.kill(-child_pid, signal.SIGKILL) 571 if self.__monitor_pid is not None: 572 os.waitpid(self.__monitor_pid, 0) 573 elif self.__timeout >= 0 and sys.platform == "win32": 574 # Join the monitoring thread. 575 if self.__monitor_thread is not None: 576 self.__monitor_thread.join() 577 578 return status
579 580
582 """Returns true if the child wil be placed in its own process group. 583 584 returns -- True if the child will be placed in its own process 585 group. In that case, a separate monitoring process will also 586 be created.""" 587 588 if sys.platform == "win32": 589 # In Windows 2000 (or later), we should use "jobs" by 590 # analogy with UNIX process groups. However, that 591 # functionality is not (yet) provided by the Python Win32 592 # extensions. 593 return 0 594 595 return self.__timeout >= 0 or self.__timeout == -2
596 597 598 if sys.platform == "win32": 599
600 - def __Monitor(self):
601 """Kill the child if the timeout expires. 602 603 This function is run in the monitoring thread.""" 604 605 # The timeout may be expressed as a floating-point value 606 # on UNIX, but it must be an integer number of 607 # milliseconds when passed to WaitForSingleObject. 608 timeout = int(self.__timeout * 1000) 609 # Wait for the child process to terminate or for the 610 # timer to expire. 611 result = win32event.WaitForSingleObject(self._GetChildPID(), 612 timeout) 613 # If the timeout occurred, kill the child process. 614 if result == win32con.WAIT_TIMEOUT: 615 self.Kill()
616 617 618
619 -class RedirectedExecutable(TimeoutExecutable):
620 """A 'RedirectedExecutable' redirects the standard I/O streams.""" 621
622 - def _InitializeParent(self):
623 624 super(RedirectedExecutable, self)._InitializeParent() 625 626 # Create a pipe for each of the streams. 627 self._stdin_pipe = self._StdinPipe() 628 self._stdout_pipe = self._StdoutPipe() 629 self._stderr_pipe = self._StderrPipe() 630 631 # There has been no output yet. 632 self.stdout = "" 633 self.stderr = "" 634 635 # Under Windows, create a startupinfo structure that explains 636 # where the streams connected to the child should go. 637 if sys.platform == "win32": 638 # Create a startupinfo structure. 639 startupinfo = win32process.STARTUPINFO() 640 # Indicate that the child process should use the standard 641 # handles in startupinfo. 642 startupinfo.dwFlags = win32con.STARTF_USESTDHANDLES 643 644 # Attach each of the pipes to the appropriate entries in 645 # startupinfo. Also create a non-inheritable duplicate of the 646 # pipe end we will be using, and close the inheritable 647 # version. 648 if self._stdin_pipe: 649 startupinfo.hStdInput = self._stdin_pipe[0] 650 self._stdin_pipe[1] \ 651 = self.__UninheritableHandle(self._stdin_pipe[1]) 652 else: 653 startupinfo.hStdInput = win32file.INVALID_HANDLE_VALUE 654 if self._stdout_pipe: 655 startupinfo.hStdOutput = self._stdout_pipe[1] 656 self._stdout_pipe[0] \ 657 = self.__UninheritableHandle(self._stdout_pipe[0]) 658 else: 659 startupinfo.hStdOutput = win32file.INVALID_HANDLE_VALUE 660 if self._stderr_pipe: 661 startupinfo.hStdError = self._stderr_pipe[1] 662 self._stderr_pipe[0] \ 663 = self.__UninheritableHandle(self._stderr_pipe[0]) 664 elif self._stdout_pipe: 665 # If there's no stderr pipe -- but there is a stdout 666 # pipe -- redirect both stdout and stderr to the same 667 # pipe. 668 startupinfo.hStdError = self._stdout_pipe[1] 669 else: 670 startupinfo.hStdError = win32file.INVALID_HANDLE_VALUE 671 672 return startupinfo
673 674
675 - def _InitializeChild(self):
676 677 # Let the base class do any initialization required. 678 super(RedirectedExecutable, self)._InitializeChild() 679 680 # Redirect the standard I/O streams to the pipes. Python does 681 # not provide STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO, 682 # so we must use the file descriptor numbers directly. 683 if self._stdin_pipe: 684 os.dup2(self._stdin_pipe[0], 0) 685 else: 686 os.close(0) 687 688 if self._stdout_pipe: 689 os.dup2(self._stdout_pipe[1], 1) 690 else: 691 os.close(1) 692 693 if self._stderr_pipe: 694 os.dup2(self._stderr_pipe[1], 2) 695 elif self._stdout_pipe: 696 # If there's no stderr pipe -- but there is a stdout 697 # pipe -- redirect both stdout and stderr to the same 698 # pipe. 699 os.dup2(self._stdout_pipe[1], 2) 700 else: 701 os.close(2) 702 703 # Close the pipe fds. This should happen automatically when we 704 # exec the new process anyway, but it is polite to close fds as 705 # soon as possible. 706 if self._stdin_pipe: 707 os.close(self._stdin_pipe[0]) 708 os.close(self._stdin_pipe[1]) 709 if self._stdout_pipe: 710 os.close(self._stdout_pipe[0]) 711 os.close(self._stdout_pipe[1]) 712 if self._stderr_pipe: 713 os.close(self._stderr_pipe[0]) 714 os.close(self._stderr_pipe[1])
715 716
717 - def _HandleChild(self):
718 719 # Close the pipe ends that we do not need. 720 if self._stdin_pipe: 721 self._ClosePipeEnd(self._stdin_pipe[0]) 722 if self._stdout_pipe: 723 self._ClosePipeEnd(self._stdout_pipe[1]) 724 if self._stderr_pipe: 725 self._ClosePipeEnd(self._stderr_pipe[1]) 726 727 # The pipes created by 'RedirectedExecutable' must be closed 728 # before the monitor process (created by 'TimeoutExecutable') 729 # is created. Otherwise, if the child process dies, 'select' 730 # in the parent will not return if the monitor process may 731 # still have one of the file descriptors open. 732 super(RedirectedExecutable, self)._HandleChild()
733 734
735 - def _DoParent(self):
736 737 super(RedirectedExecutable, self)._DoParent() 738 739 # Process the various redirected streams until none of the 740 # streams remain open. 741 if sys.platform != "win32": 742 while 1: 743 # Prepare the lists of interesting descriptors. 744 read_fds = [] 745 write_fds = [] 746 if self._stdout_pipe: 747 read_fds.append(self._stdout_pipe[0]) 748 if self._stderr_pipe: 749 read_fds.append(self._stderr_pipe[0]) 750 if self._stdin_pipe: 751 write_fds.append(self._stdin_pipe[1]) 752 753 # If there are no longer any interesting descriptors, we are 754 # done. 755 if not read_fds and not write_fds: 756 return 757 758 # See which descriptors are ready for processing. 759 read_ready, write_ready \ 760 = select.select(read_fds, write_fds, [])[:2] 761 762 # Process them. 763 if self._stdout_pipe and self._stdout_pipe[0] in read_ready: 764 self._ReadStdout() 765 if self._stderr_pipe and self._stderr_pipe[0] in read_ready: 766 self._ReadStderr() 767 if self._stdin_pipe and self._stdin_pipe[1] in write_ready: 768 self._WriteStdin() 769 else: 770 # Under Windows, neither select, nor 771 # WaitForMultipleObjects, works on pipes. The only 772 # approach that is reliable under all versions of Windows 773 # is to use a separate thread for each handle. By 774 # converting the pipe ends from OS handles to file 775 # descriptors at this point, _ReadStdout, _ReadStderr, and 776 # _WriteStdin can use the same implementations under 777 # Windows that they do under UNIX. 778 779 if self._stdin_pipe: 780 h = self._stdin_pipe[1] 781 self._stdin_pipe[1] = msvcrt.open_osfhandle(h, 0) 782 h.Detach() 783 stdin_thread = Thread(target = self.__CallUntilNone, 784 args = (self._WriteStdin, 785 "_stdin_pipe")) 786 else: 787 stdin_thread = None 788 789 if self._stdout_pipe: 790 h = self._stdout_pipe[0] 791 self._stdout_pipe[0] = msvcrt.open_osfhandle(h, 0) 792 h.Detach() 793 stdout_thread = Thread(target = self.__CallUntilNone, 794 args = (self._ReadStdout, 795 "_stdout_pipe")) 796 else: 797 stdout_thread = None 798 799 if self._stderr_pipe: 800 h = self._stderr_pipe[0] 801 self._stderr_pipe[0] = msvcrt.open_osfhandle(h, 0) 802 h.Detach() 803 stderr_thread = Thread(target = self.__CallUntilNone, 804 args = (self._ReadStderr, 805 "_stderr_pipe")) 806 else: 807 stderr_thread = None 808 809 # Start the threads. 810 for t in stdin_thread, stdout_thread, stderr_thread: 811 if t: 812 t.start() 813 # Wait for them to finish. 814 for t in stdin_thread, stdout_thread, stderr_thread: 815 if t: 816 t.join()
817 818
819 - def _ReadStdout(self):
820 """Read from the standard output pipe.""" 821 822 # Read some data. 823 data = os.read(self._stdout_pipe[0], 64 * 1024) 824 825 if not data: 826 # If there is no new data, end-of-file has been reached. 827 os.close(self._stdout_pipe[0]) 828 self._stdout_pipe = None 829 else: 830 # Otherwise, add the data to the output we have already 831 # collected. 832 self.stdout += data
833 834
835 - def _ReadStderr(self):
836 """Read from the standard error pipe.""" 837 838 # Read some data. 839 data = os.read(self._stderr_pipe[0], 64 * 1024) 840 841 if not data: 842 # If there is no new data, end-of-file has been reached. 843 os.close(self._stderr_pipe[0]) 844 self._stderr_pipe = None 845 else: 846 # Otherwise, add the data to the output we have already 847 # collected. 848 self.stderr += data
849 850
851 - def _WriteStdin(self):
852 """Write to the standard input pipe. 853 854 This implementation writes no data and closes the pipe.""" 855 856 # Close the pipe. 857 os.close(self._stdin_pipe[1]) 858 self._stdin_pipe = None
859 860
861 - def _StdinPipe(self):
862 """Return a pipe to which to redirect the standard input. 863 864 returns -- A pipe, or 'None' if the standard input should be 865 closed in the child.""" 866 867 pipe = self._CreatePipe() 868 if sys.platform != "win32": 869 # Make sure that writing to the pipe will never result in 870 # deadlock. 871 fcntl.fcntl(pipe[1], fcntl.F_SETFL, 872 fcntl.fcntl(pipe[1], fcntl.F_GETFL) | os.O_NONBLOCK) 873 return pipe
874 875
876 - def _StdoutPipe(self):
877 """Return a pipe to which to redirect the standard output. 878 879 returns -- A pipe, or 'None' if the standard output should be 880 closed in the child.""" 881 882 return self._CreatePipe()
883 884
885 - def _StderrPipe(self):
886 """Return a pipe to which to redirect the standard input. 887 888 returns -- A pipe, or 'None'. If 'None' is returned, but 889 '_StdoutPipe' returns a pipe, then the standard error and 890 standard input will both be redirected to that pipe. However, 891 if '_StdoutPipe' also returns 'None', then the standard error 892 will be closed in the child.""" 893 894 return self._CreatePipe()
895 896
897 - def _ClosePipeEnd(self, fd):
898 """Close the file descriptor 'fd', which is one end of a pipe. 899 900 'fd' -- Under UNIX, a file descriptor. Under Windows, a 901 handle.""" 902 903 if sys.platform == "win32": 904 fd.Close() 905 else: 906 os.close(fd)
907 908
909 - def _CreatePipe(self):
910 """Return a new pipe. 911 912 returns -- A tuple (under UNIX) or list (under Windows) 913 consisting of the file descriptors (UNIX) or handles (Windows) 914 for the read end and write end of a new pipe. The pipe is 915 inheritable by child processes. On UNIX the fds will not be 916 inherited across 'exec'.""" 917 918 if sys.platform == "win32": 919 # Create a security descriptor so that we can mark the handles 920 # as inheritable. (A call to os.pipe under Windows 921 # returns handles that are not inheritable.) 922 sa = pywintypes.SECURITY_ATTRIBUTES() 923 sa.bInheritHandle = 1 924 # Transform the tuple returned into a list so that the 925 # individual elements can be altered. 926 r, w = win32pipe.CreatePipe(sa, 0) 927 return [r, w] 928 else: 929 pipe = os.pipe() 930 for fd in pipe: 931 qm.common.close_file_on_exec(fd) 932 return pipe
933 934
935 - def __CallUntilNone(self, f, attribute):
936 """Call 'f' until 'self.attribute' is 'None'. 937 938 'f' -- A callable. 939 940 'attribute' -- A string giving the name of an attribute.""" 941 942 while getattr(self, attribute) is not None: 943 f()
944 945
946 - def __UninheritableHandle(self, handle):
947 """Return a duplicate of a file handle that is not inheritable. 948 949 'handle' -- A file handle. 950 951 returns -- A new handle that is a non-inheritable duplicate of 952 the 'handle'. 953 954 This method should only be used under Windows.""" 955 956 assert sys.platform == "win32" 957 958 current_process = win32api.GetCurrentProcess() 959 return win32api.DuplicateHandle(current_process, 960 handle, 961 current_process, 962 0, 963 0, 964 win32con.DUPLICATE_SAME_ACCESS)
965 966 967
968 -class Filter(RedirectedExecutable):
969 """A 'FilterExecutable' feeds an input string to another proces. 970 971 The input string is provided to a child process via a pipe; the 972 standard output and standard error streams from the child process 973 are collected in the 'Filter'.""" 974
975 - def __init__(self, input, timeout = -1):
976 """Create a new 'Filter'. 977 978 'input' -- The string containing the input to provide to the 979 child process. 980 981 'timeout' -- As for 'TimeoutExecutable.__init__'.""" 982 983 super(Filter, self).__init__(timeout) 984 self.__input = input 985 self.__next = 0
986 987
988 - def _WriteStdin(self):
989 990 # If there's nothing more to write, stop. 991 if self.__next == len(self.__input): 992 super(Filter, self)._WriteStdin() 993 else: 994 # Write some data. 995 self.__next += os.write(self._stdin_pipe[1], 996 self.__input[self.__next 997 : self.__next + 64 * 1024])
998 999 1000 ######################################################################## 1001 # Variables 1002 ####################################################################### 1003 1004 __all__ = ["Executable", 1005 "TimeoutExecutable", 1006 "RedirectedExecutable", 1007 "Filter"] 1008