def fix_logging_module(): logging = sys.modules.get('logging') # Prevent fixing multiple times as that would cause a deadlock. if logging and getattr(logging, 'fixed_for_atfork', None): return if logging: warnings.warn('logging module already imported before fixup.') import logging if logging.getLogger().handlers: # We could register each lock with atfork for these handlers but if # these exist, other loggers or not yet added handlers could as well. # Its safer to insist that this fix is applied before logging has been # configured. raise Error('logging handlers already registered.') logging._acquireLock() try: def fork_safe_createLock(self): self._orig_createLock() atfork.atfork(self.lock.acquire, self.lock.release, self.lock.release) # Fix the logging.Handler lock (a major source of deadlocks). logging.Handler._orig_createLock = logging.Handler.createLock logging.Handler.createLock = fork_safe_createLock # Fix the module level lock. atfork.atfork(logging._acquireLock, logging._releaseLock, logging._releaseLock) logging.fixed_for_atfork = True finally: logging._releaseLock()
def _test_a_fork_wrapper(self, fork_func): sys.stderr = StringIO() # restored in tearDown atfork.atfork(self._raise_pre, self._raise_parent, self._raise_child) atfork.atfork(self._other, self._other, self._other) pid = fork_func() if pid == 0: try: try: self.assertEqual([self._pre, self._other, self._child, self._other], self.calls) self.assertFalse(atfork._fork_lock.locked()) self._assert_expected_child_stderr(sys.stderr.getvalue()) except: try: traceback.print_exc() self.orig_stderr.write(sys.stderr.getvalue()) finally: os._exit(1) finally: os._exit(0) else: self.assertEqual([self._pre, self._other, self._parent, self._other], self.calls) self.assertFalse(atfork._fork_lock.locked()) self.assertEqual(0, os.waitpid(pid, 0)[1], 'error in child') self._assert_expected_parent_stderr(sys.stderr.getvalue())
def _test_a_fork_wrapper(self, fork_func): sys.stderr = StringIO() # restored in tearDown atfork.atfork(self._raise_pre, self._raise_parent, self._raise_child) atfork.atfork(self._other, self._other, self._other) pid = fork_func() if pid == 0: try: try: self.assertEqual( [self._pre, self._other, self._child, self._other], self.calls) self.assertFalse(atfork._fork_lock.locked()) self._assert_expected_child_stderr(sys.stderr.getvalue()) except: try: traceback.print_exc() self.orig_stderr.write(sys.stderr.getvalue()) finally: os._exit(1) finally: os._exit(0) else: self.assertEqual( [self._pre, self._other, self._parent, self._other], self.calls) self.assertFalse(atfork._fork_lock.locked()) self.assertEqual(0, os.waitpid(pid, 0)[1], 'error in child') self._assert_expected_parent_stderr(sys.stderr.getvalue())
def connect_to_boss(address, port): # -- original code: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # set timeout to None since we now set a default finite timeout s.settimeout(None) s.connect((address, port)) #try: # s.connect('./picloud.sock') #except Exception as e: # print e # susceptible to race conditions # closes file descriptor on exec and fork flags = fcntl.fcntl(s, fcntl.F_GETFD) fcntl.fcntl(s, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) atfork.atfork(child=lambda: s.close()) return s
def _test_fork_failure(self, orig_fork_attrname, fork_wrapper): def failing_fork(): raise OSError(0, 'testing a fork failure') atfork.atfork(self._pre, self._parent, self._child) orig_orig_fork = getattr(atfork, orig_fork_attrname) try: setattr(atfork, orig_fork_attrname, failing_fork) try: pid = fork_wrapper() if pid == 0: # This should never happen but do this just in case. os._exit(0) except OSError: self.assertEqual([self._pre, self._parent], self.calls) else: self.fail('Fork failed to fail!') finally: setattr(atfork, orig_fork_attrname, orig_orig_fork)
def test_register_atfork_calls(self): # Test with both positional and keyword arguments as well as None. atfork.atfork(self._pre, self._parent, self._child) atfork.atfork(prepare=self._pre) atfork.atfork(parent=self._parent) atfork.atfork(child=self._child) self.assertEqual([self._pre]*2, atfork._prepare_call_list) self.assertEqual([self._parent]*2, atfork._parent_call_list) self.assertEqual([self._child]*2, atfork._child_call_list) if __debug__: self.assertRaises(AssertionError, atfork.atfork, 1, 2, 3)
def test_register_atfork_calls(self): # Test with both positional and keyword arguments as well as None. atfork.atfork(self._pre, self._parent, self._child) atfork.atfork(prepare=self._pre) atfork.atfork(parent=self._parent) atfork.atfork(child=self._child) self.assertEqual([self._pre] * 2, atfork._prepare_call_list) self.assertEqual([self._parent] * 2, atfork._parent_call_list) self.assertEqual([self._child] * 2, atfork._child_call_list) if __debug__: self.assertRaises(AssertionError, atfork.atfork, 1, 2, 3)
def fork_safe_createLock(self): self._orig_createLock() atfork.atfork(self.lock.acquire, self.lock.release, self.lock.release)