##// END OF EJS Templates
selectors2: do not use platform.system()...
Jun Wu -
r34640:a568a467 default
parent child Browse files
Show More
@@ -1,316 +1,318 b''
1 # pycompat.py - portability shim for python 3
1 # pycompat.py - portability shim for python 3
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 """Mercurial portability shim for python 3.
6 """Mercurial portability shim for python 3.
7
7
8 This contains aliases to hide python version-specific details from the core.
8 This contains aliases to hide python version-specific details from the core.
9 """
9 """
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12
12
13 import getopt
13 import getopt
14 import os
14 import os
15 import shlex
15 import shlex
16 import sys
16 import sys
17
17
18 ispy3 = (sys.version_info[0] >= 3)
18 ispy3 = (sys.version_info[0] >= 3)
19 ispypy = (r'__pypy__' in sys.builtin_module_names)
19 ispypy = (r'__pypy__' in sys.builtin_module_names)
20
20
21 if not ispy3:
21 if not ispy3:
22 import cookielib
22 import cookielib
23 import cPickle as pickle
23 import cPickle as pickle
24 import httplib
24 import httplib
25 import Queue as _queue
25 import Queue as _queue
26 import SocketServer as socketserver
26 import SocketServer as socketserver
27 import xmlrpclib
27 import xmlrpclib
28 else:
28 else:
29 import http.cookiejar as cookielib
29 import http.cookiejar as cookielib
30 import http.client as httplib
30 import http.client as httplib
31 import pickle
31 import pickle
32 import queue as _queue
32 import queue as _queue
33 import socketserver
33 import socketserver
34 import xmlrpc.client as xmlrpclib
34 import xmlrpc.client as xmlrpclib
35
35
36 empty = _queue.Empty
36 empty = _queue.Empty
37 queue = _queue.Queue
37 queue = _queue.Queue
38
38
39 def identity(a):
39 def identity(a):
40 return a
40 return a
41
41
42 if ispy3:
42 if ispy3:
43 import builtins
43 import builtins
44 import functools
44 import functools
45 import io
45 import io
46 import struct
46 import struct
47
47
48 fsencode = os.fsencode
48 fsencode = os.fsencode
49 fsdecode = os.fsdecode
49 fsdecode = os.fsdecode
50 oslinesep = os.linesep.encode('ascii')
50 oslinesep = os.linesep.encode('ascii')
51 osname = os.name.encode('ascii')
51 osname = os.name.encode('ascii')
52 ospathsep = os.pathsep.encode('ascii')
52 ospathsep = os.pathsep.encode('ascii')
53 ossep = os.sep.encode('ascii')
53 ossep = os.sep.encode('ascii')
54 osaltsep = os.altsep
54 osaltsep = os.altsep
55 if osaltsep:
55 if osaltsep:
56 osaltsep = osaltsep.encode('ascii')
56 osaltsep = osaltsep.encode('ascii')
57 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
57 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
58 # returns bytes.
58 # returns bytes.
59 getcwd = os.getcwdb
59 getcwd = os.getcwdb
60 sysplatform = sys.platform.encode('ascii')
60 sysplatform = sys.platform.encode('ascii')
61 sysexecutable = sys.executable
61 sysexecutable = sys.executable
62 if sysexecutable:
62 if sysexecutable:
63 sysexecutable = os.fsencode(sysexecutable)
63 sysexecutable = os.fsencode(sysexecutable)
64 stringio = io.BytesIO
64 stringio = io.BytesIO
65 maplist = lambda *args: list(map(*args))
65 maplist = lambda *args: list(map(*args))
66 rawinput = input
66 rawinput = input
67
67
68 # TODO: .buffer might not exist if std streams were replaced; we'll need
68 # TODO: .buffer might not exist if std streams were replaced; we'll need
69 # a silly wrapper to make a bytes stream backed by a unicode one.
69 # a silly wrapper to make a bytes stream backed by a unicode one.
70 stdin = sys.stdin.buffer
70 stdin = sys.stdin.buffer
71 stdout = sys.stdout.buffer
71 stdout = sys.stdout.buffer
72 stderr = sys.stderr.buffer
72 stderr = sys.stderr.buffer
73
73
74 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
74 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
75 # we can use os.fsencode() to get back bytes argv.
75 # we can use os.fsencode() to get back bytes argv.
76 #
76 #
77 # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
77 # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
78 #
78 #
79 # TODO: On Windows, the native argv is wchar_t, so we'll need a different
79 # TODO: On Windows, the native argv is wchar_t, so we'll need a different
80 # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
80 # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
81 if getattr(sys, 'argv', None) is not None:
81 if getattr(sys, 'argv', None) is not None:
82 sysargv = list(map(os.fsencode, sys.argv))
82 sysargv = list(map(os.fsencode, sys.argv))
83
83
84 bytechr = struct.Struct('>B').pack
84 bytechr = struct.Struct('>B').pack
85
85
86 class bytestr(bytes):
86 class bytestr(bytes):
87 """A bytes which mostly acts as a Python 2 str
87 """A bytes which mostly acts as a Python 2 str
88
88
89 >>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1)
89 >>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1)
90 (b'', b'foo', b'ascii', b'1')
90 (b'', b'foo', b'ascii', b'1')
91 >>> s = bytestr(b'foo')
91 >>> s = bytestr(b'foo')
92 >>> assert s is bytestr(s)
92 >>> assert s is bytestr(s)
93
93
94 __bytes__() should be called if provided:
94 __bytes__() should be called if provided:
95
95
96 >>> class bytesable(object):
96 >>> class bytesable(object):
97 ... def __bytes__(self):
97 ... def __bytes__(self):
98 ... return b'bytes'
98 ... return b'bytes'
99 >>> bytestr(bytesable())
99 >>> bytestr(bytesable())
100 b'bytes'
100 b'bytes'
101
101
102 There's no implicit conversion from non-ascii str as its encoding is
102 There's no implicit conversion from non-ascii str as its encoding is
103 unknown:
103 unknown:
104
104
105 >>> bytestr(chr(0x80)) # doctest: +ELLIPSIS
105 >>> bytestr(chr(0x80)) # doctest: +ELLIPSIS
106 Traceback (most recent call last):
106 Traceback (most recent call last):
107 ...
107 ...
108 UnicodeEncodeError: ...
108 UnicodeEncodeError: ...
109
109
110 Comparison between bytestr and bytes should work:
110 Comparison between bytestr and bytes should work:
111
111
112 >>> assert bytestr(b'foo') == b'foo'
112 >>> assert bytestr(b'foo') == b'foo'
113 >>> assert b'foo' == bytestr(b'foo')
113 >>> assert b'foo' == bytestr(b'foo')
114 >>> assert b'f' in bytestr(b'foo')
114 >>> assert b'f' in bytestr(b'foo')
115 >>> assert bytestr(b'f') in b'foo'
115 >>> assert bytestr(b'f') in b'foo'
116
116
117 Sliced elements should be bytes, not integer:
117 Sliced elements should be bytes, not integer:
118
118
119 >>> s[1], s[:2]
119 >>> s[1], s[:2]
120 (b'o', b'fo')
120 (b'o', b'fo')
121 >>> list(s), list(reversed(s))
121 >>> list(s), list(reversed(s))
122 ([b'f', b'o', b'o'], [b'o', b'o', b'f'])
122 ([b'f', b'o', b'o'], [b'o', b'o', b'f'])
123
123
124 As bytestr type isn't propagated across operations, you need to cast
124 As bytestr type isn't propagated across operations, you need to cast
125 bytes to bytestr explicitly:
125 bytes to bytestr explicitly:
126
126
127 >>> s = bytestr(b'foo').upper()
127 >>> s = bytestr(b'foo').upper()
128 >>> t = bytestr(s)
128 >>> t = bytestr(s)
129 >>> s[0], t[0]
129 >>> s[0], t[0]
130 (70, b'F')
130 (70, b'F')
131
131
132 Be careful to not pass a bytestr object to a function which expects
132 Be careful to not pass a bytestr object to a function which expects
133 bytearray-like behavior.
133 bytearray-like behavior.
134
134
135 >>> t = bytes(t) # cast to bytes
135 >>> t = bytes(t) # cast to bytes
136 >>> assert type(t) is bytes
136 >>> assert type(t) is bytes
137 """
137 """
138
138
139 def __new__(cls, s=b''):
139 def __new__(cls, s=b''):
140 if isinstance(s, bytestr):
140 if isinstance(s, bytestr):
141 return s
141 return s
142 if (not isinstance(s, (bytes, bytearray))
142 if (not isinstance(s, (bytes, bytearray))
143 and not hasattr(s, u'__bytes__')): # hasattr-py3-only
143 and not hasattr(s, u'__bytes__')): # hasattr-py3-only
144 s = str(s).encode(u'ascii')
144 s = str(s).encode(u'ascii')
145 return bytes.__new__(cls, s)
145 return bytes.__new__(cls, s)
146
146
147 def __getitem__(self, key):
147 def __getitem__(self, key):
148 s = bytes.__getitem__(self, key)
148 s = bytes.__getitem__(self, key)
149 if not isinstance(s, bytes):
149 if not isinstance(s, bytes):
150 s = bytechr(s)
150 s = bytechr(s)
151 return s
151 return s
152
152
153 def __iter__(self):
153 def __iter__(self):
154 return iterbytestr(bytes.__iter__(self))
154 return iterbytestr(bytes.__iter__(self))
155
155
156 def iterbytestr(s):
156 def iterbytestr(s):
157 """Iterate bytes as if it were a str object of Python 2"""
157 """Iterate bytes as if it were a str object of Python 2"""
158 return map(bytechr, s)
158 return map(bytechr, s)
159
159
160 def sysbytes(s):
160 def sysbytes(s):
161 """Convert an internal str (e.g. keyword, __doc__) back to bytes
161 """Convert an internal str (e.g. keyword, __doc__) back to bytes
162
162
163 This never raises UnicodeEncodeError, but only ASCII characters
163 This never raises UnicodeEncodeError, but only ASCII characters
164 can be round-trip by sysstr(sysbytes(s)).
164 can be round-trip by sysstr(sysbytes(s)).
165 """
165 """
166 return s.encode(u'utf-8')
166 return s.encode(u'utf-8')
167
167
168 def sysstr(s):
168 def sysstr(s):
169 """Return a keyword str to be passed to Python functions such as
169 """Return a keyword str to be passed to Python functions such as
170 getattr() and str.encode()
170 getattr() and str.encode()
171
171
172 This never raises UnicodeDecodeError. Non-ascii characters are
172 This never raises UnicodeDecodeError. Non-ascii characters are
173 considered invalid and mapped to arbitrary but unique code points
173 considered invalid and mapped to arbitrary but unique code points
174 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
174 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
175 """
175 """
176 if isinstance(s, builtins.str):
176 if isinstance(s, builtins.str):
177 return s
177 return s
178 return s.decode(u'latin-1')
178 return s.decode(u'latin-1')
179
179
180 def strurl(url):
180 def strurl(url):
181 """Converts a bytes url back to str"""
181 """Converts a bytes url back to str"""
182 return url.decode(u'ascii')
182 return url.decode(u'ascii')
183
183
184 def bytesurl(url):
184 def bytesurl(url):
185 """Converts a str url to bytes by encoding in ascii"""
185 """Converts a str url to bytes by encoding in ascii"""
186 return url.encode(u'ascii')
186 return url.encode(u'ascii')
187
187
188 def raisewithtb(exc, tb):
188 def raisewithtb(exc, tb):
189 """Raise exception with the given traceback"""
189 """Raise exception with the given traceback"""
190 raise exc.with_traceback(tb)
190 raise exc.with_traceback(tb)
191
191
192 def getdoc(obj):
192 def getdoc(obj):
193 """Get docstring as bytes; may be None so gettext() won't confuse it
193 """Get docstring as bytes; may be None so gettext() won't confuse it
194 with _('')"""
194 with _('')"""
195 doc = getattr(obj, u'__doc__', None)
195 doc = getattr(obj, u'__doc__', None)
196 if doc is None:
196 if doc is None:
197 return doc
197 return doc
198 return sysbytes(doc)
198 return sysbytes(doc)
199
199
200 def _wrapattrfunc(f):
200 def _wrapattrfunc(f):
201 @functools.wraps(f)
201 @functools.wraps(f)
202 def w(object, name, *args):
202 def w(object, name, *args):
203 return f(object, sysstr(name), *args)
203 return f(object, sysstr(name), *args)
204 return w
204 return w
205
205
206 # these wrappers are automagically imported by hgloader
206 # these wrappers are automagically imported by hgloader
207 delattr = _wrapattrfunc(builtins.delattr)
207 delattr = _wrapattrfunc(builtins.delattr)
208 getattr = _wrapattrfunc(builtins.getattr)
208 getattr = _wrapattrfunc(builtins.getattr)
209 hasattr = _wrapattrfunc(builtins.hasattr)
209 hasattr = _wrapattrfunc(builtins.hasattr)
210 setattr = _wrapattrfunc(builtins.setattr)
210 setattr = _wrapattrfunc(builtins.setattr)
211 xrange = builtins.range
211 xrange = builtins.range
212 unicode = str
212 unicode = str
213
213
214 def open(name, mode='r', buffering=-1):
214 def open(name, mode='r', buffering=-1):
215 return builtins.open(name, sysstr(mode), buffering)
215 return builtins.open(name, sysstr(mode), buffering)
216
216
217 def getoptb(args, shortlist, namelist):
217 def getoptb(args, shortlist, namelist):
218 """
218 """
219 Takes bytes arguments, converts them to unicode, pass them to
219 Takes bytes arguments, converts them to unicode, pass them to
220 getopt.getopt(), convert the returned values back to bytes and then
220 getopt.getopt(), convert the returned values back to bytes and then
221 return them for Python 3 compatibility as getopt.getopt() don't accepts
221 return them for Python 3 compatibility as getopt.getopt() don't accepts
222 bytes on Python 3.
222 bytes on Python 3.
223 """
223 """
224 args = [a.decode('latin-1') for a in args]
224 args = [a.decode('latin-1') for a in args]
225 shortlist = shortlist.decode('latin-1')
225 shortlist = shortlist.decode('latin-1')
226 namelist = [a.decode('latin-1') for a in namelist]
226 namelist = [a.decode('latin-1') for a in namelist]
227 opts, args = getopt.getopt(args, shortlist, namelist)
227 opts, args = getopt.getopt(args, shortlist, namelist)
228 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
228 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
229 for a in opts]
229 for a in opts]
230 args = [a.encode('latin-1') for a in args]
230 args = [a.encode('latin-1') for a in args]
231 return opts, args
231 return opts, args
232
232
233 def strkwargs(dic):
233 def strkwargs(dic):
234 """
234 """
235 Converts the keys of a python dictonary to str i.e. unicodes so that
235 Converts the keys of a python dictonary to str i.e. unicodes so that
236 they can be passed as keyword arguments as dictonaries with bytes keys
236 they can be passed as keyword arguments as dictonaries with bytes keys
237 can't be passed as keyword arguments to functions on Python 3.
237 can't be passed as keyword arguments to functions on Python 3.
238 """
238 """
239 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
239 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
240 return dic
240 return dic
241
241
242 def byteskwargs(dic):
242 def byteskwargs(dic):
243 """
243 """
244 Converts keys of python dictonaries to bytes as they were converted to
244 Converts keys of python dictonaries to bytes as they were converted to
245 str to pass that dictonary as a keyword argument on Python 3.
245 str to pass that dictonary as a keyword argument on Python 3.
246 """
246 """
247 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
247 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
248 return dic
248 return dic
249
249
250 # TODO: handle shlex.shlex().
250 # TODO: handle shlex.shlex().
251 def shlexsplit(s):
251 def shlexsplit(s):
252 """
252 """
253 Takes bytes argument, convert it to str i.e. unicodes, pass that into
253 Takes bytes argument, convert it to str i.e. unicodes, pass that into
254 shlex.split(), convert the returned value to bytes and return that for
254 shlex.split(), convert the returned value to bytes and return that for
255 Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
255 Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
256 """
256 """
257 ret = shlex.split(s.decode('latin-1'))
257 ret = shlex.split(s.decode('latin-1'))
258 return [a.encode('latin-1') for a in ret]
258 return [a.encode('latin-1') for a in ret]
259
259
260 else:
260 else:
261 import cStringIO
261 import cStringIO
262
262
263 bytechr = chr
263 bytechr = chr
264 bytestr = str
264 bytestr = str
265 iterbytestr = iter
265 iterbytestr = iter
266 sysbytes = identity
266 sysbytes = identity
267 sysstr = identity
267 sysstr = identity
268 strurl = identity
268 strurl = identity
269 bytesurl = identity
269 bytesurl = identity
270
270
271 # this can't be parsed on Python 3
271 # this can't be parsed on Python 3
272 exec('def raisewithtb(exc, tb):\n'
272 exec('def raisewithtb(exc, tb):\n'
273 ' raise exc, None, tb\n')
273 ' raise exc, None, tb\n')
274
274
275 def fsencode(filename):
275 def fsencode(filename):
276 """
276 """
277 Partial backport from os.py in Python 3, which only accepts bytes.
277 Partial backport from os.py in Python 3, which only accepts bytes.
278 In Python 2, our paths should only ever be bytes, a unicode path
278 In Python 2, our paths should only ever be bytes, a unicode path
279 indicates a bug.
279 indicates a bug.
280 """
280 """
281 if isinstance(filename, str):
281 if isinstance(filename, str):
282 return filename
282 return filename
283 else:
283 else:
284 raise TypeError(
284 raise TypeError(
285 "expect str, not %s" % type(filename).__name__)
285 "expect str, not %s" % type(filename).__name__)
286
286
287 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
287 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
288 # better not to touch Python 2 part as it's already working fine.
288 # better not to touch Python 2 part as it's already working fine.
289 fsdecode = identity
289 fsdecode = identity
290
290
291 def getdoc(obj):
291 def getdoc(obj):
292 return getattr(obj, '__doc__', None)
292 return getattr(obj, '__doc__', None)
293
293
294 def getoptb(args, shortlist, namelist):
294 def getoptb(args, shortlist, namelist):
295 return getopt.getopt(args, shortlist, namelist)
295 return getopt.getopt(args, shortlist, namelist)
296
296
297 strkwargs = identity
297 strkwargs = identity
298 byteskwargs = identity
298 byteskwargs = identity
299
299
300 oslinesep = os.linesep
300 oslinesep = os.linesep
301 osname = os.name
301 osname = os.name
302 ospathsep = os.pathsep
302 ospathsep = os.pathsep
303 ossep = os.sep
303 ossep = os.sep
304 osaltsep = os.altsep
304 osaltsep = os.altsep
305 stdin = sys.stdin
305 stdin = sys.stdin
306 stdout = sys.stdout
306 stdout = sys.stdout
307 stderr = sys.stderr
307 stderr = sys.stderr
308 if getattr(sys, 'argv', None) is not None:
308 if getattr(sys, 'argv', None) is not None:
309 sysargv = sys.argv
309 sysargv = sys.argv
310 sysplatform = sys.platform
310 sysplatform = sys.platform
311 getcwd = os.getcwd
311 getcwd = os.getcwd
312 sysexecutable = sys.executable
312 sysexecutable = sys.executable
313 shlexsplit = shlex.split
313 shlexsplit = shlex.split
314 stringio = cStringIO.StringIO
314 stringio = cStringIO.StringIO
315 maplist = map
315 maplist = map
316 rawinput = raw_input
316 rawinput = raw_input
317
318 isjython = sysplatform.startswith('java')
@@ -1,744 +1,745 b''
1 """ Back-ported, durable, and portable selectors """
1 """ Back-ported, durable, and portable selectors """
2
2
3 # MIT License
3 # MIT License
4 #
4 #
5 # Copyright (c) 2017 Seth Michael Larson
5 # Copyright (c) 2017 Seth Michael Larson
6 #
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
12 # furnished to do so, subject to the following conditions:
13 #
13 #
14 # The above copyright notice and this permission notice shall be included in all
14 # The above copyright notice and this permission notice shall be included in all
15 # copies or substantial portions of the Software.
15 # copies or substantial portions of the Software.
16 #
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 # SOFTWARE.
23 # SOFTWARE.
24
24
25 # no-check-code
25 # no-check-code
26
26
27 from __future__ import absolute_import
27 from __future__ import absolute_import
28
28
29 import collections
29 import collections
30 import errno
30 import errno
31 import math
31 import math
32 import platform
33 import select
32 import select
34 import socket
33 import socket
35 import sys
34 import sys
36 import time
35 import time
37
36
37 from . import pycompat
38
38 namedtuple = collections.namedtuple
39 namedtuple = collections.namedtuple
39 Mapping = collections.Mapping
40 Mapping = collections.Mapping
40
41
41 try:
42 try:
42 monotonic = time.monotonic
43 monotonic = time.monotonic
43 except AttributeError:
44 except AttributeError:
44 monotonic = time.time
45 monotonic = time.time
45
46
46 __author__ = 'Seth Michael Larson'
47 __author__ = 'Seth Michael Larson'
47 __email__ = 'sethmichaellarson@protonmail.com'
48 __email__ = 'sethmichaellarson@protonmail.com'
48 __version__ = '2.0.0'
49 __version__ = '2.0.0'
49 __license__ = 'MIT'
50 __license__ = 'MIT'
50 __url__ = 'https://www.github.com/SethMichaelLarson/selectors2'
51 __url__ = 'https://www.github.com/SethMichaelLarson/selectors2'
51
52
52 __all__ = ['EVENT_READ',
53 __all__ = ['EVENT_READ',
53 'EVENT_WRITE',
54 'EVENT_WRITE',
54 'SelectorKey',
55 'SelectorKey',
55 'DefaultSelector',
56 'DefaultSelector',
56 'BaseSelector']
57 'BaseSelector']
57
58
58 EVENT_READ = (1 << 0)
59 EVENT_READ = (1 << 0)
59 EVENT_WRITE = (1 << 1)
60 EVENT_WRITE = (1 << 1)
60 _DEFAULT_SELECTOR = None
61 _DEFAULT_SELECTOR = None
61 _SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None.
62 _SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None.
62 _ERROR_TYPES = (OSError, IOError, socket.error)
63 _ERROR_TYPES = (OSError, IOError, socket.error)
63
64
64
65
65 SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
66 SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
66
67
67
68
68 class _SelectorMapping(Mapping):
69 class _SelectorMapping(Mapping):
69 """ Mapping of file objects to selector keys """
70 """ Mapping of file objects to selector keys """
70
71
71 def __init__(self, selector):
72 def __init__(self, selector):
72 self._selector = selector
73 self._selector = selector
73
74
74 def __len__(self):
75 def __len__(self):
75 return len(self._selector._fd_to_key)
76 return len(self._selector._fd_to_key)
76
77
77 def __getitem__(self, fileobj):
78 def __getitem__(self, fileobj):
78 try:
79 try:
79 fd = self._selector._fileobj_lookup(fileobj)
80 fd = self._selector._fileobj_lookup(fileobj)
80 return self._selector._fd_to_key[fd]
81 return self._selector._fd_to_key[fd]
81 except KeyError:
82 except KeyError:
82 raise KeyError("{0!r} is not registered.".format(fileobj))
83 raise KeyError("{0!r} is not registered.".format(fileobj))
83
84
84 def __iter__(self):
85 def __iter__(self):
85 return iter(self._selector._fd_to_key)
86 return iter(self._selector._fd_to_key)
86
87
87
88
88 def _fileobj_to_fd(fileobj):
89 def _fileobj_to_fd(fileobj):
89 """ Return a file descriptor from a file object. If
90 """ Return a file descriptor from a file object. If
90 given an integer will simply return that integer back. """
91 given an integer will simply return that integer back. """
91 if isinstance(fileobj, int):
92 if isinstance(fileobj, int):
92 fd = fileobj
93 fd = fileobj
93 else:
94 else:
94 try:
95 try:
95 fd = int(fileobj.fileno())
96 fd = int(fileobj.fileno())
96 except (AttributeError, TypeError, ValueError):
97 except (AttributeError, TypeError, ValueError):
97 raise ValueError("Invalid file object: {0!r}".format(fileobj))
98 raise ValueError("Invalid file object: {0!r}".format(fileobj))
98 if fd < 0:
99 if fd < 0:
99 raise ValueError("Invalid file descriptor: {0}".format(fd))
100 raise ValueError("Invalid file descriptor: {0}".format(fd))
100 return fd
101 return fd
101
102
102
103
103 class BaseSelector(object):
104 class BaseSelector(object):
104 """ Abstract Selector class
105 """ Abstract Selector class
105
106
106 A selector supports registering file objects to be monitored
107 A selector supports registering file objects to be monitored
107 for specific I/O events.
108 for specific I/O events.
108
109
109 A file object is a file descriptor or any object with a
110 A file object is a file descriptor or any object with a
110 `fileno()` method. An arbitrary object can be attached to the
111 `fileno()` method. An arbitrary object can be attached to the
111 file object which can be used for example to store context info,
112 file object which can be used for example to store context info,
112 a callback, etc.
113 a callback, etc.
113
114
114 A selector can use various implementations (select(), poll(), epoll(),
115 A selector can use various implementations (select(), poll(), epoll(),
115 and kqueue()) depending on the platform. The 'DefaultSelector' class uses
116 and kqueue()) depending on the platform. The 'DefaultSelector' class uses
116 the most efficient implementation for the current platform.
117 the most efficient implementation for the current platform.
117 """
118 """
118 def __init__(self):
119 def __init__(self):
119 # Maps file descriptors to keys.
120 # Maps file descriptors to keys.
120 self._fd_to_key = {}
121 self._fd_to_key = {}
121
122
122 # Read-only mapping returned by get_map()
123 # Read-only mapping returned by get_map()
123 self._map = _SelectorMapping(self)
124 self._map = _SelectorMapping(self)
124
125
125 def _fileobj_lookup(self, fileobj):
126 def _fileobj_lookup(self, fileobj):
126 """ Return a file descriptor from a file object.
127 """ Return a file descriptor from a file object.
127 This wraps _fileobj_to_fd() to do an exhaustive
128 This wraps _fileobj_to_fd() to do an exhaustive
128 search in case the object is invalid but we still
129 search in case the object is invalid but we still
129 have it in our map. Used by unregister() so we can
130 have it in our map. Used by unregister() so we can
130 unregister an object that was previously registered
131 unregister an object that was previously registered
131 even if it is closed. It is also used by _SelectorMapping
132 even if it is closed. It is also used by _SelectorMapping
132 """
133 """
133 try:
134 try:
134 return _fileobj_to_fd(fileobj)
135 return _fileobj_to_fd(fileobj)
135 except ValueError:
136 except ValueError:
136
137
137 # Search through all our mapped keys.
138 # Search through all our mapped keys.
138 for key in self._fd_to_key.values():
139 for key in self._fd_to_key.values():
139 if key.fileobj is fileobj:
140 if key.fileobj is fileobj:
140 return key.fd
141 return key.fd
141
142
142 # Raise ValueError after all.
143 # Raise ValueError after all.
143 raise
144 raise
144
145
145 def register(self, fileobj, events, data=None):
146 def register(self, fileobj, events, data=None):
146 """ Register a file object for a set of events to monitor. """
147 """ Register a file object for a set of events to monitor. """
147 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
148 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
148 raise ValueError("Invalid events: {0!r}".format(events))
149 raise ValueError("Invalid events: {0!r}".format(events))
149
150
150 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
151 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
151
152
152 if key.fd in self._fd_to_key:
153 if key.fd in self._fd_to_key:
153 raise KeyError("{0!r} (FD {1}) is already registered"
154 raise KeyError("{0!r} (FD {1}) is already registered"
154 .format(fileobj, key.fd))
155 .format(fileobj, key.fd))
155
156
156 self._fd_to_key[key.fd] = key
157 self._fd_to_key[key.fd] = key
157 return key
158 return key
158
159
159 def unregister(self, fileobj):
160 def unregister(self, fileobj):
160 """ Unregister a file object from being monitored. """
161 """ Unregister a file object from being monitored. """
161 try:
162 try:
162 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
163 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
163 except KeyError:
164 except KeyError:
164 raise KeyError("{0!r} is not registered".format(fileobj))
165 raise KeyError("{0!r} is not registered".format(fileobj))
165
166
166 # Getting the fileno of a closed socket on Windows errors with EBADF.
167 # Getting the fileno of a closed socket on Windows errors with EBADF.
167 except socket.error as err:
168 except socket.error as err:
168 if err.errno != errno.EBADF:
169 if err.errno != errno.EBADF:
169 raise
170 raise
170 else:
171 else:
171 for key in self._fd_to_key.values():
172 for key in self._fd_to_key.values():
172 if key.fileobj is fileobj:
173 if key.fileobj is fileobj:
173 self._fd_to_key.pop(key.fd)
174 self._fd_to_key.pop(key.fd)
174 break
175 break
175 else:
176 else:
176 raise KeyError("{0!r} is not registered".format(fileobj))
177 raise KeyError("{0!r} is not registered".format(fileobj))
177 return key
178 return key
178
179
179 def modify(self, fileobj, events, data=None):
180 def modify(self, fileobj, events, data=None):
180 """ Change a registered file object monitored events and data. """
181 """ Change a registered file object monitored events and data. """
181 # NOTE: Some subclasses optimize this operation even further.
182 # NOTE: Some subclasses optimize this operation even further.
182 try:
183 try:
183 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
184 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
184 except KeyError:
185 except KeyError:
185 raise KeyError("{0!r} is not registered".format(fileobj))
186 raise KeyError("{0!r} is not registered".format(fileobj))
186
187
187 if events != key.events:
188 if events != key.events:
188 self.unregister(fileobj)
189 self.unregister(fileobj)
189 key = self.register(fileobj, events, data)
190 key = self.register(fileobj, events, data)
190
191
191 elif data != key.data:
192 elif data != key.data:
192 # Use a shortcut to update the data.
193 # Use a shortcut to update the data.
193 key = key._replace(data=data)
194 key = key._replace(data=data)
194 self._fd_to_key[key.fd] = key
195 self._fd_to_key[key.fd] = key
195
196
196 return key
197 return key
197
198
198 def select(self, timeout=None):
199 def select(self, timeout=None):
199 """ Perform the actual selection until some monitored file objects
200 """ Perform the actual selection until some monitored file objects
200 are ready or the timeout expires. """
201 are ready or the timeout expires. """
201 raise NotImplementedError()
202 raise NotImplementedError()
202
203
203 def close(self):
204 def close(self):
204 """ Close the selector. This must be called to ensure that all
205 """ Close the selector. This must be called to ensure that all
205 underlying resources are freed. """
206 underlying resources are freed. """
206 self._fd_to_key.clear()
207 self._fd_to_key.clear()
207 self._map = None
208 self._map = None
208
209
209 def get_key(self, fileobj):
210 def get_key(self, fileobj):
210 """ Return the key associated with a registered file object. """
211 """ Return the key associated with a registered file object. """
211 mapping = self.get_map()
212 mapping = self.get_map()
212 if mapping is None:
213 if mapping is None:
213 raise RuntimeError("Selector is closed")
214 raise RuntimeError("Selector is closed")
214 try:
215 try:
215 return mapping[fileobj]
216 return mapping[fileobj]
216 except KeyError:
217 except KeyError:
217 raise KeyError("{0!r} is not registered".format(fileobj))
218 raise KeyError("{0!r} is not registered".format(fileobj))
218
219
219 def get_map(self):
220 def get_map(self):
220 """ Return a mapping of file objects to selector keys """
221 """ Return a mapping of file objects to selector keys """
221 return self._map
222 return self._map
222
223
223 def _key_from_fd(self, fd):
224 def _key_from_fd(self, fd):
224 """ Return the key associated to a given file descriptor
225 """ Return the key associated to a given file descriptor
225 Return None if it is not found. """
226 Return None if it is not found. """
226 try:
227 try:
227 return self._fd_to_key[fd]
228 return self._fd_to_key[fd]
228 except KeyError:
229 except KeyError:
229 return None
230 return None
230
231
231 def __enter__(self):
232 def __enter__(self):
232 return self
233 return self
233
234
234 def __exit__(self, *_):
235 def __exit__(self, *_):
235 self.close()
236 self.close()
236
237
237
238
238 # Almost all platforms have select.select()
239 # Almost all platforms have select.select()
239 if hasattr(select, "select"):
240 if hasattr(select, "select"):
240 class SelectSelector(BaseSelector):
241 class SelectSelector(BaseSelector):
241 """ Select-based selector. """
242 """ Select-based selector. """
242 def __init__(self):
243 def __init__(self):
243 super(SelectSelector, self).__init__()
244 super(SelectSelector, self).__init__()
244 self._readers = set()
245 self._readers = set()
245 self._writers = set()
246 self._writers = set()
246
247
247 def register(self, fileobj, events, data=None):
248 def register(self, fileobj, events, data=None):
248 key = super(SelectSelector, self).register(fileobj, events, data)
249 key = super(SelectSelector, self).register(fileobj, events, data)
249 if events & EVENT_READ:
250 if events & EVENT_READ:
250 self._readers.add(key.fd)
251 self._readers.add(key.fd)
251 if events & EVENT_WRITE:
252 if events & EVENT_WRITE:
252 self._writers.add(key.fd)
253 self._writers.add(key.fd)
253 return key
254 return key
254
255
255 def unregister(self, fileobj):
256 def unregister(self, fileobj):
256 key = super(SelectSelector, self).unregister(fileobj)
257 key = super(SelectSelector, self).unregister(fileobj)
257 self._readers.discard(key.fd)
258 self._readers.discard(key.fd)
258 self._writers.discard(key.fd)
259 self._writers.discard(key.fd)
259 return key
260 return key
260
261
261 def select(self, timeout=None):
262 def select(self, timeout=None):
262 # Selecting on empty lists on Windows errors out.
263 # Selecting on empty lists on Windows errors out.
263 if not len(self._readers) and not len(self._writers):
264 if not len(self._readers) and not len(self._writers):
264 return []
265 return []
265
266
266 timeout = None if timeout is None else max(timeout, 0.0)
267 timeout = None if timeout is None else max(timeout, 0.0)
267 ready = []
268 ready = []
268 r, w, _ = _syscall_wrapper(self._wrap_select, True, self._readers,
269 r, w, _ = _syscall_wrapper(self._wrap_select, True, self._readers,
269 self._writers, timeout)
270 self._writers, timeout)
270 r = set(r)
271 r = set(r)
271 w = set(w)
272 w = set(w)
272 for fd in r | w:
273 for fd in r | w:
273 events = 0
274 events = 0
274 if fd in r:
275 if fd in r:
275 events |= EVENT_READ
276 events |= EVENT_READ
276 if fd in w:
277 if fd in w:
277 events |= EVENT_WRITE
278 events |= EVENT_WRITE
278
279
279 key = self._key_from_fd(fd)
280 key = self._key_from_fd(fd)
280 if key:
281 if key:
281 ready.append((key, events & key.events))
282 ready.append((key, events & key.events))
282 return ready
283 return ready
283
284
284 def _wrap_select(self, r, w, timeout=None):
285 def _wrap_select(self, r, w, timeout=None):
285 """ Wrapper for select.select because timeout is a positional arg """
286 """ Wrapper for select.select because timeout is a positional arg """
286 return select.select(r, w, [], timeout)
287 return select.select(r, w, [], timeout)
287
288
288 __all__.append('SelectSelector')
289 __all__.append('SelectSelector')
289
290
290 # Jython has a different implementation of .fileno() for socket objects.
291 # Jython has a different implementation of .fileno() for socket objects.
291 if platform.system() == 'Java':
292 if pycompat.isjython:
292 class _JythonSelectorMapping(object):
293 class _JythonSelectorMapping(object):
293 """ This is an implementation of _SelectorMapping that is built
294 """ This is an implementation of _SelectorMapping that is built
294 for use specifically with Jython, which does not provide a hashable
295 for use specifically with Jython, which does not provide a hashable
295 value from socket.socket.fileno(). """
296 value from socket.socket.fileno(). """
296
297
297 def __init__(self, selector):
298 def __init__(self, selector):
298 assert isinstance(selector, JythonSelectSelector)
299 assert isinstance(selector, JythonSelectSelector)
299 self._selector = selector
300 self._selector = selector
300
301
301 def __len__(self):
302 def __len__(self):
302 return len(self._selector._sockets)
303 return len(self._selector._sockets)
303
304
304 def __getitem__(self, fileobj):
305 def __getitem__(self, fileobj):
305 for sock, key in self._selector._sockets:
306 for sock, key in self._selector._sockets:
306 if sock is fileobj:
307 if sock is fileobj:
307 return key
308 return key
308 else:
309 else:
309 raise KeyError("{0!r} is not registered.".format(fileobj))
310 raise KeyError("{0!r} is not registered.".format(fileobj))
310
311
311 class JythonSelectSelector(SelectSelector):
312 class JythonSelectSelector(SelectSelector):
312 """ This is an implementation of SelectSelector that is for Jython
313 """ This is an implementation of SelectSelector that is for Jython
313 which works around that Jython's socket.socket.fileno() does not
314 which works around that Jython's socket.socket.fileno() does not
314 return an integer fd value. All SelectorKey.fd will be equal to -1
315 return an integer fd value. All SelectorKey.fd will be equal to -1
315 and should not be used. This instead uses object id to compare fileobj
316 and should not be used. This instead uses object id to compare fileobj
316 and will only use select.select as it's the only selector that allows
317 and will only use select.select as it's the only selector that allows
317 directly passing in socket objects rather than registering fds.
318 directly passing in socket objects rather than registering fds.
318 See: http://bugs.jython.org/issue1678
319 See: http://bugs.jython.org/issue1678
319 https://wiki.python.org/jython/NewSocketModule#socket.fileno.28.29_does_not_return_an_integer
320 https://wiki.python.org/jython/NewSocketModule#socket.fileno.28.29_does_not_return_an_integer
320 """
321 """
321
322
322 def __init__(self):
323 def __init__(self):
323 super(JythonSelectSelector, self).__init__()
324 super(JythonSelectSelector, self).__init__()
324
325
325 self._sockets = [] # Uses a list of tuples instead of dictionary.
326 self._sockets = [] # Uses a list of tuples instead of dictionary.
326 self._map = _JythonSelectorMapping(self)
327 self._map = _JythonSelectorMapping(self)
327 self._readers = []
328 self._readers = []
328 self._writers = []
329 self._writers = []
329
330
330 # Jython has a select.cpython_compatible_select function in older versions.
331 # Jython has a select.cpython_compatible_select function in older versions.
331 self._select_func = getattr(select, 'cpython_compatible_select', select.select)
332 self._select_func = getattr(select, 'cpython_compatible_select', select.select)
332
333
333 def register(self, fileobj, events, data=None):
334 def register(self, fileobj, events, data=None):
334 for sock, _ in self._sockets:
335 for sock, _ in self._sockets:
335 if sock is fileobj:
336 if sock is fileobj:
336 raise KeyError("{0!r} is already registered"
337 raise KeyError("{0!r} is already registered"
337 .format(fileobj, sock))
338 .format(fileobj, sock))
338
339
339 key = SelectorKey(fileobj, -1, events, data)
340 key = SelectorKey(fileobj, -1, events, data)
340 self._sockets.append((fileobj, key))
341 self._sockets.append((fileobj, key))
341
342
342 if events & EVENT_READ:
343 if events & EVENT_READ:
343 self._readers.append(fileobj)
344 self._readers.append(fileobj)
344 if events & EVENT_WRITE:
345 if events & EVENT_WRITE:
345 self._writers.append(fileobj)
346 self._writers.append(fileobj)
346 return key
347 return key
347
348
348 def unregister(self, fileobj):
349 def unregister(self, fileobj):
349 for i, (sock, key) in enumerate(self._sockets):
350 for i, (sock, key) in enumerate(self._sockets):
350 if sock is fileobj:
351 if sock is fileobj:
351 break
352 break
352 else:
353 else:
353 raise KeyError("{0!r} is not registered.".format(fileobj))
354 raise KeyError("{0!r} is not registered.".format(fileobj))
354
355
355 if key.events & EVENT_READ:
356 if key.events & EVENT_READ:
356 self._readers.remove(fileobj)
357 self._readers.remove(fileobj)
357 if key.events & EVENT_WRITE:
358 if key.events & EVENT_WRITE:
358 self._writers.remove(fileobj)
359 self._writers.remove(fileobj)
359
360
360 del self._sockets[i]
361 del self._sockets[i]
361 return key
362 return key
362
363
363 def _wrap_select(self, r, w, timeout=None):
364 def _wrap_select(self, r, w, timeout=None):
364 """ Wrapper for select.select because timeout is a positional arg """
365 """ Wrapper for select.select because timeout is a positional arg """
365 return self._select_func(r, w, [], timeout)
366 return self._select_func(r, w, [], timeout)
366
367
367 __all__.append('JythonSelectSelector')
368 __all__.append('JythonSelectSelector')
368 SelectSelector = JythonSelectSelector # Override so the wrong selector isn't used.
369 SelectSelector = JythonSelectSelector # Override so the wrong selector isn't used.
369
370
370
371
371 if hasattr(select, "poll"):
372 if hasattr(select, "poll"):
372 class PollSelector(BaseSelector):
373 class PollSelector(BaseSelector):
373 """ Poll-based selector """
374 """ Poll-based selector """
374 def __init__(self):
375 def __init__(self):
375 super(PollSelector, self).__init__()
376 super(PollSelector, self).__init__()
376 self._poll = select.poll()
377 self._poll = select.poll()
377
378
378 def register(self, fileobj, events, data=None):
379 def register(self, fileobj, events, data=None):
379 key = super(PollSelector, self).register(fileobj, events, data)
380 key = super(PollSelector, self).register(fileobj, events, data)
380 event_mask = 0
381 event_mask = 0
381 if events & EVENT_READ:
382 if events & EVENT_READ:
382 event_mask |= select.POLLIN
383 event_mask |= select.POLLIN
383 if events & EVENT_WRITE:
384 if events & EVENT_WRITE:
384 event_mask |= select.POLLOUT
385 event_mask |= select.POLLOUT
385 self._poll.register(key.fd, event_mask)
386 self._poll.register(key.fd, event_mask)
386 return key
387 return key
387
388
388 def unregister(self, fileobj):
389 def unregister(self, fileobj):
389 key = super(PollSelector, self).unregister(fileobj)
390 key = super(PollSelector, self).unregister(fileobj)
390 self._poll.unregister(key.fd)
391 self._poll.unregister(key.fd)
391 return key
392 return key
392
393
393 def _wrap_poll(self, timeout=None):
394 def _wrap_poll(self, timeout=None):
394 """ Wrapper function for select.poll.poll() so that
395 """ Wrapper function for select.poll.poll() so that
395 _syscall_wrapper can work with only seconds. """
396 _syscall_wrapper can work with only seconds. """
396 if timeout is not None:
397 if timeout is not None:
397 if timeout <= 0:
398 if timeout <= 0:
398 timeout = 0
399 timeout = 0
399 else:
400 else:
400 # select.poll.poll() has a resolution of 1 millisecond,
401 # select.poll.poll() has a resolution of 1 millisecond,
401 # round away from zero to wait *at least* timeout seconds.
402 # round away from zero to wait *at least* timeout seconds.
402 timeout = math.ceil(timeout * 1000)
403 timeout = math.ceil(timeout * 1000)
403
404
404 result = self._poll.poll(timeout)
405 result = self._poll.poll(timeout)
405 return result
406 return result
406
407
407 def select(self, timeout=None):
408 def select(self, timeout=None):
408 ready = []
409 ready = []
409 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout)
410 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout)
410 for fd, event_mask in fd_events:
411 for fd, event_mask in fd_events:
411 events = 0
412 events = 0
412 if event_mask & ~select.POLLIN:
413 if event_mask & ~select.POLLIN:
413 events |= EVENT_WRITE
414 events |= EVENT_WRITE
414 if event_mask & ~select.POLLOUT:
415 if event_mask & ~select.POLLOUT:
415 events |= EVENT_READ
416 events |= EVENT_READ
416
417
417 key = self._key_from_fd(fd)
418 key = self._key_from_fd(fd)
418 if key:
419 if key:
419 ready.append((key, events & key.events))
420 ready.append((key, events & key.events))
420
421
421 return ready
422 return ready
422
423
423 __all__.append('PollSelector')
424 __all__.append('PollSelector')
424
425
425 if hasattr(select, "epoll"):
426 if hasattr(select, "epoll"):
426 class EpollSelector(BaseSelector):
427 class EpollSelector(BaseSelector):
427 """ Epoll-based selector """
428 """ Epoll-based selector """
428 def __init__(self):
429 def __init__(self):
429 super(EpollSelector, self).__init__()
430 super(EpollSelector, self).__init__()
430 self._epoll = select.epoll()
431 self._epoll = select.epoll()
431
432
432 def fileno(self):
433 def fileno(self):
433 return self._epoll.fileno()
434 return self._epoll.fileno()
434
435
435 def register(self, fileobj, events, data=None):
436 def register(self, fileobj, events, data=None):
436 key = super(EpollSelector, self).register(fileobj, events, data)
437 key = super(EpollSelector, self).register(fileobj, events, data)
437 events_mask = 0
438 events_mask = 0
438 if events & EVENT_READ:
439 if events & EVENT_READ:
439 events_mask |= select.EPOLLIN
440 events_mask |= select.EPOLLIN
440 if events & EVENT_WRITE:
441 if events & EVENT_WRITE:
441 events_mask |= select.EPOLLOUT
442 events_mask |= select.EPOLLOUT
442 _syscall_wrapper(self._epoll.register, False, key.fd, events_mask)
443 _syscall_wrapper(self._epoll.register, False, key.fd, events_mask)
443 return key
444 return key
444
445
445 def unregister(self, fileobj):
446 def unregister(self, fileobj):
446 key = super(EpollSelector, self).unregister(fileobj)
447 key = super(EpollSelector, self).unregister(fileobj)
447 try:
448 try:
448 _syscall_wrapper(self._epoll.unregister, False, key.fd)
449 _syscall_wrapper(self._epoll.unregister, False, key.fd)
449 except _ERROR_TYPES:
450 except _ERROR_TYPES:
450 # This can occur when the fd was closed since registry.
451 # This can occur when the fd was closed since registry.
451 pass
452 pass
452 return key
453 return key
453
454
454 def select(self, timeout=None):
455 def select(self, timeout=None):
455 if timeout is not None:
456 if timeout is not None:
456 if timeout <= 0:
457 if timeout <= 0:
457 timeout = 0.0
458 timeout = 0.0
458 else:
459 else:
459 # select.epoll.poll() has a resolution of 1 millisecond
460 # select.epoll.poll() has a resolution of 1 millisecond
460 # but luckily takes seconds so we don't need a wrapper
461 # but luckily takes seconds so we don't need a wrapper
461 # like PollSelector. Just for better rounding.
462 # like PollSelector. Just for better rounding.
462 timeout = math.ceil(timeout * 1000) * 0.001
463 timeout = math.ceil(timeout * 1000) * 0.001
463 timeout = float(timeout)
464 timeout = float(timeout)
464 else:
465 else:
465 timeout = -1.0 # epoll.poll() must have a float.
466 timeout = -1.0 # epoll.poll() must have a float.
466
467
467 # We always want at least 1 to ensure that select can be called
468 # We always want at least 1 to ensure that select can be called
468 # with no file descriptors registered. Otherwise will fail.
469 # with no file descriptors registered. Otherwise will fail.
469 max_events = max(len(self._fd_to_key), 1)
470 max_events = max(len(self._fd_to_key), 1)
470
471
471 ready = []
472 ready = []
472 fd_events = _syscall_wrapper(self._epoll.poll, True,
473 fd_events = _syscall_wrapper(self._epoll.poll, True,
473 timeout=timeout,
474 timeout=timeout,
474 maxevents=max_events)
475 maxevents=max_events)
475 for fd, event_mask in fd_events:
476 for fd, event_mask in fd_events:
476 events = 0
477 events = 0
477 if event_mask & ~select.EPOLLIN:
478 if event_mask & ~select.EPOLLIN:
478 events |= EVENT_WRITE
479 events |= EVENT_WRITE
479 if event_mask & ~select.EPOLLOUT:
480 if event_mask & ~select.EPOLLOUT:
480 events |= EVENT_READ
481 events |= EVENT_READ
481
482
482 key = self._key_from_fd(fd)
483 key = self._key_from_fd(fd)
483 if key:
484 if key:
484 ready.append((key, events & key.events))
485 ready.append((key, events & key.events))
485 return ready
486 return ready
486
487
487 def close(self):
488 def close(self):
488 self._epoll.close()
489 self._epoll.close()
489 super(EpollSelector, self).close()
490 super(EpollSelector, self).close()
490
491
491 __all__.append('EpollSelector')
492 __all__.append('EpollSelector')
492
493
493
494
494 if hasattr(select, "devpoll"):
495 if hasattr(select, "devpoll"):
495 class DevpollSelector(BaseSelector):
496 class DevpollSelector(BaseSelector):
496 """Solaris /dev/poll selector."""
497 """Solaris /dev/poll selector."""
497
498
498 def __init__(self):
499 def __init__(self):
499 super(DevpollSelector, self).__init__()
500 super(DevpollSelector, self).__init__()
500 self._devpoll = select.devpoll()
501 self._devpoll = select.devpoll()
501
502
502 def fileno(self):
503 def fileno(self):
503 return self._devpoll.fileno()
504 return self._devpoll.fileno()
504
505
505 def register(self, fileobj, events, data=None):
506 def register(self, fileobj, events, data=None):
506 key = super(DevpollSelector, self).register(fileobj, events, data)
507 key = super(DevpollSelector, self).register(fileobj, events, data)
507 poll_events = 0
508 poll_events = 0
508 if events & EVENT_READ:
509 if events & EVENT_READ:
509 poll_events |= select.POLLIN
510 poll_events |= select.POLLIN
510 if events & EVENT_WRITE:
511 if events & EVENT_WRITE:
511 poll_events |= select.POLLOUT
512 poll_events |= select.POLLOUT
512 self._devpoll.register(key.fd, poll_events)
513 self._devpoll.register(key.fd, poll_events)
513 return key
514 return key
514
515
515 def unregister(self, fileobj):
516 def unregister(self, fileobj):
516 key = super(DevpollSelector, self).unregister(fileobj)
517 key = super(DevpollSelector, self).unregister(fileobj)
517 self._devpoll.unregister(key.fd)
518 self._devpoll.unregister(key.fd)
518 return key
519 return key
519
520
520 def _wrap_poll(self, timeout=None):
521 def _wrap_poll(self, timeout=None):
521 """ Wrapper function for select.poll.poll() so that
522 """ Wrapper function for select.poll.poll() so that
522 _syscall_wrapper can work with only seconds. """
523 _syscall_wrapper can work with only seconds. """
523 if timeout is not None:
524 if timeout is not None:
524 if timeout <= 0:
525 if timeout <= 0:
525 timeout = 0
526 timeout = 0
526 else:
527 else:
527 # select.devpoll.poll() has a resolution of 1 millisecond,
528 # select.devpoll.poll() has a resolution of 1 millisecond,
528 # round away from zero to wait *at least* timeout seconds.
529 # round away from zero to wait *at least* timeout seconds.
529 timeout = math.ceil(timeout * 1000)
530 timeout = math.ceil(timeout * 1000)
530
531
531 result = self._devpoll.poll(timeout)
532 result = self._devpoll.poll(timeout)
532 return result
533 return result
533
534
534 def select(self, timeout=None):
535 def select(self, timeout=None):
535 ready = []
536 ready = []
536 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout)
537 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout)
537 for fd, event_mask in fd_events:
538 for fd, event_mask in fd_events:
538 events = 0
539 events = 0
539 if event_mask & ~select.POLLIN:
540 if event_mask & ~select.POLLIN:
540 events |= EVENT_WRITE
541 events |= EVENT_WRITE
541 if event_mask & ~select.POLLOUT:
542 if event_mask & ~select.POLLOUT:
542 events |= EVENT_READ
543 events |= EVENT_READ
543
544
544 key = self._key_from_fd(fd)
545 key = self._key_from_fd(fd)
545 if key:
546 if key:
546 ready.append((key, events & key.events))
547 ready.append((key, events & key.events))
547
548
548 return ready
549 return ready
549
550
550 def close(self):
551 def close(self):
551 self._devpoll.close()
552 self._devpoll.close()
552 super(DevpollSelector, self).close()
553 super(DevpollSelector, self).close()
553
554
554 __all__.append('DevpollSelector')
555 __all__.append('DevpollSelector')
555
556
556
557
557 if hasattr(select, "kqueue"):
558 if hasattr(select, "kqueue"):
558 class KqueueSelector(BaseSelector):
559 class KqueueSelector(BaseSelector):
559 """ Kqueue / Kevent-based selector """
560 """ Kqueue / Kevent-based selector """
560 def __init__(self):
561 def __init__(self):
561 super(KqueueSelector, self).__init__()
562 super(KqueueSelector, self).__init__()
562 self._kqueue = select.kqueue()
563 self._kqueue = select.kqueue()
563
564
564 def fileno(self):
565 def fileno(self):
565 return self._kqueue.fileno()
566 return self._kqueue.fileno()
566
567
567 def register(self, fileobj, events, data=None):
568 def register(self, fileobj, events, data=None):
568 key = super(KqueueSelector, self).register(fileobj, events, data)
569 key = super(KqueueSelector, self).register(fileobj, events, data)
569 if events & EVENT_READ:
570 if events & EVENT_READ:
570 kevent = select.kevent(key.fd,
571 kevent = select.kevent(key.fd,
571 select.KQ_FILTER_READ,
572 select.KQ_FILTER_READ,
572 select.KQ_EV_ADD)
573 select.KQ_EV_ADD)
573
574
574 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
575 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
575
576
576 if events & EVENT_WRITE:
577 if events & EVENT_WRITE:
577 kevent = select.kevent(key.fd,
578 kevent = select.kevent(key.fd,
578 select.KQ_FILTER_WRITE,
579 select.KQ_FILTER_WRITE,
579 select.KQ_EV_ADD)
580 select.KQ_EV_ADD)
580
581
581 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
582 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
582
583
583 return key
584 return key
584
585
585 def unregister(self, fileobj):
586 def unregister(self, fileobj):
586 key = super(KqueueSelector, self).unregister(fileobj)
587 key = super(KqueueSelector, self).unregister(fileobj)
587 if key.events & EVENT_READ:
588 if key.events & EVENT_READ:
588 kevent = select.kevent(key.fd,
589 kevent = select.kevent(key.fd,
589 select.KQ_FILTER_READ,
590 select.KQ_FILTER_READ,
590 select.KQ_EV_DELETE)
591 select.KQ_EV_DELETE)
591 try:
592 try:
592 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
593 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
593 except _ERROR_TYPES:
594 except _ERROR_TYPES:
594 pass
595 pass
595 if key.events & EVENT_WRITE:
596 if key.events & EVENT_WRITE:
596 kevent = select.kevent(key.fd,
597 kevent = select.kevent(key.fd,
597 select.KQ_FILTER_WRITE,
598 select.KQ_FILTER_WRITE,
598 select.KQ_EV_DELETE)
599 select.KQ_EV_DELETE)
599 try:
600 try:
600 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
601 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
601 except _ERROR_TYPES:
602 except _ERROR_TYPES:
602 pass
603 pass
603
604
604 return key
605 return key
605
606
606 def select(self, timeout=None):
607 def select(self, timeout=None):
607 if timeout is not None:
608 if timeout is not None:
608 timeout = max(timeout, 0)
609 timeout = max(timeout, 0)
609
610
610 max_events = len(self._fd_to_key) * 2
611 max_events = len(self._fd_to_key) * 2
611 ready_fds = {}
612 ready_fds = {}
612
613
613 kevent_list = _syscall_wrapper(self._kqueue.control, True,
614 kevent_list = _syscall_wrapper(self._kqueue.control, True,
614 None, max_events, timeout)
615 None, max_events, timeout)
615
616
616 for kevent in kevent_list:
617 for kevent in kevent_list:
617 fd = kevent.ident
618 fd = kevent.ident
618 event_mask = kevent.filter
619 event_mask = kevent.filter
619 events = 0
620 events = 0
620 if event_mask == select.KQ_FILTER_READ:
621 if event_mask == select.KQ_FILTER_READ:
621 events |= EVENT_READ
622 events |= EVENT_READ
622 if event_mask == select.KQ_FILTER_WRITE:
623 if event_mask == select.KQ_FILTER_WRITE:
623 events |= EVENT_WRITE
624 events |= EVENT_WRITE
624
625
625 key = self._key_from_fd(fd)
626 key = self._key_from_fd(fd)
626 if key:
627 if key:
627 if key.fd not in ready_fds:
628 if key.fd not in ready_fds:
628 ready_fds[key.fd] = (key, events & key.events)
629 ready_fds[key.fd] = (key, events & key.events)
629 else:
630 else:
630 old_events = ready_fds[key.fd][1]
631 old_events = ready_fds[key.fd][1]
631 ready_fds[key.fd] = (key, (events | old_events) & key.events)
632 ready_fds[key.fd] = (key, (events | old_events) & key.events)
632
633
633 return list(ready_fds.values())
634 return list(ready_fds.values())
634
635
635 def close(self):
636 def close(self):
636 self._kqueue.close()
637 self._kqueue.close()
637 super(KqueueSelector, self).close()
638 super(KqueueSelector, self).close()
638
639
639 __all__.append('KqueueSelector')
640 __all__.append('KqueueSelector')
640
641
641
642
642 def _can_allocate(struct):
643 def _can_allocate(struct):
643 """ Checks that select structs can be allocated by the underlying
644 """ Checks that select structs can be allocated by the underlying
644 operating system, not just advertised by the select module. We don't
645 operating system, not just advertised by the select module. We don't
645 check select() because we'll be hopeful that most platforms that
646 check select() because we'll be hopeful that most platforms that
646 don't have it available will not advertise it. (ie: GAE) """
647 don't have it available will not advertise it. (ie: GAE) """
647 try:
648 try:
648 # select.poll() objects won't fail until used.
649 # select.poll() objects won't fail until used.
649 if struct == 'poll':
650 if struct == 'poll':
650 p = select.poll()
651 p = select.poll()
651 p.poll(0)
652 p.poll(0)
652
653
653 # All others will fail on allocation.
654 # All others will fail on allocation.
654 else:
655 else:
655 getattr(select, struct)().close()
656 getattr(select, struct)().close()
656 return True
657 return True
657 except (OSError, AttributeError):
658 except (OSError, AttributeError):
658 return False
659 return False
659
660
660
661
661 # Python 3.5 uses a more direct route to wrap system calls to increase speed.
662 # Python 3.5 uses a more direct route to wrap system calls to increase speed.
662 if sys.version_info >= (3, 5):
663 if sys.version_info >= (3, 5):
663 def _syscall_wrapper(func, _, *args, **kwargs):
664 def _syscall_wrapper(func, _, *args, **kwargs):
664 """ This is the short-circuit version of the below logic
665 """ This is the short-circuit version of the below logic
665 because in Python 3.5+ all selectors restart system calls. """
666 because in Python 3.5+ all selectors restart system calls. """
666 return func(*args, **kwargs)
667 return func(*args, **kwargs)
667 else:
668 else:
668 def _syscall_wrapper(func, recalc_timeout, *args, **kwargs):
669 def _syscall_wrapper(func, recalc_timeout, *args, **kwargs):
669 """ Wrapper function for syscalls that could fail due to EINTR.
670 """ Wrapper function for syscalls that could fail due to EINTR.
670 All functions should be retried if there is time left in the timeout
671 All functions should be retried if there is time left in the timeout
671 in accordance with PEP 475. """
672 in accordance with PEP 475. """
672 timeout = kwargs.get("timeout", None)
673 timeout = kwargs.get("timeout", None)
673 if timeout is None:
674 if timeout is None:
674 expires = None
675 expires = None
675 recalc_timeout = False
676 recalc_timeout = False
676 else:
677 else:
677 timeout = float(timeout)
678 timeout = float(timeout)
678 if timeout < 0.0: # Timeout less than 0 treated as no timeout.
679 if timeout < 0.0: # Timeout less than 0 treated as no timeout.
679 expires = None
680 expires = None
680 else:
681 else:
681 expires = monotonic() + timeout
682 expires = monotonic() + timeout
682
683
683 args = list(args)
684 args = list(args)
684 if recalc_timeout and "timeout" not in kwargs:
685 if recalc_timeout and "timeout" not in kwargs:
685 raise ValueError(
686 raise ValueError(
686 "Timeout must be in args or kwargs to be recalculated")
687 "Timeout must be in args or kwargs to be recalculated")
687
688
688 result = _SYSCALL_SENTINEL
689 result = _SYSCALL_SENTINEL
689 while result is _SYSCALL_SENTINEL:
690 while result is _SYSCALL_SENTINEL:
690 try:
691 try:
691 result = func(*args, **kwargs)
692 result = func(*args, **kwargs)
692 # OSError is thrown by select.select
693 # OSError is thrown by select.select
693 # IOError is thrown by select.epoll.poll
694 # IOError is thrown by select.epoll.poll
694 # select.error is thrown by select.poll.poll
695 # select.error is thrown by select.poll.poll
695 # Aren't we thankful for Python 3.x rework for exceptions?
696 # Aren't we thankful for Python 3.x rework for exceptions?
696 except (OSError, IOError, select.error) as e:
697 except (OSError, IOError, select.error) as e:
697 # select.error wasn't a subclass of OSError in the past.
698 # select.error wasn't a subclass of OSError in the past.
698 errcode = None
699 errcode = None
699 if hasattr(e, "errno"):
700 if hasattr(e, "errno"):
700 errcode = e.errno
701 errcode = e.errno
701 elif hasattr(e, "args"):
702 elif hasattr(e, "args"):
702 errcode = e.args[0]
703 errcode = e.args[0]
703
704
704 # Also test for the Windows equivalent of EINTR.
705 # Also test for the Windows equivalent of EINTR.
705 is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and
706 is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and
706 errcode == errno.WSAEINTR))
707 errcode == errno.WSAEINTR))
707
708
708 if is_interrupt:
709 if is_interrupt:
709 if expires is not None:
710 if expires is not None:
710 current_time = monotonic()
711 current_time = monotonic()
711 if current_time > expires:
712 if current_time > expires:
712 raise OSError(errno=errno.ETIMEDOUT)
713 raise OSError(errno=errno.ETIMEDOUT)
713 if recalc_timeout:
714 if recalc_timeout:
714 if "timeout" in kwargs:
715 if "timeout" in kwargs:
715 kwargs["timeout"] = expires - current_time
716 kwargs["timeout"] = expires - current_time
716 continue
717 continue
717 raise
718 raise
718 return result
719 return result
719
720
720
721
721 # Choose the best implementation, roughly:
722 # Choose the best implementation, roughly:
722 # kqueue == devpoll == epoll > poll > select
723 # kqueue == devpoll == epoll > poll > select
723 # select() also can't accept a FD > FD_SETSIZE (usually around 1024)
724 # select() also can't accept a FD > FD_SETSIZE (usually around 1024)
724 def DefaultSelector():
725 def DefaultSelector():
725 """ This function serves as a first call for DefaultSelector to
726 """ This function serves as a first call for DefaultSelector to
726 detect if the select module is being monkey-patched incorrectly
727 detect if the select module is being monkey-patched incorrectly
727 by eventlet, greenlet, and preserve proper behavior. """
728 by eventlet, greenlet, and preserve proper behavior. """
728 global _DEFAULT_SELECTOR
729 global _DEFAULT_SELECTOR
729 if _DEFAULT_SELECTOR is None:
730 if _DEFAULT_SELECTOR is None:
730 if platform.system() == 'Java': # Platform-specific: Jython
731 if pycompat.isjython:
731 _DEFAULT_SELECTOR = JythonSelectSelector
732 _DEFAULT_SELECTOR = JythonSelectSelector
732 elif _can_allocate('kqueue'):
733 elif _can_allocate('kqueue'):
733 _DEFAULT_SELECTOR = KqueueSelector
734 _DEFAULT_SELECTOR = KqueueSelector
734 elif _can_allocate('devpoll'):
735 elif _can_allocate('devpoll'):
735 _DEFAULT_SELECTOR = DevpollSelector
736 _DEFAULT_SELECTOR = DevpollSelector
736 elif _can_allocate('epoll'):
737 elif _can_allocate('epoll'):
737 _DEFAULT_SELECTOR = EpollSelector
738 _DEFAULT_SELECTOR = EpollSelector
738 elif _can_allocate('poll'):
739 elif _can_allocate('poll'):
739 _DEFAULT_SELECTOR = PollSelector
740 _DEFAULT_SELECTOR = PollSelector
740 elif hasattr(select, 'select'):
741 elif hasattr(select, 'select'):
741 _DEFAULT_SELECTOR = SelectSelector
742 _DEFAULT_SELECTOR = SelectSelector
742 else: # Platform-specific: AppEngine
743 else: # Platform-specific: AppEngine
743 raise RuntimeError('Platform does not have a selector.')
744 raise RuntimeError('Platform does not have a selector.')
744 return _DEFAULT_SELECTOR()
745 return _DEFAULT_SELECTOR()
General Comments 0
You need to be logged in to leave comments. Login now