Revision 232144d0

b/lib/daemon.py
94 94

  
95 95
  # this method is overriding an asyncore.dispatcher method
96 96
  def handle_read(self):
97
    try:
98
      payload, address = self.recvfrom(constants.MAX_UDP_DATA_SIZE)
99
    except socket.error, err:
100
      if err.errno == errno.EINTR:
101
        # we got a signal while trying to read. no need to do anything,
102
        # handle_read will be called again if there is data on the socket.
103
        return
104
      else:
105
        raise
97
    payload, address = utils.IgnoreSignals(self.recvfrom,
98
                                           constants.MAX_UDP_DATA_SIZE)
106 99
    ip, port = address
107 100
    self.handle_datagram(payload, ip, port)
108 101

  
......
124 117
      logging.error("handle_write called with empty output queue")
125 118
      return
126 119
    (ip, port, payload) = self._out_queue[0]
127
    try:
128
      self.sendto(payload, 0, (ip, port))
129
    except socket.error, err:
130
      if err.errno == errno.EINTR:
131
        # we got a signal while trying to write. no need to do anything,
132
        # handle_write will be called again because we haven't emptied the
133
        # _out_queue, and we'll try again
134
        return
135
      else:
136
        raise
120
    utils.IgnoreSignals(self.sendto, payload, 0, (ip, port))
137 121
    self._out_queue.pop(0)
138 122

  
139 123
  # this method is overriding an asyncore.dispatcher method
b/lib/utils.py
2507 2507
  return bool(exitcode)
2508 2508

  
2509 2509

  
2510
def IgnoreSignals(fn, *args, **kwargs):
2511
  """Tries to call a function ignoring failures due to EINTR.
2512

  
2513
  """
2514
  try:
2515
    return fn(*args, **kwargs)
2516
  except (EnvironmentError, socket.error), err:
2517
    if err.errno != errno.EINTR:
2518
      raise
2519
  except select.error, err:
2520
    if not (err.args and err.args[0] == errno.EINTR):
2521
      raise
2522

  
2523

  
2510 2524
def LockedMethod(fn):
2511 2525
  """Synchronized object access decorator.
2512 2526

  
b/test/ganeti.utils_unittest.py
39 39
import distutils.version
40 40
import glob
41 41
import md5
42
import errno
42 43

  
43 44
import ganeti
44 45
import testutils
......
1822 1823
                             "", "x"])
1823 1824

  
1824 1825

  
1826
class TestIgnoreSignals(unittest.TestCase):
1827
  """Test the IgnoreSignals decorator"""
1828

  
1829
  @staticmethod
1830
  def _Raise(exception):
1831
    raise exception
1832

  
1833
  @staticmethod
1834
  def _Return(rval):
1835
    return rval
1836

  
1837
  def testIgnoreSignals(self):
1838
    sock_err_intr = socket.error(errno.EINTR, "Message")
1839
    sock_err_intr.errno = errno.EINTR
1840
    sock_err_inval = socket.error(errno.EINVAL, "Message")
1841
    sock_err_inval.errno = errno.EINVAL
1842

  
1843
    env_err_intr = EnvironmentError(errno.EINTR, "Message")
1844
    env_err_inval = EnvironmentError(errno.EINVAL, "Message")
1845

  
1846
    self.assertRaises(socket.error, self._Raise, sock_err_intr)
1847
    self.assertRaises(socket.error, self._Raise, sock_err_inval)
1848
    self.assertRaises(EnvironmentError, self._Raise, env_err_intr)
1849
    self.assertRaises(EnvironmentError, self._Raise, env_err_inval)
1850

  
1851
    self.assertEquals(utils.IgnoreSignals(self._Raise, sock_err_intr), None)
1852
    self.assertEquals(utils.IgnoreSignals(self._Raise, env_err_intr), None)
1853
    self.assertRaises(socket.error, utils.IgnoreSignals, self._Raise,
1854
                      sock_err_inval)
1855
    self.assertRaises(EnvironmentError, utils.IgnoreSignals, self._Raise,
1856
                      env_err_inval)
1857

  
1858
    self.assertEquals(utils.IgnoreSignals(self._Return, True), True)
1859
    self.assertEquals(utils.IgnoreSignals(self._Return, 33), 33)
1860

  
1861

  
1825 1862
if __name__ == '__main__':
1826 1863
  testutils.GanetiTestProgram()

Also available in: Unified diff