Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Doc/library/selectors.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -102,14 +102,15 @@ constants below:
:class:`BaseSelector` and its concrete implementations support the
:term:`context manager` protocol.

.. abstractmethod:: register(fileobj, events, data=None)
.. abstractmethod:: register(fileobj, events, data=None, *, extra_events=0)

Register a file object for selection, monitoring it for I/O events.

*fileobj* is the file object to monitor. It may either be an integer
file descriptor or an object with a ``fileno()`` method.
*events* is a bitwise mask of events to monitor.
*data* is an opaque object.
*extra_events* is the extra events people want to use. All of the events are defined in :mod:`select` module.

This returns a new :class:`SelectorKey` instance, or raises a
:exc:`ValueError` in case of invalid event mask or file descriptor, or
Expand All@@ -127,12 +128,12 @@ constants below:
:exc:`ValueError` if *fileobj* is invalid (e.g. it has no ``fileno()``
method or its ``fileno()`` method has an invalid return value).

.. method:: modify(fileobj, events, data=None)
.. method:: modify(fileobj, events, data=None, *, extra_events=0)

Change a registered file object's monitored events or attached data.

This is equivalent to :meth:`BaseSelector.unregister(fileobj)` followed
by :meth:`BaseSelector.register(fileobj, events, data)`, except that it
by :meth:`BaseSelector.register(fileobj, events, data, *, extra_events=0)`, except that it
can be implemented more efficiently.

This returns a new :class:`SelectorKey` instance, or raises a
Expand Down
24 changes: 14 additions & 10 deletions Lib/selectors.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -93,13 +93,14 @@ class BaseSelector(metaclass=ABCMeta):
"""

@abstractmethod
def register(self, fileobj, events, data=None):
def register(self, fileobj, events, data=None, *, extra_events=0):
"""Register a file object.

Parameters:
fileobj -- file object or file descriptor
events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
data -- attached data
extra_events -- extra events which is supported in select module

Returns:
SelectorKey instance
Expand DownExpand Up@@ -134,7 +135,7 @@ def unregister(self, fileobj):
"""
raise NotImplementedError

def modify(self, fileobj, events, data=None):
def modify(self, fileobj, events, data=None, *, extra_events=0):
"""Change a registered file object monitored events or attached data.

Parameters:
Expand All@@ -149,7 +150,7 @@ def modify(self, fileobj, events, data=None):
Anything that unregister() or register() raises
"""
self.unregister(fileobj)
return self.register(fileobj, events, data)
return self.register(fileobj, events, data, extra_events=extra_events)

@abstractmethod
def select(self, timeout=None):
Expand DownExpand Up@@ -231,7 +232,7 @@ def _fileobj_lookup(self, fileobj):
# Raise ValueError after all.
raise

def register(self, fileobj, events, data=None):
def register(self, fileobj, events, data=None, *, extra_events=0):
if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
raise ValueError("Invalid events: {!r}".format(events))

Expand All@@ -251,14 +252,14 @@ def unregister(self, fileobj):
raise KeyError("{!r} is not registered".format(fileobj)) from None
return key

def modify(self, fileobj, events, data=None):
def modify(self, fileobj, events, data=None, *, extra_events=0):
try:
key = self._fd_to_key[self._fileobj_lookup(fileobj)]
except KeyError:
raise KeyError("{!r} is not registered".format(fileobj)) from None
if events != key.events:
self.unregister(fileobj)
key = self.register(fileobj, events, data)
key = self.register(fileobj, events, data, extra_events=extra_events)
elif data != key.data:
# Use a shortcut to update the data.
key = key._replace(data=data)
Expand DownExpand Up@@ -295,7 +296,7 @@ def __init__(self):
self._readers = set()
self._writers = set()

def register(self, fileobj, events, data=None):
def register(self, fileobj, events, data=None, *, extra_events=0):
key = super().register(fileobj, events, data)
if events & EVENT_READ:
self._readers.add(key.fd)
Expand DownExpand Up@@ -348,13 +349,15 @@ def __init__(self):
super().__init__()
self._selector = self._selector_cls()

def register(self, fileobj, events, data=None):
def register(self, fileobj, events, data=None, *, extra_events=0):
key = super().register(fileobj, events, data)
poller_events = 0
if events & EVENT_READ:
poller_events |= self._EVENT_READ
if events & EVENT_WRITE:
poller_events |= self._EVENT_WRITE
# allow user use events defiend in select
poller_events |= extra_events
try:
self._selector.register(key.fd, poller_events)
except:
Expand All@@ -372,7 +375,7 @@ def unregister(self, fileobj):
pass
return key

def modify(self, fileobj, events, data=None):
def modify(self, fileobj, events, data=None, *, extra_events=0):
try:
key = self._fd_to_key[self._fileobj_lookup(fileobj)]
except KeyError:
Expand All@@ -385,6 +388,7 @@ def modify(self, fileobj, events, data=None):
selector_events |= self._EVENT_READ
if events & EVENT_WRITE:
selector_events |= self._EVENT_WRITE
selector_events |= extra_events
try:
self._selector.modify(key.fd, selector_events)
except:
Expand DownExpand Up@@ -513,7 +517,7 @@ def __init__(self):
def fileno(self):
return self._selector.fileno()

def register(self, fileobj, events, data=None):
def register(self, fileobj, events, data=None, *, extra_events=0):
key = super().register(fileobj, events, data)
try:
if events & EVENT_READ:
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/test_selectors.py
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
import errno
import os
import random
import select
import selectors
import signal
import socket
Expand DownExpand Up@@ -524,6 +525,15 @@ def test_register_file(self):
with self.assertRaises(KeyError):
s.get_key(f)

def test_register(self):
super().test_register()
s = self.SELECTOR()
if hasattr("select", 'EPOLLEXCLUSIVE'):
key = s.register(wr, selectors.EVENT_WRITE, 'data', extra_events=select.EPOLLEXCLUSIVE)
self.assertEqual(key.fileobj, wr)
self.assertEqual(key.fd, wr.fileno())
self.assertEqual(key.events, select.EPOLLEXCLUSIVE)
self.assertEqual(key.data, "data")

@unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
"Test needs selectors.KqueueSelector)")
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
selector.EpollSelector: add new parameter to support extra_events