Commits

Jan-Philip Gehrcke committed 23e54ec

Consolidate handle processing.

Comments (0)

Files changed (1)

     r, w = os.pipe()
     reader = _GIPCReader(r)
     writer = _GIPCWriter(w)
-    _all_handles.append(reader)
-    _all_handles.append(writer)
     return _HandlePairContext((reader, writer))
 
 
     state is reset before running the user-given function.
     """
     log.debug("_child start. target: `%s`" % target)
+    allargs = itertools.chain(args, kwargs.values())
+    childhandles = [a for a in allargs if isinstance(a, _GIPCHandle)]
     if not WINDOWS:
         # `gevent.reinit` calls `libev.ev_loop_fork()`, which reinitialises
         # the kernel state for backends that have one. Must be called in the
         h = gevent.get_hub(default=True)
         log.debug("Created new hub and default event loop.")
         assert h.loop.default, 'Could not create libev default event loop.'
-    allargs = itertools.chain(args, kwargs.values())
-    childhandles = [a for a in allargs if isinstance(a, _GIPCHandle)]
-    set_all_handles(childhandles)
-    # Register inherited handles for current process. Close those that are not
-    # intended for further usage.
+        # On Unix, file descriptors are inherited by default. Also, the global
+        # `_all_handles` is inherited from the parent. Close dispensable file
+        # descriptors in child.
+        for h in _all_handles[:]:
+            if not h in childhandles:
+                log.debug("Invalidate %s in child." % h)
+                h._set_legit_process()
+                h.close()
+    else:
+        # On Windows, the state of module globals is not transferred to
+        # children. Set `_all_handles`.
+        set_all_handles(childhandles)
+    # `_all_handles` now must contain only those handles that have been
+    # transferred to the child on purpose.
+    for h in _all_handles:
+        assert h in childhandles
+    # Register transferred handles for current process.
     for h in childhandles:
         h._set_legit_process()
         if WINDOWS:
             h._post_createprocess_windows()
-        #if not h in childhandles:
-        #    log.debug("Invalidate %s in child." % h)
-        #    h.close()
-        #    continue
-        log.debug("Handle `%s` is valid in child." % h)
+        log.debug("Handle `%s` is now valid in child." % h)
     target(*args, **kwargs)
     for h in childhandles:
         try:
-            # The user or a child of this child might already have closed it.
+            # The user might already have closed it.
             h.close()
         except GIPCClosed:
             pass
 
     .. todo::
 
-        Care about destructor?
+        Implement destructor?
         http://eli.thegreenplace.net/2009/06/12/
         safely-using-destructors-in-python/
     """
     def __init__(self):
+        global _all_handles
         self._id = os.urandom(3).encode("hex")
         self._legit_pid = os.getpid()
         self._make_nonblocking()
         self._lock = gevent.lock.Semaphore(value=1)
         self._closed = False
+        _all_handles.append(self)
 
     def _make_nonblocking(self):
         if hasattr(gevent.os, 'make_nonblocking'):
             raise GIPCLocked(
                 "Can't close handle %s: locked for I/O operation." % self)
         log.debug("Invalidating %s ..." % self)
-        self._closed = True
         if self._fd is not None:
             os.close(self._fd)
             self._fd = None
         if self in _all_handles:
             # Remove the handle from the global list of valid handles.
             _all_handles.remove(self)
+        self._closed = True
         self._lock.release()
 
     def _set_legit_process(self):
             self._fd = False
 
     def _post_createprocess_windows(self):
-        """Restore file descriptor on Windows."""
+        """Restore file descriptor on Windows.
+        """
         if WINDOWS:
             # Get C file descriptor from Windows file handle.
             self._fd = msvcrt.open_osfhandle(self._ihfd, self._fd_flag)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.