diff --git a/quamash/__init__.py b/quamash/__init__.py index 927fccd..fb883a3 100644 --- a/quamash/__init__.py +++ b/quamash/__init__.py @@ -310,6 +310,11 @@ def close(self): The loop cannot be restarted after it has been closed. """ + if self.is_running(): + raise RuntimeError("Cannot close a running event loop") + if self.is_closed(): + return + self._logger.debug('Closing event loop...') if self.__default_executor is not None: self.__default_executor.shutdown() @@ -376,6 +381,8 @@ def time(self): def add_reader(self, fd, callback, *args): """Register a callback for when a file descriptor is ready for reading.""" + self._check_closed() + try: existing = self._read_notifiers[fd] except KeyError: @@ -397,6 +404,10 @@ def add_reader(self, fd, callback, *args): def remove_reader(self, fd): """Remove reader callback.""" + + if self.is_closed(): + return + self._logger.debug('Removing reader callback for file descriptor {}'.format(fd)) try: notifier = self._read_notifiers.pop(fd) @@ -408,6 +419,7 @@ def remove_reader(self, fd): def add_writer(self, fd, callback, *args): """Register a callback for when a file descriptor is ready for writing.""" + self._check_closed() try: existing = self._write_notifiers[fd] except KeyError: @@ -429,6 +441,10 @@ def add_writer(self, fd, callback, *args): def remove_writer(self, fd): """Remove writer callback.""" + + if self.is_closed(): + return + self._logger.debug('Removing writer callback for file descriptor {}'.format(fd)) try: notifier = self._write_notifiers.pop(fd) diff --git a/tests/test_qeventloop.py b/tests/test_qeventloop.py index 84a74a3..3adafc7 100644 --- a/tests/test_qeventloop.py +++ b/tests/test_qeventloop.py @@ -399,6 +399,37 @@ def can_read(): assert got_msg is None, 'Should not have received a read notification' +def test_remove_reader_after_closing(loop, sock_pair): + """Verify that we can remove a reader callback from an event loop.""" + client_sock, srv_sock = sock_pair + + loop.add_reader(srv_sock.fileno(), lambda: None) + loop.close() + loop.remove_reader(srv_sock.fileno()) + +def test_remove_writer_after_closing(loop, sock_pair): + """Verify that we can remove a reader callback from an event loop.""" + client_sock, srv_sock = sock_pair + + loop.add_writer(client_sock.fileno(), lambda: None) + loop.close() + loop.remove_writer(client_sock.fileno()) + +def test_add_reader_after_closing(loop, sock_pair): + """Verify that we can remove a reader callback from an event loop.""" + client_sock, srv_sock = sock_pair + + loop.close() + with pytest.raises(RuntimeError): + loop.add_reader(srv_sock.fileno(), lambda:None) + +def test_add_writer_after_closing(loop, sock_pair): + """Verify that we can remove a reader callback from an event loop.""" + client_sock, srv_sock = sock_pair + + loop.close() + with pytest.raises(RuntimeError): + loop.add_writer(client_sock.fileno(), lambda:None) def test_can_add_writer(loop, sock_pair): """Verify that we can add a writer callback to an event loop."""