(self, real_loop: asyncio.AbstractEventLoop)
| 473 | _closed = False |
| 474 | |
| 475 | def __init__(self, real_loop: asyncio.AbstractEventLoop) -> None: |
| 476 | self._main_thread_ctx = contextvars.copy_context() |
| 477 | |
| 478 | self._real_loop = real_loop |
| 479 | |
| 480 | self._select_cond = threading.Condition() |
| 481 | self._select_args: Optional[ |
| 482 | Tuple[List[_FileDescriptorLike], List[_FileDescriptorLike]] |
| 483 | ] = None |
| 484 | self._closing_selector = False |
| 485 | self._thread: Optional[threading.Thread] = None |
| 486 | self._thread_manager_handle = self._thread_manager() |
| 487 | |
| 488 | async def thread_manager_anext() -> None: |
| 489 | # the anext builtin wasn't added until 3.10. We just need to iterate |
| 490 | # this generator one step. |
| 491 | await self._thread_manager_handle.__anext__() |
| 492 | |
| 493 | # When the loop starts, start the thread. Not too soon because we can't |
| 494 | # clean up if we get to this point but the event loop is closed without |
| 495 | # starting. |
| 496 | self._real_loop.call_soon( |
| 497 | lambda: self._real_loop.create_task(thread_manager_anext()), |
| 498 | context=self._main_thread_ctx, |
| 499 | ) |
| 500 | |
| 501 | self._readers: Dict[_FileDescriptorLike, Callable] = {} |
| 502 | self._writers: Dict[_FileDescriptorLike, Callable] = {} |
| 503 | |
| 504 | # Writing to _waker_w will wake up the selector thread, which |
| 505 | # watches for _waker_r to be readable. |
| 506 | self._waker_r, self._waker_w = socket.socketpair() |
| 507 | self._waker_r.setblocking(False) |
| 508 | self._waker_w.setblocking(False) |
| 509 | _selector_loops.add(self) |
| 510 | self.add_reader(self._waker_r, self._consume_waker) |
| 511 | |
| 512 | def close(self) -> None: |
| 513 | if self._closed: |
no test coverage detected