2019-08-05 15:28:04 +00:00
|
|
|
# pylint: disable=redefined-builtin
|
|
|
|
from contextlib import suppress, contextmanager
|
|
|
|
from os import O_NONBLOCK, O_RDONLY, O_WRONLY, open, close, write, read
|
2019-04-01 12:36:11 +00:00
|
|
|
from threading import Thread
|
2018-12-14 16:36:53 +00:00
|
|
|
|
2018-12-14 23:32:29 +00:00
|
|
|
from .terminate_process_on_failure import terminate_process_on_failure
|
2019-05-02 21:14:08 +00:00
|
|
|
from .deque import Deque
|
2018-12-14 23:32:29 +00:00
|
|
|
|
2018-12-14 16:36:53 +00:00
|
|
|
|
|
|
|
class PipeWriterThread(Thread):
|
2019-03-28 15:25:53 +00:00
|
|
|
def __init__(self, pipe_path, stop_event):
|
2019-05-07 15:16:43 +00:00
|
|
|
super().__init__(daemon=True)
|
2018-12-14 16:36:53 +00:00
|
|
|
self._pipe_path = pipe_path
|
2019-08-05 15:28:04 +00:00
|
|
|
self._write_fd, self._drain_fd = None, None
|
2019-03-28 15:25:53 +00:00
|
|
|
self._stop_event = stop_event
|
2019-05-02 21:14:08 +00:00
|
|
|
self._write_queue = Deque()
|
2018-12-14 16:36:53 +00:00
|
|
|
|
|
|
|
def write(self, message):
|
2019-05-02 21:14:08 +00:00
|
|
|
self._write_queue.push(message)
|
2018-12-14 16:36:53 +00:00
|
|
|
|
2018-12-14 23:32:29 +00:00
|
|
|
@terminate_process_on_failure
|
2018-12-14 16:36:53 +00:00
|
|
|
def run(self):
|
2019-08-05 15:28:04 +00:00
|
|
|
with self._open():
|
2019-05-02 21:07:32 +00:00
|
|
|
while True:
|
2019-05-02 21:14:08 +00:00
|
|
|
message = self._write_queue.pop()
|
2019-05-02 21:07:32 +00:00
|
|
|
if message is None:
|
|
|
|
self._stop_event.set()
|
|
|
|
break
|
2019-08-05 15:28:04 +00:00
|
|
|
write(self._write_fd, message + b'\n')
|
2019-05-02 21:07:32 +00:00
|
|
|
|
2019-08-05 15:28:04 +00:00
|
|
|
@contextmanager
|
2019-05-02 21:07:32 +00:00
|
|
|
def _open(self):
|
2019-08-05 15:28:04 +00:00
|
|
|
self._drain_fd = open(self._pipe_path, O_RDONLY | O_NONBLOCK)
|
|
|
|
self._write_fd = open(self._pipe_path, O_WRONLY)
|
|
|
|
yield
|
|
|
|
close(self._write_fd)
|
|
|
|
close(self._drain_fd)
|
2018-12-14 16:36:53 +00:00
|
|
|
|
|
|
|
def stop(self):
|
2019-05-03 20:00:23 +00:00
|
|
|
while self.is_alive():
|
|
|
|
self._unblock()
|
2018-12-14 16:36:53 +00:00
|
|
|
self.join()
|
2019-03-28 15:25:53 +00:00
|
|
|
|
2019-05-03 15:31:57 +00:00
|
|
|
def _unblock(self):
|
2019-08-05 15:28:04 +00:00
|
|
|
self._write_queue.push_front(None)
|
2019-08-06 14:18:56 +00:00
|
|
|
with suppress(OSError, TypeError):
|
2019-08-05 15:28:04 +00:00
|
|
|
while read(self._drain_fd, 65536):
|
|
|
|
pass
|