Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#30014: refactor poll-related classes #1035

Merged
merged 9 commits into from May 20, 2017
Merged

#30014: refactor poll-related classes #1035

merged 9 commits into from May 20, 2017

Conversation

@giampaolo
Copy link
Contributor

@giampaolo giampaolo commented Apr 7, 2017

Refactor poll-related classes so that poll(), epoll() and devpoll() share the same methods for register(), unregister(), close() and select().
This was inspired by http://bugs.python.org/issue30014 and serves as a strategy to avoid duplicating the implementation of modify() method.

UPDATE 2017-05-20: also use a single self._poller attribute for all classes instead of having self._poll, self._kqueue etc..

@Haypo

…poll() share the same methods for register(), unregister(), close() and select()
Lib/selectors.py Outdated
"""Poll-based selector."""
def __init__(self):
super().__init__()
self._poller = self._poller()
Copy link
Contributor

@cf-natali cf-natali Apr 29, 2017

This looks strange: I assume that self._poller is the poller class (e.g. select, poll, etc).
It's used here but not defined in this base class: maybe make it an abstract property to force its definition?
Also, assigning
self._poller = self._poller() is very confusing: you're reusing the same member for the instance and the class.
Maybe use poller_cls, or poller_type for the type of the poller, to avoid confusion with the instance?

Copy link
Contributor Author

@giampaolo giampaolo May 1, 2017

Yes, the idea is to have a _poller attribute which can be referenced by all 3 classes. Actually I think it'd be cool to do the same also for select and kqueue.
And yes, it's probably better to also have _poller_cls.
I don't have a strong opinion about abstract properties but it's up to you.

Copy link
Contributor Author

@giampaolo giampaolo May 1, 2017

How would you feel about having a _selector attribute for all classes (also kqueue and select)?

Copy link
Contributor

@cf-natali cf-natali May 20, 2017

Sounds great.

Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

Done

Lib/selectors.py Outdated
poller_events |= self._EVENT_WRITE
try:
self._poller.register(key.fd, poller_events)
except BaseException:
Copy link
Contributor

@cf-natali cf-natali Apr 29, 2017

I think catching BaseException is discouraged, shouldn't it be Exception?

Copy link
Contributor Author

@giampaolo giampaolo May 1, 2017

yes, I think it should; I think I copied it from the previous code

Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

Done.

Lib/selectors.py Outdated
key = super().unregister(fileobj)
try:
self._poller.unregister(key.fd)
except OSError:
Copy link
Contributor

@cf-natali cf-natali Apr 29, 2017

Why catch OSError here and BaseException in register()?

Copy link
Contributor Author

@giampaolo giampaolo May 1, 2017

I copied it from the previous code:

except OSError:

...although the original code did that for epoll only wheres with this it's applied to all 3 selectors. Not sure if it matters. Probably not.
In general I think it would make sense to always catch OSError (also in kqueue).

Copy link
Contributor

@cf-natali cf-natali May 20, 2017

Agreed, let's catch OSError everywhere.

Lib/selectors.py Outdated
self._devpoll = select.devpoll()
_poller = select.devpoll
_EVENT_READ = select.POLLIN
_EVENT_WRITE = select.POLLOUT

def fileno(self):
return self._devpoll.fileno()
Copy link
Contributor

@cf-natali cf-natali Apr 29, 2017

This can't work, self._devpoll has been replaced by self._poller.

Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

Good catch. Fixed.

Lib/selectors.py Outdated
ready.append((key, events & key.events))
return ready
def close(self):
if hasattr(self._poller, "close"):
Copy link
Contributor

@cf-natali cf-natali Apr 29, 2017

Doing such a hasattr() is a bit naughty: why not instead override close() in EpollSelector and DevPollSelector to close the underlying FD?

If you want to maximize code reuse, maybe we could add a _FDBasedSelector - common to al implementations using a file descriptor - in which you could define close() and fileno()?

Copy link
Contributor Author

@giampaolo giampaolo May 1, 2017

Fine with me.

Copy link
Contributor

@cf-natali cf-natali May 20, 2017

Good.

Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

I overrode close() in EpollSelector and DevPollSelector to close the underlying FD as per your suggestion.

Copy link
Contributor

@cf-natali cf-natali left a comment

Sorry for the delay, didn't see this message.

With the proposed changes, sounds great!

Copy link
Contributor Author

@giampaolo giampaolo left a comment

Sorry for the delay, didn't see this message.

No problem. ;-)
OK, I think it's ready.

Lib/selectors.py Outdated
"""Poll-based selector."""
def __init__(self):
super().__init__()
self._poller = self._poller()
Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

Done

Lib/selectors.py Outdated
poller_events |= self._EVENT_WRITE
try:
self._poller.register(key.fd, poller_events)
except BaseException:
Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

Done.

Lib/selectors.py Outdated
ready.append((key, events & key.events))
return ready
def close(self):
if hasattr(self._poller, "close"):
Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

I overrode close() in EpollSelector and DevPollSelector to close the underlying FD as per your suggestion.

Lib/selectors.py Outdated
self._devpoll = select.devpoll()
_poller = select.devpoll
_EVENT_READ = select.POLLIN
_EVENT_WRITE = select.POLLOUT

def fileno(self):
return self._devpoll.fileno()
Copy link
Contributor Author

@giampaolo giampaolo May 20, 2017

Good catch. Fixed.

Copy link
Contributor

@cf-natali cf-natali left a comment

Great!

@giampaolo giampaolo merged commit 62c7d90 into master May 20, 2017
3 of 4 checks passed
@giampaolo giampaolo deleted the selectors-refactoring branch May 20, 2017
@giampaolo
Copy link
Contributor Author

@giampaolo giampaolo commented May 20, 2017

Cool. Merged. I'll submit a PR for a faster modify() soon.

@vstinner
Copy link
Member

@vstinner vstinner commented May 20, 2017

@giampaolo
Copy link
Contributor Author

@giampaolo giampaolo commented May 20, 2017

Thanks Victor. ;)

mlouielu added a commit to mlouielu/cpython that referenced this issue Jun 15, 2017
* #30014: refactor poll-related classes so that poll(), epoll() and devpoll() share the same methods for register(), unregister(), close() and select()

* remove unused attribute

* use specific class attributes instead of select.* constants

* have all classes except SelectSelector a _selector attribute

* BaseException -> Exception

* be explicit in defining a close() method only for selectors which have it

* fix AttributeError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants