| 823 | self._stopped_serving.add(obj) |
| 824 | |
| 825 | def close(self): |
| 826 | if self._iocp is None: |
| 827 | # already closed |
| 828 | return |
| 829 | |
| 830 | # Cancel remaining registered operations. |
| 831 | for fut, ov, obj, callback in list(self._cache.values()): |
| 832 | if fut.cancelled(): |
| 833 | # Nothing to do with cancelled futures |
| 834 | pass |
| 835 | elif isinstance(fut, _WaitCancelFuture): |
| 836 | # _WaitCancelFuture must not be cancelled |
| 837 | pass |
| 838 | else: |
| 839 | try: |
| 840 | fut.cancel() |
| 841 | except OSError as exc: |
| 842 | if self._loop is not None: |
| 843 | context = { |
| 844 | 'message': 'Cancelling a future failed', |
| 845 | 'exception': exc, |
| 846 | 'future': fut, |
| 847 | } |
| 848 | if fut._source_traceback: |
| 849 | context['source_traceback'] = fut._source_traceback |
| 850 | self._loop.call_exception_handler(context) |
| 851 | |
| 852 | # Wait until all cancelled overlapped complete: don't exit with running |
| 853 | # overlapped to prevent a crash. Display progress every second if the |
| 854 | # loop is still running. |
| 855 | msg_update = 1.0 |
| 856 | start_time = time.monotonic() |
| 857 | next_msg = start_time + msg_update |
| 858 | while self._cache: |
| 859 | if next_msg <= time.monotonic(): |
| 860 | logger.debug('%r is running after closing for %.1f seconds', |
| 861 | self, time.monotonic() - start_time) |
| 862 | next_msg = time.monotonic() + msg_update |
| 863 | |
| 864 | # handle a few events, or timeout |
| 865 | self._poll(msg_update) |
| 866 | |
| 867 | self._results = [] |
| 868 | |
| 869 | _winapi.CloseHandle(self._iocp) |
| 870 | self._iocp = None |
| 871 | |
| 872 | def __del__(self): |
| 873 | self.close() |