Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gevent
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gevent
Commits
4b59a304
Commit
4b59a304
authored
Jul 07, 2015
by
Jason Madden
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Apply the FORKCHECK flag to make libev notice forks when multiple threads are in use.
parent
ef6c7df2
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
63 additions
and
10 deletions
+63
-10
changelog.rst
changelog.rst
+2
-0
gevent/core.ppyx
gevent/core.ppyx
+1
-0
gevent/corecffi.py
gevent/corecffi.py
+1
-0
gevent/hub.py
gevent/hub.py
+17
-10
greentest/test__core_fork.py
greentest/test__core_fork.py
+42
-0
No files found.
changelog.rst
View file @
4b59a304
...
...
@@ -49,6 +49,8 @@ Unreleased
forked child process, such as with ``multiprocessing.Process``.
Previously the child process would hang indefinitely. Reported in
:issue:`230` by Lx Yu.
- Fork watchers are more likely to (eventually) get called in a
multi-threaded program.
1.1a1 (Jun 29, 2015)
====================
...
...
gevent/core.ppyx
View file @
4b59a304
...
...
@@ -270,6 +270,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
c_flags = _flags_to_int(flags)
_check_flags(c_flags)
c_flags |= libev.EVFLAG_NOENV
c_flags |= libev.EVFLAG_FORKCHECK
if default is None:
default = True
if _default_loop_destroyed:
...
...
gevent/corecffi.py
View file @
4b59a304
...
...
@@ -549,6 +549,7 @@ class loop(object):
c_flags
=
_flags_to_int
(
flags
)
_check_flags
(
c_flags
)
c_flags
|=
libev
.
EVFLAG_NOENV
c_flags
|=
libev
.
EVFLAG_FORKCHECK
if
default
is
None
:
default
=
True
if
_default_loop_destroyed
:
...
...
gevent/hub.py
View file @
4b59a304
...
...
@@ -153,16 +153,23 @@ def reinit():
hub
=
_get_hub
()
if
hub
is
not
None
:
hub
.
loop
.
reinit
()
# XXX: libev's fork watchers seem not to be firing for some reason
# in both the cython (core.ppyx) and CFFI (corecffi.py) implementations
# (at least on OS X; confirm on other platforms)
# This breaks the threadpool and anything that uses it, including
# resolver_thread in the forked process (if there was already one thread
# in the pool before fork, adding an additional task will hang forever post-fork)
# The below is a kludge. The correct fix is to figure out why the fork watchers
# don't work. Fortunately, both of these methods are idempotent and can be called
# multiple times following a fork if the suddenly started working, or were already
# working on some platforms.
# libev's fork watchers are slow to fire because the only fire
# at the beginning of a loop; due to our use of callbacks that
# run at the end of the loop, that may be too late. The
# threadpool and resolvers depend on the fork handlers being
# run ( specifically, the threadpool will fail in the forked
# child if there were any threads in it, which there will be
# if the resolver_thread was in use (the default) before the
# fork.)
#
# If the forked process wants to use the threadpool or
# resolver immediately, it would hang.
#
# The below is a workaround. Fortunately, both of these
# methods are idempotent and can be called multiple times
# following a fork if the suddenly started working, or were
# already working on some platforms. Other threadpools and fork handlers
# will be called at an arbitrary time later ('soon')
if
hasattr
(
hub
.
threadpool
,
'_on_fork'
):
hub
.
threadpool
.
_on_fork
()
# resolver_ares also has a fork watcher that's not firing
...
...
greentest/test__core_fork.py
0 → 100644
View file @
4b59a304
from
__future__
import
print_function
import
gevent.monkey
;
gevent
.
monkey
.
patch_all
()
import
gevent
import
os
hub
=
gevent
.
get_hub
()
pid
=
os
.
getpid
()
newpid
=
None
def
on_fork
():
global
newpid
newpid
=
os
.
getpid
()
fork_watcher
=
hub
.
loop
.
fork
(
ref
=
False
)
fork_watcher
.
start
(
on_fork
)
# fork watchers weren't firing in multi-threading processes.
def
run
():
# libev only calls fork callbacks at the beginning of
# the loop; we use callbacks extensively so it takes *two*
# calls to sleep (with a timer) to actually get wrapped
# around to the beginning of the loop.
gevent
.
sleep
(
0.01
)
gevent
.
sleep
(
0.01
)
q
.
put
(
newpid
)
import
multiprocessing
# Use a thread to make us multi-threaded
hub
.
threadpool
.
apply
(
lambda
:
None
)
q
=
multiprocessing
.
Queue
()
p
=
multiprocessing
.
Process
(
target
=
run
)
p
.
start
()
p_val
=
q
.
get
()
p
.
join
()
assert
p_val
is
not
None
assert
p_val
!=
pid
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment