Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d8b9ae6

Browse files
committed
Issue #6397: Support '/dev/poll' polling objects in select module, under Solaris & derivatives.
1 parent d5d4406 commit d8b9ae6

7 files changed

Lines changed: 561 additions & 7 deletions

File tree

Doc/library/select.rst

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77

88
This module provides access to the :c:func:`select` and :c:func:`poll` functions
9-
available in most operating systems, :c:func:`epoll` available on Linux 2.5+ and
9+
available in most operating systems, :c:func:`devpoll` available on
10+
Solaris and derivatives, :c:func:`epoll` available on Linux 2.5+ and
1011
:c:func:`kqueue` available on most BSD.
1112
Note that on Windows, it only works for sockets; on other operating systems,
1213
it also works for other file types (in particular, on Unix, it works on pipes).
@@ -24,6 +25,19 @@ The module defines the following:
2425
Following :pep:`3151`, this class was made an alias of :exc:`OSError`.
2526

2627

28+
.. function:: devpoll()
29+
(Only supported on Solaris and derivatives.) Returns a ``/dev/poll``
30+
polling object; see section :ref:`devpoll-objects` below for the
31+
methods supported by devpoll objects.
32+
33+
:c:func:`devpoll` objects are linked to the number of file
34+
descriptors allowed at the time of instantiation. If your program
35+
reduces this value, :c:func:`devpoll` will fail. If your program
36+
increases this value, c:func:`devpoll` may return an
37+
incomplete list of active file descriptors.
38+
39+
.. versionadded:: 3.3
40+
2741
.. function:: epoll(sizehint=-1)
2842

2943
(Only supported on Linux 2.5.44 and newer.) Returns an edge polling object,
@@ -107,6 +121,74 @@ The module defines the following:
107121
.. versionadded:: 3.2
108122

109123

124+
.. _devpoll-objects:
125+
126+
``/dev/poll`` Polling Objects
127+
----------------------------------------------
128+
129+
http://developers.sun.com/solaris/articles/using_devpoll.html
130+
http://developers.sun.com/solaris/articles/polling_efficient.html
131+
132+
Solaris and derivatives have ``/dev/poll``. While :c:func:`select` is
133+
O(highest file descriptor) and :c:func:`poll` is O(number of file
134+
descriptors), ``/dev/poll`` is O(active file descriptors).
135+
136+
``/dev/poll`` behaviour is very close to the standard :c:func:`poll`
137+
object.
138+
139+
140+
.. method:: devpoll.register(fd[, eventmask])
141+
142+
Register a file descriptor with the polling object. Future calls to the
143+
:meth:`poll` method will then check whether the file descriptor has any pending
144+
I/O events. *fd* can be either an integer, or an object with a :meth:`fileno`
145+
method that returns an integer. File objects implement :meth:`fileno`, so they
146+
can also be used as the argument.
147+
148+
*eventmask* is an optional bitmask describing the type of events you want to
149+
check for. The constants are the same that with :c:func:`poll`
150+
object. The default value is a combination of the constants :const:`POLLIN`,
151+
:const:`POLLPRI`, and :const:`POLLOUT`.
152+
153+
.. warning::
154+
155+
Registering a file descriptor that's already registered is not an
156+
error, but the result is undefined. The appropiate action is to
157+
unregister or modify it first. This is an important difference
158+
compared with :c:func:`poll`.
159+
160+
161+
.. method:: devpoll.modify(fd[, eventmask])
162+
163+
This method does an :meth:`unregister` followed by a
164+
:meth:`register`. It is (a bit) more efficient that doing the same
165+
explicitly.
166+
167+
168+
.. method:: devpoll.unregister(fd)
169+
170+
Remove a file descriptor being tracked by a polling object. Just like the
171+
:meth:`register` method, *fd* can be an integer or an object with a
172+
:meth:`fileno` method that returns an integer.
173+
174+
Attempting to remove a file descriptor that was never registered is
175+
safely ignored.
176+
177+
178+
.. method:: devpoll.poll([timeout])
179+
180+
Polls the set of registered file descriptors, and returns a possibly-empty list
181+
containing ``(fd, event)`` 2-tuples for the descriptors that have events or
182+
errors to report. *fd* is the file descriptor, and *event* is a bitmask with
183+
bits set for the reported events for that descriptor --- :const:`POLLIN` for
184+
waiting input, :const:`POLLOUT` to indicate that the descriptor can be written
185+
to, and so forth. An empty list indicates that the call timed out and no file
186+
descriptors had any events to report. If *timeout* is given, it specifies the
187+
length of time in milliseconds which the system will wait for events before
188+
returning. If *timeout* is omitted, -1, or :const:`None`, the call will
189+
block until there is an event for this poll object.
190+
191+
110192
.. _epoll-objects:
111193

112194
Edge and Level Trigger Polling (epoll) Objects

Lib/test/test_devpoll.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Test case for the select.devpoll() function
2+
3+
# Initial tests are copied as is from "test_poll.py"
4+
5+
import os, select, random, unittest, sys
6+
from test.support import TESTFN, run_unittest
7+
8+
try:
9+
select.devpoll
10+
except AttributeError:
11+
raise unittest.SkipTest("select.devpoll not defined -- skipping test_devpoll")
12+
13+
14+
def find_ready_matching(ready, flag):
15+
match = []
16+
for fd, mode in ready:
17+
if mode & flag:
18+
match.append(fd)
19+
return match
20+
21+
class DevPollTests(unittest.TestCase):
22+
23+
def test_devpoll1(self):
24+
# Basic functional test of poll object
25+
# Create a bunch of pipe and test that poll works with them.
26+
27+
p = select.devpoll()
28+
29+
NUM_PIPES = 12
30+
MSG = b" This is a test."
31+
MSG_LEN = len(MSG)
32+
readers = []
33+
writers = []
34+
r2w = {}
35+
w2r = {}
36+
37+
for i in range(NUM_PIPES):
38+
rd, wr = os.pipe()
39+
p.register(rd)
40+
p.modify(rd, select.POLLIN)
41+
p.register(wr, select.POLLOUT)
42+
readers.append(rd)
43+
writers.append(wr)
44+
r2w[rd] = wr
45+
w2r[wr] = rd
46+
47+
bufs = []
48+
49+
while writers:
50+
ready = p.poll()
51+
ready_writers = find_ready_matching(ready, select.POLLOUT)
52+
if not ready_writers:
53+
self.fail("no pipes ready for writing")
54+
wr = random.choice(ready_writers)
55+
os.write(wr, MSG)
56+
57+
ready = p.poll()
58+
ready_readers = find_ready_matching(ready, select.POLLIN)
59+
if not ready_readers:
60+
self.fail("no pipes ready for reading")
61+
self.assertEqual([w2r[wr]], ready_readers)
62+
rd = ready_readers[0]
63+
buf = os.read(rd, MSG_LEN)
64+
self.assertEqual(len(buf), MSG_LEN)
65+
bufs.append(buf)
66+
os.close(r2w[rd]) ; os.close(rd)
67+
p.unregister(r2w[rd])
68+
p.unregister(rd)
69+
writers.remove(r2w[rd])
70+
71+
self.assertEqual(bufs, [MSG] * NUM_PIPES)
72+
73+
def test_timeout_overflow(self):
74+
pollster = select.devpoll()
75+
w, r = os.pipe()
76+
pollster.register(w)
77+
78+
pollster.poll(-1)
79+
self.assertRaises(OverflowError, pollster.poll, -2)
80+
self.assertRaises(OverflowError, pollster.poll, -1 << 31)
81+
self.assertRaises(OverflowError, pollster.poll, -1 << 64)
82+
83+
pollster.poll(0)
84+
pollster.poll(1)
85+
pollster.poll(1 << 30)
86+
self.assertRaises(OverflowError, pollster.poll, 1 << 31)
87+
self.assertRaises(OverflowError, pollster.poll, 1 << 63)
88+
self.assertRaises(OverflowError, pollster.poll, 1 << 64)
89+
90+
def test_main():
91+
run_unittest(DevPollTests)
92+
93+
if __name__ == '__main__':
94+
test_main()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ Core and Builtins
365365
Library
366366
-------
367367

368+
- Issue #6397: Support "/dev/poll" polling objects in select module,
369+
under Solaris & derivatives.
370+
368371
- Issues #1745761, #755670, #13357, #12629, #1200313: HTMLParser now correctly
369372
handles non-valid attributes, including adjacent and unquoted attributes.
370373

0 commit comments

Comments
 (0)