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)
|
||||
* Raymond Lu, fixing busy-wait in eventlet.green.ssl.socket.sendall()
|
||||
* 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)")
|
||||
# We managed to import fcntl.
|
||||
fileno = fd.fileno()
|
||||
flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
|
||||
fcntl.fcntl(fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
orig_flags = fcntl.fcntl(fileno, fcntl.F_GETFL)
|
||||
new_flags = orig_flags | os.O_NONBLOCK
|
||||
if new_flags != orig_flags:
|
||||
fcntl.fcntl(fileno, fcntl.F_SETFL, new_flags)
|
||||
else:
|
||||
# socket supports setblocking()
|
||||
setblocking(0)
|
||||
@@ -114,8 +116,13 @@ class GreenSocket(object):
|
||||
"""
|
||||
Green version of socket.socket class, that is intended to be 100%
|
||||
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):
|
||||
should_set_nonblocking = kwargs.pop('set_nonblocking', True)
|
||||
if isinstance(family_or_realsock, (int, long)):
|
||||
fd = _original_socket(family_or_realsock, *args, **kwargs)
|
||||
else:
|
||||
@@ -129,7 +136,8 @@ class GreenSocket(object):
|
||||
except AttributeError:
|
||||
self._timeout = socket.getdefaulttimeout()
|
||||
|
||||
set_nonblocking(fd)
|
||||
if should_set_nonblocking:
|
||||
set_nonblocking(fd)
|
||||
self.fd = fd
|
||||
# when client calls setblocking(0) or settimeout(0) the socket must
|
||||
# act non-blocking
|
||||
@@ -209,8 +217,7 @@ class GreenSocket(object):
|
||||
|
||||
def dup(self, *args, **kw):
|
||||
sock = self.fd.dup(*args, **kw)
|
||||
set_nonblocking(sock)
|
||||
newsock = type(self)(sock)
|
||||
newsock = type(self)(sock, set_nonblocking=False)
|
||||
newsock.settimeout(self.gettimeout())
|
||||
return newsock
|
||||
|
||||
|
@@ -4,12 +4,13 @@ from eventlet import event, greenio, debug
|
||||
from eventlet.hubs import get_hub
|
||||
from eventlet.green import socket, time
|
||||
from eventlet.support import get_errno
|
||||
import errno
|
||||
|
||||
import array
|
||||
import errno
|
||||
import eventlet
|
||||
import fcntl
|
||||
import os
|
||||
import sys
|
||||
import array
|
||||
import tempfile, shutil
|
||||
|
||||
|
||||
@@ -551,6 +552,35 @@ class TestGreenSocket(LimitedTestCase):
|
||||
self.assertRaises(socket.timeout, client.recv, 1)
|
||||
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):
|
||||
@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 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__':
|
||||
main()
|
||||
|
Reference in New Issue
Block a user