Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions uvloop/handles/process.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,28 @@ cdef class UVProcess(UVHandle):
self._abort_init()
raise

if __forking or loop.active_process_handler is not None:
# Our pthread_atfork handlers won't work correctly when
# another loop is forking in another thread (even though
# GIL should help us to avoid that.)
# Acquire the global spawn lock to serialize process spawning
# across threads. Without this, concurrent spawns from different
# loops would race on the global pthread_atfork handlers.
__spawn_lock.acquire()
_spawn_lock_held = True

if loop.active_process_handler is not None:
__spawn_lock.release()
_spawn_lock_held = False
self._abort_init()
raise RuntimeError(
'Racing with another loop to spawn a process.')

self._errpipe_read, self._errpipe_write = os_pipe()
fds_to_close = self._fds_to_close
self._fds_to_close = None
fds_to_close.append(self._errpipe_read)
# add the write pipe last so we can close it early
fds_to_close.append(self._errpipe_write)
'Racing with the same loop to spawn a process.')

fds_to_close = None
try:
self._errpipe_read, self._errpipe_write = os_pipe()
fds_to_close = self._fds_to_close
self._fds_to_close = None
fds_to_close.append(self._errpipe_read)
# add the write pipe last so we can close it early
fds_to_close.append(self._errpipe_write)

os_set_inheritable(self._errpipe_write, True)

self._preexec_fn = preexec_fn
Expand All @@ -103,6 +110,8 @@ cdef class UVProcess(UVHandle):
__forking_loop = None
system.resetForkHandler()
loop.active_process_handler = None
__spawn_lock.release()
_spawn_lock_held = False

PyOS_AfterFork_Parent()

Expand All @@ -128,8 +137,16 @@ cdef class UVProcess(UVHandle):
break

finally:
while fds_to_close:
os_close(fds_to_close.pop())
if _spawn_lock_held:
__forking = 0
__forking_loop = None
system.resetForkHandler()
loop.active_process_handler = None
__spawn_lock.release()

if fds_to_close is not None:
while fds_to_close:
os_close(fds_to_close.pop())

for fd in restore_inheritable:
os_set_inheritable(fd, False)
Expand Down
2 changes: 2 additions & 0 deletions uvloop/loop.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ from cpython cimport (
from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer

from . import _noop
import threading
__spawn_lock = threading.Lock()


include "includes/stdlib.pxi"
Expand Down
Loading