|
1 | 1 | """Selector eventloop for Unix with signal handling.""" |
2 | 2 |
|
3 | | -import collections |
4 | 3 | import errno |
5 | 4 | import fcntl |
6 | 5 | import os |
|
11 | 10 | import sys |
12 | 11 |
|
13 | 12 |
|
| 13 | +from . import base_subprocess |
14 | 14 | from . import constants |
15 | 15 | from . import events |
16 | 16 | from . import protocols |
@@ -406,159 +406,20 @@ def _call_connection_lost(self, exc): |
406 | 406 | self._loop = None |
407 | 407 |
|
408 | 408 |
|
409 | | -class _UnixWriteSubprocessPipeProto(protocols.BaseProtocol): |
410 | | - pipe = None |
| 409 | +class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport): |
411 | 410 |
|
412 | | - def __init__(self, proc, fd): |
413 | | - self.proc = proc |
414 | | - self.fd = fd |
415 | | - self.connected = False |
416 | | - self.disconnected = False |
417 | | - proc._pipes[fd] = self |
418 | | - |
419 | | - def connection_made(self, transport): |
420 | | - self.connected = True |
421 | | - self.pipe = transport |
422 | | - self.proc._try_connected() |
423 | | - |
424 | | - def connection_lost(self, exc): |
425 | | - self.disconnected = True |
426 | | - self.proc._pipe_connection_lost(self.fd, exc) |
427 | | - |
428 | | - |
429 | | -class _UnixReadSubprocessPipeProto(_UnixWriteSubprocessPipeProto, |
430 | | - protocols.Protocol): |
431 | | - |
432 | | - def data_received(self, data): |
433 | | - self.proc._pipe_data_received(self.fd, data) |
434 | | - |
435 | | - def eof_received(self): |
436 | | - pass |
437 | | - |
438 | | - |
439 | | -class _UnixSubprocessTransport(transports.SubprocessTransport): |
440 | | - |
441 | | - def __init__(self, loop, protocol, args, shell, |
442 | | - stdin, stdout, stderr, bufsize, |
443 | | - extra=None, **kwargs): |
444 | | - super().__init__(extra) |
445 | | - self._protocol = protocol |
446 | | - self._loop = loop |
447 | | - |
448 | | - self._pipes = {} |
| 411 | + def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): |
449 | 412 | stdin_w = None |
450 | 413 | if stdin == subprocess.PIPE: |
451 | | - self._pipes[STDIN] = None |
452 | 414 | # Use a socket pair for stdin, since not all platforms |
453 | 415 | # support selecting read events on the write end of a |
454 | 416 | # socket (which we use in order to detect closing of the |
455 | 417 | # other end). Notably this is needed on AIX, and works |
456 | 418 | # just fine on other platforms. |
457 | 419 | stdin, stdin_w = self._loop._socketpair() |
458 | | - if stdout == subprocess.PIPE: |
459 | | - self._pipes[STDOUT] = None |
460 | | - if stderr == subprocess.PIPE: |
461 | | - self._pipes[STDERR] = None |
462 | | - self._pending_calls = collections.deque() |
463 | | - self._finished = False |
464 | | - self._returncode = None |
465 | | - |
466 | 420 | self._proc = subprocess.Popen( |
467 | 421 | args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr, |
468 | 422 | universal_newlines=False, bufsize=bufsize, **kwargs) |
469 | 423 | if stdin_w is not None: |
470 | 424 | stdin.close() |
471 | 425 | self._proc.stdin = open(stdin_w.detach(), 'rb', buffering=bufsize) |
472 | | - self._extra['subprocess'] = self._proc |
473 | | - |
474 | | - def close(self): |
475 | | - for proto in self._pipes.values(): |
476 | | - proto.pipe.close() |
477 | | - if self._returncode is None: |
478 | | - self.terminate() |
479 | | - |
480 | | - def get_pid(self): |
481 | | - return self._proc.pid |
482 | | - |
483 | | - def get_returncode(self): |
484 | | - return self._returncode |
485 | | - |
486 | | - def get_pipe_transport(self, fd): |
487 | | - if fd in self._pipes: |
488 | | - return self._pipes[fd].pipe |
489 | | - else: |
490 | | - return None |
491 | | - |
492 | | - def send_signal(self, signal): |
493 | | - self._proc.send_signal(signal) |
494 | | - |
495 | | - def terminate(self): |
496 | | - self._proc.terminate() |
497 | | - |
498 | | - def kill(self): |
499 | | - self._proc.kill() |
500 | | - |
501 | | - @tasks.coroutine |
502 | | - def _post_init(self): |
503 | | - proc = self._proc |
504 | | - loop = self._loop |
505 | | - if proc.stdin is not None: |
506 | | - transp, proto = yield from loop.connect_write_pipe( |
507 | | - lambda: _UnixWriteSubprocessPipeProto(self, STDIN), |
508 | | - proc.stdin) |
509 | | - if proc.stdout is not None: |
510 | | - transp, proto = yield from loop.connect_read_pipe( |
511 | | - lambda: _UnixReadSubprocessPipeProto(self, STDOUT), |
512 | | - proc.stdout) |
513 | | - if proc.stderr is not None: |
514 | | - transp, proto = yield from loop.connect_read_pipe( |
515 | | - lambda: _UnixReadSubprocessPipeProto(self, STDERR), |
516 | | - proc.stderr) |
517 | | - if not self._pipes: |
518 | | - self._try_connected() |
519 | | - |
520 | | - def _call(self, cb, *data): |
521 | | - if self._pending_calls is not None: |
522 | | - self._pending_calls.append((cb, data)) |
523 | | - else: |
524 | | - self._loop.call_soon(cb, *data) |
525 | | - |
526 | | - def _try_connected(self): |
527 | | - assert self._pending_calls is not None |
528 | | - if all(p is not None and p.connected for p in self._pipes.values()): |
529 | | - self._loop.call_soon(self._protocol.connection_made, self) |
530 | | - for callback, data in self._pending_calls: |
531 | | - self._loop.call_soon(callback, *data) |
532 | | - self._pending_calls = None |
533 | | - |
534 | | - def _pipe_connection_lost(self, fd, exc): |
535 | | - self._call(self._protocol.pipe_connection_lost, fd, exc) |
536 | | - self._try_finish() |
537 | | - |
538 | | - def _pipe_data_received(self, fd, data): |
539 | | - self._call(self._protocol.pipe_data_received, fd, data) |
540 | | - |
541 | | - def _process_exited(self, returncode): |
542 | | - assert returncode is not None, returncode |
543 | | - assert self._returncode is None, self._returncode |
544 | | - self._returncode = returncode |
545 | | - self._loop._subprocess_closed(self) |
546 | | - self._call(self._protocol.process_exited) |
547 | | - self._try_finish() |
548 | | - |
549 | | - def _try_finish(self): |
550 | | - assert not self._finished |
551 | | - if self._returncode is None: |
552 | | - return |
553 | | - if all(p is not None and p.disconnected |
554 | | - for p in self._pipes.values()): |
555 | | - self._finished = True |
556 | | - self._loop.call_soon(self._call_connection_lost, None) |
557 | | - |
558 | | - def _call_connection_lost(self, exc): |
559 | | - try: |
560 | | - self._protocol.connection_lost(exc) |
561 | | - finally: |
562 | | - self._proc = None |
563 | | - self._protocol = None |
564 | | - self._loop = None |
0 commit comments