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