Commit f23135ea authored by Martín Ferrari's avatar Martín Ferrari

Moved the EINTR wrapper into environ, and replaced the many copies of the same...

Moved the EINTR wrapper into environ, and replaced the many copies of the same code scattered around the code. Also made it catch both IOError and OSerror.
parent 103e5496
......@@ -4,7 +4,7 @@ from syslog import LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG
__all__ = ["ip_path", "tc_path", "brctl_path", "sysctl_path", "hz"]
__all__ += ["tcpdump_path", "netperf_path", "xauth_path", "xdpyinfo_path"]
__all__ += ["execute", "backticks"]
__all__ += ["execute", "backticks", "eintr_wrapper"]
__all__ += ["find_listen_port"]
__all__ += ["LOG_ERR", "LOG_WARNING", "LOG_NOTICE", "LOG_INFO", "LOG_DEBUG"]
__all__ += ["set_log_level", "logger"]
......@@ -74,6 +74,20 @@ def backticks(cmd):
raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
return out
def eintr_wrapper(f, *args):
"Wraps some callable with a loop that retries on EINTR."
while True:
try:
return f(*args)
except OSError, e: # pragma: no cover
if e.errno == errno.EINTR:
continue
raise
except IOError, e: # pragma: no cover
if e.errno == errno.EINTR:
continue
raise
def find_listen_port(family = socket.AF_INET, type = socket.SOCK_STREAM,
proto = 0, addr = "127.0.0.1", min_port = 1, max_port = 65535):
s = socket.socket(family, type, proto)
......@@ -133,15 +147,8 @@ def logger(priority, message):
if priority > _log_level:
return
while True:
try:
_log_stream.write("[%d] %s\n" % (os.getpid(), message.rstrip()))
except OSError, e: # pragma: no cover
if e.errno == errno.EINTR:
continue
else:
raise
break
eintr_wrapper(_log_stream.write,
"[%d] %s\n" % (os.getpid(), message.rstrip()))
_log_stream.flush()
def error(message):
......
......@@ -60,16 +60,7 @@ class Node(object):
if self._slave:
self._slave.shutdown()
while True:
try:
exitcode = os.waitpid(self._pid, 0)[1]
except OSError, e: # pragma: no cover
if e.errno == errno.EINTR:
continue
else:
raise
break
exitcode = eintr_wrapper(os.waitpid, self._pid, 0)[1]
if exitcode != 0:
error("Node(0x%x) process %d exited with non-zero status: %d" %
(id(self), self._pid, exitcode))
......
......@@ -149,8 +149,8 @@ class Server(object):
def readline(self):
"Read a line from the socket and detect connection break-up."
# FIXME: should use the _eintr_wrapper from subprocess: some
# reorganization needed first.
# FIXME: should use the eintr_wrapper from environ; why was I using
# readline instead of read?
while True:
try:
line = self._rfd.readline()
......@@ -552,13 +552,7 @@ class Client(object):
raise RuntimeError("Client already shut down.")
text = []
while True:
try:
line = self._rfd.readline().rstrip()
except IOError, e:
if e.errno == errno.EINTR:
continue
else:
raise e
line = eintr_wrapper(self._rfd.readline).rstrip()
if not line:
raise RuntimeError("Protocol error, empty line received")
......
# vim:ts=4:sw=4:et:ai:sts=4
import errno, fcntl, grp, os, pickle, pwd, signal, select, sys, time, traceback
import fcntl, grp, os, pickle, pwd, signal, select, sys, time, traceback
from netns.environ import eintr_wrapper
__all__ = [ 'PIPE', 'STDOUT', 'Popen', 'Subprocess', 'spawn', 'wait', 'poll',
'get_user', 'system', 'backticks', 'backticks_raise' ]
......@@ -167,7 +168,7 @@ class Popen(Subprocess):
# Close pipes, they have been dup()ed to the child
for k, v in fdmap.items():
if getattr(self, k) != None:
_eintr_wrapper(os.close, v)
eintr_wrapper(os.close, v)
def communicate(self, input = None):
"""See Popen.communicate."""
......@@ -296,10 +297,10 @@ def spawn(executable, argv = None, cwd = None, env = None, close_fds = False,
if userfd[i] != None and userfd[i] >= 0:
os.dup2(userfd[i], i)
if userfd[i] != i and userfd[i] not in userfd[0:i]:
_eintr_wrapper(os.close, userfd[i]) # only in child!
eintr_wrapper(os.close, userfd[i]) # only in child!
# Set up special control pipe
_eintr_wrapper(os.close, r)
eintr_wrapper(os.close, r)
flags = fcntl.fcntl(w, fcntl.F_GETFD)
fcntl.fcntl(w, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
......@@ -345,29 +346,29 @@ def spawn(executable, argv = None, cwd = None, env = None, close_fds = False,
# subprocess.py
v.child_traceback = "".join(
traceback.format_exception(t, v, tb))
_eintr_wrapper(os.write, w, pickle.dumps(v))
_eintr_wrapper(os.close, w)
eintr_wrapper(os.write, w, pickle.dumps(v))
eintr_wrapper(os.close, w)
#traceback.print_exc()
except:
traceback.print_exc()
os._exit(1)
_eintr_wrapper(os.close, w)
eintr_wrapper(os.close, w)
# read EOF for success, or a string as error info
s = ""
while True:
s1 = _eintr_wrapper(os.read, r, 4096)
s1 = eintr_wrapper(os.read, r, 4096)
if s1 == "":
break
s += s1
_eintr_wrapper(os.close, r)
eintr_wrapper(os.close, r)
if s == "":
return pid
# It was an error
_eintr_wrapper(os.waitpid, pid, 0)
eintr_wrapper(os.waitpid, pid, 0)
exc = pickle.loads(s)
# XXX: sys.excepthook
#print exc.child_traceback
......@@ -383,7 +384,7 @@ def poll(pid):
def wait(pid):
"""Wait for process to die and return the exit code."""
return _eintr_wrapper(os.waitpid, pid, 0)[1]
return eintr_wrapper(os.waitpid, pid, 0)[1]
def get_user(user):
"Take either an username or an uid, and return a tuple (user, uid, gid)."
......@@ -403,17 +404,6 @@ def get_user(user):
# internal stuff, do not look!
def _eintr_wrapper(f, *args):
"Wraps some callable with a loop that retries on EINTR"
while True:
try:
return f(*args)
except OSError, e: # pragma: no cover
if e.errno == errno.EINTR:
continue
else:
raise
try:
MAXFD = os.sysconf("SC_OPEN_MAX")
except: # pragma: no cover
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment