4 # Copyright (C) 2006, 2007, 2010, 2011, 2012 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 """Utility functions wrapping other functions.
36 def TestDelay(duration):
37 """Sleep for a fixed amount of time.
40 @param duration: the sleep duration, in seconds
41 @rtype: (boolean, str)
42 @return: False for negative value, and an accompanying error message;
43 True otherwise (and msg is None)
47 return False, "Invalid sleep duration"
52 def CloseFdNoError(fd, retries=5):
53 """Close a file descriptor ignoring errors.
56 @param fd: the file descriptor
58 @param retries: how many retries to make, in case we get any
59 other error than EBADF
65 if err.errno != errno.EBADF:
67 CloseFdNoError(fd, retries - 1)
68 # else either it's closed already or we're out of retries, so we
69 # ignore this and go on
72 def SetCloseOnExecFlag(fd, enable):
73 """Sets or unsets the close-on-exec flag on a file descriptor.
76 @param fd: File descriptor
78 @param enable: Whether to set or unset it.
81 flags = fcntl.fcntl(fd, fcntl.F_GETFD)
84 flags |= fcntl.FD_CLOEXEC
86 flags &= ~fcntl.FD_CLOEXEC
88 fcntl.fcntl(fd, fcntl.F_SETFD, flags)
91 def SetNonblockFlag(fd, enable):
92 """Sets or unsets the O_NONBLOCK flag on on a file descriptor.
95 @param fd: File descriptor
97 @param enable: Whether to set or unset it
100 flags = fcntl.fcntl(fd, fcntl.F_GETFL)
103 flags |= os.O_NONBLOCK
105 flags &= ~os.O_NONBLOCK
107 fcntl.fcntl(fd, fcntl.F_SETFL, flags)
110 def RetryOnSignal(fn, *args, **kwargs):
111 """Calls a function again if it failed due to EINTR.
116 return fn(*args, **kwargs)
117 except EnvironmentError, err:
118 if err.errno != errno.EINTR:
120 except (socket.error, select.error), err:
121 # In python 2.6 and above select.error is an IOError, so it's handled
122 # above, in 2.5 and below it's not, and it's handled here.
123 if not (err.args and err.args[0] == errno.EINTR):
127 def IgnoreProcessNotFound(fn, *args, **kwargs):
128 """Ignores ESRCH when calling a process-related function.
130 ESRCH is raised when a process is not found.
133 @return: Whether process was found
138 except EnvironmentError, err:
140 if err.errno == errno.ESRCH:
147 def IgnoreSignals(fn, *args, **kwargs):
148 """Tries to call a function ignoring failures due to EINTR.
152 return fn(*args, **kwargs)
153 except EnvironmentError, err:
154 if err.errno == errno.EINTR:
158 except (select.error, socket.error), err:
159 # In python 2.6 and above select.error is an IOError, so it's handled
160 # above, in 2.5 and below it's not, and it's handled here.
161 if err.args and err.args[0] == errno.EINTR:
167 def GetClosedTempfile(*args, **kwargs):
168 """Creates a temporary file and returns its path.
171 (fd, path) = tempfile.mkstemp(*args, **kwargs)
176 def IsExecutable(filename):
177 """Checks whether a file exists and is executable.
179 @type filename: string
180 @param filename: Filename
184 return os.path.isfile(filename) and os.access(filename, os.X_OK)
187 def ResetTempfileModule(_time=time.time):
188 """Resets the random name generator of the tempfile module.
190 This function should be called after C{os.fork} in the child process to
191 ensure it creates a newly seeded random generator. Otherwise it would
192 generate the same random parts as the parent process. If several processes
193 race for the creation of a temporary file, this could lead to one not getting
197 # pylint: disable=W0212
198 if ((sys.hexversion >= 0x020703F0 and sys.hexversion < 0x03000000) or
199 sys.hexversion >= 0x030203F0):
200 # Python 2.7 automatically resets the RNG on pid changes (i.e. forking)
204 lock = tempfile._once_lock
207 # Re-seed random name generator
208 if tempfile._name_sequence:
209 tempfile._name_sequence.rng.seed(hash(_time()) ^ os.getpid())
212 except AttributeError:
213 logging.critical("The tempfile module misses at least one of the"
214 " '_once_lock' and '_name_sequence' attributes")