Revision 29da446a

b/daemons/import-export
399 399
  return GetBashCommand(buf.getvalue())
400 400

  
401 401

  
402
def ProcessChildIO(child, socat_stderr_read, status_file, child_logger,
402
def ProcessChildIO(child, socat_stderr_read_fd, status_file, child_logger,
403 403
                   signal_notify, signal_handler):
404 404
  """Handles the child processes' output.
405 405

  
406 406
  """
407
  poller = select.poll()
407
  assert not (signal_handler.signum - set([signal.SIGTERM, signal.SIGINT])), \
408
         "Other signals are not handled in this function"
409

  
410
  # Buffer size 0 is important, otherwise .read() with a specified length
411
  # might buffer data while poll(2) won't mark its file descriptor as
412
  # readable again.
413
  socat_stderr_read = os.fdopen(socat_stderr_read_fd, "r", 0)
408 414

  
409 415
  script_stderr_lines = utils.LineSplitter(ProcessOutput, status_file,
410 416
                                           child_logger, False)
......
418 424
        signal_notify.fileno(): (signal_notify, None),
419 425
        }
420 426

  
427
      poller = select.poll()
421 428
      for fd in fdmap:
422 429
        utils.SetNonblockFlag(fd, True)
423 430
        poller.register(fd, select.POLLIN)
......
599 606
      # Pipe to receive socat's stderr output
600 607
      (socat_stderr_read_fd, socat_stderr_write_fd) = os.pipe()
601 608

  
602
      # Pipe to notify on signals
603
      (signal_notify_read_fd, signal_notify_write_fd) = os.pipe()
604

  
605
      # Configure signal module's notifier
606
      try:
607
        # This is only supported in Python 2.5 and above (some distributions
608
        # backported it to Python 2.4)
609
        set_wakeup_fd_fn = signal.set_wakeup_fd
610
      except AttributeError:
611
        pass
612
      else:
613
        set_wakeup_fd_fn(signal_notify_write_fd)
614

  
615
      # Buffer size 0 is important, otherwise .read() with a specified length
616
      # might buffer data while poll(2) won't mark its file descriptor as
617
      # readable again.
618
      socat_stderr_read = os.fdopen(socat_stderr_read_fd, "r", 0)
619
      signal_notify_read = os.fdopen(signal_notify_read_fd, "r", 0)
620

  
621 609
      # Get child process command
622 610
      cmd = GetCommand(mode, socat_stderr_write_fd)
623 611

  
......
626 614
      # Start child process
627 615
      child = ChildProcess(cmd, [socat_stderr_write_fd])
628 616
      try:
629
        # Forward signals to child process
630 617
        def _ForwardSignal(signum, _):
631
          # Wake up poll(2)
632
          os.write(signal_notify_write_fd, "\0")
618
          """Forwards signals to child process.
633 619

  
634
          # Send signal to child
620
          """
635 621
          child.Kill(signum)
636 622

  
637
        # TODO: There is a race condition between starting the child and
638
        # handling the signals here. While there might be a way to work around
639
        # it by registering the handlers before starting the child and
640
        # deferring sent signals until the child is available, doing so can be
641
        # complicated.
642
        signal_handler = utils.SignalHandler([signal.SIGTERM, signal.SIGINT],
643
                                             handler_fn=_ForwardSignal)
623
        signal_wakeup = utils.SignalWakeupFd()
644 624
        try:
645
          # Close child's side
646
          utils.RetryOnSignal(os.close, socat_stderr_write_fd)
647

  
648
          if ProcessChildIO(child, socat_stderr_read, status_file, child_logger,
649
                            signal_notify_read, signal_handler):
650
            # The child closed all its file descriptors and there was no signal
651
            # TODO: Implement timeout instead of waiting indefinitely
652
            utils.RetryOnSignal(child.wait)
625
          # TODO: There is a race condition between starting the child and
626
          # handling the signals here. While there might be a way to work around
627
          # it by registering the handlers before starting the child and
628
          # deferring sent signals until the child is available, doing so can be
629
          # complicated.
630
          signal_handler = utils.SignalHandler([signal.SIGTERM, signal.SIGINT],
631
                                               handler_fn=_ForwardSignal,
632
                                               wakeup=signal_wakeup)
633
          try:
634
            # Close child's side
635
            utils.RetryOnSignal(os.close, socat_stderr_write_fd)
636

  
637
            if ProcessChildIO(child, socat_stderr_read_fd, status_file,
638
                              child_logger, signal_wakeup,
639
                              signal_handler):
640
              # The child closed all its file descriptors and there was no
641
              # signal
642
              # TODO: Implement timeout instead of waiting indefinitely
643
              utils.RetryOnSignal(child.wait)
644
          finally:
645
            signal_handler.Reset()
653 646
        finally:
654
          signal_handler.Reset()
647
          signal_wakeup.Reset()
655 648
      finally:
656 649
        child.ForceQuit()
657 650

  

Also available in: Unified diff