Statistics
| Branch: | Tag: | Revision:

root / lib / utils / wrapper.py @ b459a848

History | View | Annotate | Download (4.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21
"""Utility functions wrapping other functions.
22

23
"""
24

    
25
import time
26
import socket
27
import errno
28
import tempfile
29
import fcntl
30
import os
31
import select
32
import logging
33

    
34

    
35
def TestDelay(duration):
36
  """Sleep for a fixed amount of time.
37

38
  @type duration: float
39
  @param duration: the sleep duration
40
  @rtype: boolean
41
  @return: False for negative value, True otherwise
42

43
  """
44
  if duration < 0:
45
    return False, "Invalid sleep duration"
46
  time.sleep(duration)
47
  return True, None
48

    
49

    
50
def CloseFdNoError(fd, retries=5):
51
  """Close a file descriptor ignoring errors.
52

53
  @type fd: int
54
  @param fd: the file descriptor
55
  @type retries: int
56
  @param retries: how many retries to make, in case we get any
57
      other error than EBADF
58

59
  """
60
  try:
61
    os.close(fd)
62
  except OSError, err:
63
    if err.errno != errno.EBADF:
64
      if retries > 0:
65
        CloseFdNoError(fd, retries - 1)
66
    # else either it's closed already or we're out of retries, so we
67
    # ignore this and go on
68

    
69

    
70
def SetCloseOnExecFlag(fd, enable):
71
  """Sets or unsets the close-on-exec flag on a file descriptor.
72

73
  @type fd: int
74
  @param fd: File descriptor
75
  @type enable: bool
76
  @param enable: Whether to set or unset it.
77

78
  """
79
  flags = fcntl.fcntl(fd, fcntl.F_GETFD)
80

    
81
  if enable:
82
    flags |= fcntl.FD_CLOEXEC
83
  else:
84
    flags &= ~fcntl.FD_CLOEXEC
85

    
86
  fcntl.fcntl(fd, fcntl.F_SETFD, flags)
87

    
88

    
89
def SetNonblockFlag(fd, enable):
90
  """Sets or unsets the O_NONBLOCK flag on on a file descriptor.
91

92
  @type fd: int
93
  @param fd: File descriptor
94
  @type enable: bool
95
  @param enable: Whether to set or unset it
96

97
  """
98
  flags = fcntl.fcntl(fd, fcntl.F_GETFL)
99

    
100
  if enable:
101
    flags |= os.O_NONBLOCK
102
  else:
103
    flags &= ~os.O_NONBLOCK
104

    
105
  fcntl.fcntl(fd, fcntl.F_SETFL, flags)
106

    
107

    
108
def RetryOnSignal(fn, *args, **kwargs):
109
  """Calls a function again if it failed due to EINTR.
110

111
  """
112
  while True:
113
    try:
114
      return fn(*args, **kwargs)
115
    except EnvironmentError, err:
116
      if err.errno != errno.EINTR:
117
        raise
118
    except (socket.error, select.error), err:
119
      # In python 2.6 and above select.error is an IOError, so it's handled
120
      # above, in 2.5 and below it's not, and it's handled here.
121
      if not (err.args and err.args[0] == errno.EINTR):
122
        raise
123

    
124

    
125
def IgnoreProcessNotFound(fn, *args, **kwargs):
126
  """Ignores ESRCH when calling a process-related function.
127

128
  ESRCH is raised when a process is not found.
129

130
  @rtype: bool
131
  @return: Whether process was found
132

133
  """
134
  try:
135
    fn(*args, **kwargs)
136
  except EnvironmentError, err:
137
    # Ignore ESRCH
138
    if err.errno == errno.ESRCH:
139
      return False
140
    raise
141

    
142
  return True
143

    
144

    
145
def IgnoreSignals(fn, *args, **kwargs):
146
  """Tries to call a function ignoring failures due to EINTR.
147

148
  """
149
  try:
150
    return fn(*args, **kwargs)
151
  except EnvironmentError, err:
152
    if err.errno == errno.EINTR:
153
      return None
154
    else:
155
      raise
156
  except (select.error, socket.error), err:
157
    # In python 2.6 and above select.error is an IOError, so it's handled
158
    # above, in 2.5 and below it's not, and it's handled here.
159
    if err.args and err.args[0] == errno.EINTR:
160
      return None
161
    else:
162
      raise
163

    
164

    
165
def GetClosedTempfile(*args, **kwargs):
166
  """Creates a temporary file and returns its path.
167

168
  """
169
  (fd, path) = tempfile.mkstemp(*args, **kwargs)
170
  CloseFdNoError(fd)
171
  return path
172

    
173

    
174
def ResetTempfileModule():
175
  """Resets the random name generator of the tempfile module.
176

177
  This function should be called after C{os.fork} in the child process to
178
  ensure it creates a newly seeded random generator. Otherwise it would
179
  generate the same random parts as the parent process. If several processes
180
  race for the creation of a temporary file, this could lead to one not getting
181
  a temporary name.
182

183
  """
184
  # pylint: disable=W0212
185
  if hasattr(tempfile, "_once_lock") and hasattr(tempfile, "_name_sequence"):
186
    tempfile._once_lock.acquire()
187
    try:
188
      # Reset random name generator
189
      tempfile._name_sequence = None
190
    finally:
191
      tempfile._once_lock.release()
192
  else:
193
    logging.critical("The tempfile module misses at least one of the"
194
                     " '_once_lock' and '_name_sequence' attributes")