(self)
| 525 | self._closed = True |
| 526 | |
| 527 | async def _thread_manager(self) -> typing.AsyncGenerator[None, None]: |
| 528 | # Create a thread to run the select system call. We manage this thread |
| 529 | # manually so we can trigger a clean shutdown from an atexit hook. Note |
| 530 | # that due to the order of operations at shutdown, only daemon threads |
| 531 | # can be shut down in this way (non-daemon threads would require the |
| 532 | # introduction of a new hook: https://bugs.python.org/issue41962) |
| 533 | self._thread = threading.Thread( |
| 534 | name="Tornado selector", |
| 535 | daemon=True, |
| 536 | target=self._run_select, |
| 537 | ) |
| 538 | self._thread.start() |
| 539 | self._start_select() |
| 540 | try: |
| 541 | # The presense of this yield statement means that this coroutine |
| 542 | # is actually an asynchronous generator, which has a special |
| 543 | # shutdown protocol. We wait at this yield point until the |
| 544 | # event loop's shutdown_asyncgens method is called, at which point |
| 545 | # we will get a GeneratorExit exception and can shut down the |
| 546 | # selector thread. |
| 547 | yield |
| 548 | except GeneratorExit: |
| 549 | self.close() |
| 550 | raise |
| 551 | |
| 552 | def _wake_selector(self) -> None: |
| 553 | if self._closed: |
no test coverage detected