greenio: socket.dup() made excess fcntl syscalls, added set_nonblocking=True kwarg to skip it; Thanks to Peter Portante
https://bitbucket.org/which_linden/eventlet/pull-request/27
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -78,3 +78,4 @@ Thanks To
|
|||||||
* Eric Windisch, zmq getsockopt(EVENTS) wake correct threads (pull request 22)
|
* Eric Windisch, zmq getsockopt(EVENTS) wake correct threads (pull request 22)
|
||||||
* Raymond Lu, fixing busy-wait in eventlet.green.ssl.socket.sendall()
|
* Raymond Lu, fixing busy-wait in eventlet.green.ssl.socket.sendall()
|
||||||
* Thomas Grainger, webcrawler example small fix, "requests" library import bug report
|
* Thomas Grainger, webcrawler example small fix, "requests" library import bug report
|
||||||
|
* Peter Portante, save syscalls in socket.dup(), environ[REMOTE_PORT] in wsgi
|
||||||
|
@@ -97,8 +97,10 @@ def set_nonblocking(fd):
|
|||||||
"(Windows pipes don't support non-blocking I/O)")
|
"(Windows pipes don't support non-blocking I/O)")
|
||||||
# We managed to import fcntl.
|
# We managed to import fcntl.
|
||||||
fileno = fd.fileno()
|
fileno = fd.fileno()
|
||||||
flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
|
orig_flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
|
||||||
fcntl.fcntl(fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
new_flags = orig_flags | os.O_NONBLOCK
|
||||||
|
if new_flags != orig_flags:
|
||||||
|
fcntl.fcntl(fileno, fcntl.F_SETFL, new_flags)
|
||||||
else:
|
else:
|
||||||
# socket supports setblocking()
|
# socket supports setblocking()
|
||||||
setblocking(0)
|
setblocking(0)
|
||||||
@@ -114,8 +116,13 @@ class GreenSocket(object):
|
|||||||
"""
|
"""
|
||||||
Green version of socket.socket class, that is intended to be 100%
|
Green version of socket.socket class, that is intended to be 100%
|
||||||
API-compatible.
|
API-compatible.
|
||||||
|
|
||||||
|
It also recognizes the keyword parameter, 'set_nonblocking=True'.
|
||||||
|
Pass False to indicate that socket is already in non-blocking mode
|
||||||
|
to save syscalls.
|
||||||
"""
|
"""
|
||||||
def __init__(self, family_or_realsock=socket.AF_INET, *args, **kwargs):
|
def __init__(self, family_or_realsock=socket.AF_INET, *args, **kwargs):
|
||||||
|
should_set_nonblocking = kwargs.pop('set_nonblocking', True)
|
||||||
if isinstance(family_or_realsock, (int, long)):
|
if isinstance(family_or_realsock, (int, long)):
|
||||||
fd = _original_socket(family_or_realsock, *args, **kwargs)
|
fd = _original_socket(family_or_realsock, *args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@@ -129,7 +136,8 @@ class GreenSocket(object):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
self._timeout = socket.getdefaulttimeout()
|
self._timeout = socket.getdefaulttimeout()
|
||||||
|
|
||||||
set_nonblocking(fd)
|
if should_set_nonblocking:
|
||||||
|
set_nonblocking(fd)
|
||||||
self.fd = fd
|
self.fd = fd
|
||||||
# when client calls setblocking(0) or settimeout(0) the socket must
|
# when client calls setblocking(0) or settimeout(0) the socket must
|
||||||
# act non-blocking
|
# act non-blocking
|
||||||
@@ -209,8 +217,7 @@ class GreenSocket(object):
|
|||||||
|
|
||||||
def dup(self, *args, **kw):
|
def dup(self, *args, **kw):
|
||||||
sock = self.fd.dup(*args, **kw)
|
sock = self.fd.dup(*args, **kw)
|
||||||
set_nonblocking(sock)
|
newsock = type(self)(sock, set_nonblocking=False)
|
||||||
newsock = type(self)(sock)
|
|
||||||
newsock.settimeout(self.gettimeout())
|
newsock.settimeout(self.gettimeout())
|
||||||
return newsock
|
return newsock
|
||||||
|
|
||||||
|
@@ -4,12 +4,13 @@ from eventlet import event, greenio, debug
|
|||||||
from eventlet.hubs import get_hub
|
from eventlet.hubs import get_hub
|
||||||
from eventlet.green import socket, time
|
from eventlet.green import socket, time
|
||||||
from eventlet.support import get_errno
|
from eventlet.support import get_errno
|
||||||
import errno
|
|
||||||
|
|
||||||
|
import array
|
||||||
|
import errno
|
||||||
import eventlet
|
import eventlet
|
||||||
|
import fcntl
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import array
|
|
||||||
import tempfile, shutil
|
import tempfile, shutil
|
||||||
|
|
||||||
|
|
||||||
@@ -551,6 +552,35 @@ class TestGreenSocket(LimitedTestCase):
|
|||||||
self.assertRaises(socket.timeout, client.recv, 1)
|
self.assertRaises(socket.timeout, client.recv, 1)
|
||||||
server.wait()
|
server.wait()
|
||||||
|
|
||||||
|
def test_default_nonblocking(self):
|
||||||
|
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
flags = fcntl.fcntl(sock1.fd.fileno(), fcntl.F_GETFL)
|
||||||
|
assert flags & os.O_NONBLOCK
|
||||||
|
|
||||||
|
sock2 = socket.socket(sock1.fd)
|
||||||
|
flags = fcntl.fcntl(sock2.fd.fileno(), fcntl.F_GETFL)
|
||||||
|
assert flags & os.O_NONBLOCK
|
||||||
|
|
||||||
|
def test_dup_nonblocking(self):
|
||||||
|
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
flags = fcntl.fcntl(sock1.fd.fileno(), fcntl.F_GETFL)
|
||||||
|
assert flags & os.O_NONBLOCK
|
||||||
|
|
||||||
|
sock2 = sock1.dup()
|
||||||
|
flags = fcntl.fcntl(sock2.fd.fileno(), fcntl.F_GETFL)
|
||||||
|
assert flags & os.O_NONBLOCK
|
||||||
|
|
||||||
|
def test_skip_nonblocking(self):
|
||||||
|
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
fd = sock1.fd.fileno()
|
||||||
|
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||||
|
flags = fcntl.fcntl(fd, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)
|
||||||
|
assert flags & os.O_NONBLOCK == 0
|
||||||
|
|
||||||
|
sock2 = socket.socket(sock1.fd, set_nonblocking=False)
|
||||||
|
flags = fcntl.fcntl(sock2.fd.fileno(), fcntl.F_GETFL)
|
||||||
|
assert flags & os.O_NONBLOCK == 0
|
||||||
|
|
||||||
|
|
||||||
class TestGreenPipe(LimitedTestCase):
|
class TestGreenPipe(LimitedTestCase):
|
||||||
@skip_on_windows
|
@skip_on_windows
|
||||||
@@ -821,5 +851,16 @@ class TestGreenIoStarvation(LimitedTestCase):
|
|||||||
assert maxstartdiff * 2 < runlengths[0], "Largest difference in starting times more than twice the shortest running time!"
|
assert maxstartdiff * 2 < runlengths[0], "Largest difference in starting times more than twice the shortest running time!"
|
||||||
assert runlengths[0] * 2 > runlengths[-1], "Longest runtime more than twice as long as shortest!"
|
assert runlengths[0] * 2 > runlengths[-1], "Longest runtime more than twice as long as shortest!"
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_nonblocking():
|
||||||
|
sock = _orig_sock.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
fileno = sock.fileno()
|
||||||
|
orig_flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
|
||||||
|
assert orig_flags & os.O_NONBLOCK == 0
|
||||||
|
greenio.set_nonblocking(sock)
|
||||||
|
new_flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
|
||||||
|
assert new_flags == (orig_flags | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
Reference in New Issue
Block a user