Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
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
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
5be45a61
Commit
5be45a61
authored
Mar 08, 2019
by
Eric Snow
Committed by
GitHub
Mar 08, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-33608: Minor cleanup related to pending calls. (gh-12247)
parent
7bda9de5
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
81 additions
and
68 deletions
+81
-68
Include/internal/pycore_ceval.h
Include/internal/pycore_ceval.h
+0
-1
Include/internal/pycore_pystate.h
Include/internal/pycore_pystate.h
+4
-0
Python/ceval.c
Python/ceval.c
+48
-32
Python/pylifecycle.c
Python/pylifecycle.c
+1
-0
Python/pystate.c
Python/pystate.c
+28
-35
No files found.
Include/internal/pycore_ceval.h
View file @
5be45a61
...
@@ -12,7 +12,6 @@ extern "C" {
...
@@ -12,7 +12,6 @@ extern "C" {
#include "pythread.h"
#include "pythread.h"
struct
_pending_calls
{
struct
_pending_calls
{
unsigned
long
main_thread
;
PyThread_type_lock
lock
;
PyThread_type_lock
lock
;
/* Request for running pending calls. */
/* Request for running pending calls. */
_Py_atomic_int
calls_to_do
;
_Py_atomic_int
calls_to_do
;
...
...
Include/internal/pycore_pystate.h
View file @
5be45a61
...
@@ -31,6 +31,8 @@ struct _is {
...
@@ -31,6 +31,8 @@ struct _is {
int64_t
id_refcount
;
int64_t
id_refcount
;
PyThread_type_lock
id_mutex
;
PyThread_type_lock
id_mutex
;
int
finalizing
;
PyObject
*
modules
;
PyObject
*
modules
;
PyObject
*
modules_by_index
;
PyObject
*
modules_by_index
;
PyObject
*
sysdict
;
PyObject
*
sysdict
;
...
@@ -207,6 +209,8 @@ typedef struct pyruntimestate {
...
@@ -207,6 +209,8 @@ typedef struct pyruntimestate {
struct
_xidregitem
*
head
;
struct
_xidregitem
*
head
;
}
xidregistry
;
}
xidregistry
;
unsigned
long
main_thread
;
#define NEXITFUNCS 32
#define NEXITFUNCS 32
void
(
*
exitfuncs
[
NEXITFUNCS
])(
void
);
void
(
*
exitfuncs
[
NEXITFUNCS
])(
void
);
int
nexitfuncs
;
int
nexitfuncs
;
...
...
Python/ceval.c
View file @
5be45a61
...
@@ -174,9 +174,11 @@ PyEval_InitThreads(void)
...
@@ -174,9 +174,11 @@ PyEval_InitThreads(void)
PyThread_init_thread
();
PyThread_init_thread
();
create_gil
();
create_gil
();
take_gil
(
_PyThreadState_GET
());
take_gil
(
_PyThreadState_GET
());
_PyRuntime
.
ceval
.
pending
.
main_thread
=
PyThread_get_thread_ident
();
// Set it to the ID of the main thread of the main interpreter.
if
(
!
_PyRuntime
.
ceval
.
pending
.
lock
)
_PyRuntime
.
main_thread
=
PyThread_get_thread_ident
();
if
(
!
_PyRuntime
.
ceval
.
pending
.
lock
)
{
_PyRuntime
.
ceval
.
pending
.
lock
=
PyThread_allocate_lock
();
_PyRuntime
.
ceval
.
pending
.
lock
=
PyThread_allocate_lock
();
}
}
}
void
void
...
@@ -243,9 +245,9 @@ PyEval_ReInitThreads(void)
...
@@ -243,9 +245,9 @@ PyEval_ReInitThreads(void)
if
(
!
gil_created
())
if
(
!
gil_created
())
return
;
return
;
recreate_gil
();
recreate_gil
();
_PyRuntime
.
ceval
.
pending
.
lock
=
PyThread_allocate_lock
();
take_gil
(
current_tstate
);
take_gil
(
current_tstate
);
_PyRuntime
.
ceval
.
pending
.
main_thread
=
PyThread_get_thread_ident
();
_PyRuntime
.
main_thread
=
PyThread_get_thread_ident
();
_PyRuntime
.
ceval
.
pending
.
lock
=
PyThread_allocate_lock
();
/* Destroy all threads except the current one */
/* Destroy all threads except the current one */
_PyThreadState_DeleteExcept
(
current_tstate
);
_PyThreadState_DeleteExcept
(
current_tstate
);
...
@@ -323,6 +325,35 @@ _PyEval_SignalReceived(void)
...
@@ -323,6 +325,35 @@ _PyEval_SignalReceived(void)
SIGNAL_PENDING_SIGNALS
();
SIGNAL_PENDING_SIGNALS
();
}
}
/* Push one item onto the queue while holding the lock. */
static
int
_push_pending_call
(
int
(
*
func
)(
void
*
),
void
*
arg
)
{
int
i
=
_PyRuntime
.
ceval
.
pending
.
last
;
int
j
=
(
i
+
1
)
%
NPENDINGCALLS
;
if
(
j
==
_PyRuntime
.
ceval
.
pending
.
first
)
{
return
-
1
;
/* Queue full */
}
_PyRuntime
.
ceval
.
pending
.
calls
[
i
].
func
=
func
;
_PyRuntime
.
ceval
.
pending
.
calls
[
i
].
arg
=
arg
;
_PyRuntime
.
ceval
.
pending
.
last
=
j
;
return
0
;
}
/* Pop one item off the queue while holding the lock. */
static
void
_pop_pending_call
(
int
(
**
func
)(
void
*
),
void
**
arg
)
{
int
i
=
_PyRuntime
.
ceval
.
pending
.
first
;
if
(
i
==
_PyRuntime
.
ceval
.
pending
.
last
)
{
return
;
/* Queue empty */
}
*
func
=
_PyRuntime
.
ceval
.
pending
.
calls
[
i
].
func
;
*
arg
=
_PyRuntime
.
ceval
.
pending
.
calls
[
i
].
arg
;
_PyRuntime
.
ceval
.
pending
.
first
=
(
i
+
1
)
%
NPENDINGCALLS
;
}
/* This implementation is thread-safe. It allows
/* This implementation is thread-safe. It allows
scheduling to be made from any thread, and even from an executing
scheduling to be made from any thread, and even from an executing
callback.
callback.
...
@@ -331,7 +362,6 @@ _PyEval_SignalReceived(void)
...
@@ -331,7 +362,6 @@ _PyEval_SignalReceived(void)
int
int
Py_AddPendingCall
(
int
(
*
func
)(
void
*
),
void
*
arg
)
Py_AddPendingCall
(
int
(
*
func
)(
void
*
),
void
*
arg
)
{
{
int
i
,
j
,
result
=
0
;
PyThread_type_lock
lock
=
_PyRuntime
.
ceval
.
pending
.
lock
;
PyThread_type_lock
lock
=
_PyRuntime
.
ceval
.
pending
.
lock
;
/* try a few times for the lock. Since this mechanism is used
/* try a few times for the lock. Since this mechanism is used
...
@@ -346,6 +376,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
...
@@ -346,6 +376,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
* this function is called before any bytecode evaluation takes place.
* this function is called before any bytecode evaluation takes place.
*/
*/
if
(
lock
!=
NULL
)
{
if
(
lock
!=
NULL
)
{
int
i
;
for
(
i
=
0
;
i
<
100
;
i
++
)
{
for
(
i
=
0
;
i
<
100
;
i
++
)
{
if
(
PyThread_acquire_lock
(
lock
,
NOWAIT_LOCK
))
if
(
PyThread_acquire_lock
(
lock
,
NOWAIT_LOCK
))
break
;
break
;
...
@@ -354,15 +385,8 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
...
@@ -354,15 +385,8 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
return
-
1
;
return
-
1
;
}
}
i
=
_PyRuntime
.
ceval
.
pending
.
last
;
int
result
=
_push_pending_call
(
func
,
arg
);
j
=
(
i
+
1
)
%
NPENDINGCALLS
;
if
(
j
==
_PyRuntime
.
ceval
.
pending
.
first
)
{
result
=
-
1
;
/* Queue full */
}
else
{
_PyRuntime
.
ceval
.
pending
.
calls
[
i
].
func
=
func
;
_PyRuntime
.
ceval
.
pending
.
calls
[
i
].
arg
=
arg
;
_PyRuntime
.
ceval
.
pending
.
last
=
j
;
}
/* signal main loop */
/* signal main loop */
SIGNAL_PENDING_CALLS
();
SIGNAL_PENDING_CALLS
();
if
(
lock
!=
NULL
)
if
(
lock
!=
NULL
)
...
@@ -373,10 +397,10 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
...
@@ -373,10 +397,10 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
static
int
static
int
handle_signals
(
void
)
handle_signals
(
void
)
{
{
/* Only handle signals on main thread.
*/
/* Only handle signals on main thread.
PyEval_InitThreads must
if
(
_PyRuntime
.
ceval
.
pending
.
main_thread
&&
* have been called already.
PyThread_get_thread_ident
()
!=
_PyRuntime
.
ceval
.
pending
.
main_thread
)
*/
{
if
(
PyThread_get_thread_ident
()
!=
_PyRuntime
.
main_thread
)
{
return
0
;
return
0
;
}
}
/*
/*
...
@@ -401,9 +425,7 @@ make_pending_calls(void)
...
@@ -401,9 +425,7 @@ make_pending_calls(void)
static
int
busy
=
0
;
static
int
busy
=
0
;
/* only service pending calls on main thread */
/* only service pending calls on main thread */
if
(
_PyRuntime
.
ceval
.
pending
.
main_thread
&&
if
(
PyThread_get_thread_ident
()
!=
_PyRuntime
.
main_thread
)
{
PyThread_get_thread_ident
()
!=
_PyRuntime
.
ceval
.
pending
.
main_thread
)
{
return
0
;
return
0
;
}
}
...
@@ -428,24 +450,18 @@ make_pending_calls(void)
...
@@ -428,24 +450,18 @@ make_pending_calls(void)
/* perform a bounded number of calls, in case of recursion */
/* perform a bounded number of calls, in case of recursion */
for
(
int
i
=
0
;
i
<
NPENDINGCALLS
;
i
++
)
{
for
(
int
i
=
0
;
i
<
NPENDINGCALLS
;
i
++
)
{
int
j
;
int
(
*
func
)(
void
*
)
=
NULL
;
int
(
*
func
)(
void
*
);
void
*
arg
=
NULL
;
void
*
arg
=
NULL
;
/* pop one item off the queue while holding the lock */
/* pop one item off the queue while holding the lock */
PyThread_acquire_lock
(
_PyRuntime
.
ceval
.
pending
.
lock
,
WAIT_LOCK
);
PyThread_acquire_lock
(
_PyRuntime
.
ceval
.
pending
.
lock
,
WAIT_LOCK
);
j
=
_PyRuntime
.
ceval
.
pending
.
first
;
_pop_pending_call
(
&
func
,
&
arg
);
if
(
j
==
_PyRuntime
.
ceval
.
pending
.
last
)
{
func
=
NULL
;
/* Queue empty */
}
else
{
func
=
_PyRuntime
.
ceval
.
pending
.
calls
[
j
].
func
;
arg
=
_PyRuntime
.
ceval
.
pending
.
calls
[
j
].
arg
;
_PyRuntime
.
ceval
.
pending
.
first
=
(
j
+
1
)
%
NPENDINGCALLS
;
}
PyThread_release_lock
(
_PyRuntime
.
ceval
.
pending
.
lock
);
PyThread_release_lock
(
_PyRuntime
.
ceval
.
pending
.
lock
);
/* having released the lock, perform the callback */
/* having released the lock, perform the callback */
if
(
func
==
NULL
)
if
(
func
==
NULL
)
{
break
;
break
;
}
res
=
func
(
arg
);
res
=
func
(
arg
);
if
(
res
)
{
if
(
res
)
{
goto
error
;
goto
error
;
...
...
Python/pylifecycle.c
View file @
5be45a61
...
@@ -1460,6 +1460,7 @@ Py_EndInterpreter(PyThreadState *tstate)
...
@@ -1460,6 +1460,7 @@ Py_EndInterpreter(PyThreadState *tstate)
Py_FatalError
(
"Py_EndInterpreter: thread is not current"
);
Py_FatalError
(
"Py_EndInterpreter: thread is not current"
);
if
(
tstate
->
frame
!=
NULL
)
if
(
tstate
->
frame
!=
NULL
)
Py_FatalError
(
"Py_EndInterpreter: thread still has a frame"
);
Py_FatalError
(
"Py_EndInterpreter: thread still has a frame"
);
interp
->
finalizing
=
1
;
wait_for_thread_shutdown
();
wait_for_thread_shutdown
();
...
...
Python/pystate.c
View file @
5be45a61
...
@@ -60,6 +60,8 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime)
...
@@ -60,6 +60,8 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime)
return
_Py_INIT_ERR
(
"Can't initialize threads for cross-interpreter data registry"
);
return
_Py_INIT_ERR
(
"Can't initialize threads for cross-interpreter data registry"
);
}
}
// runtime->main_thread is set in PyEval_InitThreads().
return
_Py_INIT_OK
();
return
_Py_INIT_OK
();
}
}
...
@@ -133,28 +135,12 @@ PyInterpreterState_New(void)
...
@@ -133,28 +135,12 @@ PyInterpreterState_New(void)
return
NULL
;
return
NULL
;
}
}
memset
(
interp
,
0
,
sizeof
(
*
interp
));
interp
->
id_refcount
=
-
1
;
interp
->
id_refcount
=
-
1
;
interp
->
id_mutex
=
NULL
;
interp
->
modules
=
NULL
;
interp
->
modules_by_index
=
NULL
;
interp
->
sysdict
=
NULL
;
interp
->
builtins
=
NULL
;
interp
->
builtins_copy
=
NULL
;
interp
->
tstate_head
=
NULL
;
interp
->
check_interval
=
100
;
interp
->
check_interval
=
100
;
interp
->
num_threads
=
0
;
interp
->
pythread_stacksize
=
0
;
interp
->
codec_search_path
=
NULL
;
interp
->
codec_search_cache
=
NULL
;
interp
->
codec_error_registry
=
NULL
;
interp
->
codecs_initialized
=
0
;
interp
->
fscodec_initialized
=
0
;
interp
->
core_config
=
_PyCoreConfig_INIT
;
interp
->
core_config
=
_PyCoreConfig_INIT
;
interp
->
config
=
_PyMainInterpreterConfig_INIT
;
interp
->
config
=
_PyMainInterpreterConfig_INIT
;
interp
->
importlib
=
NULL
;
interp
->
import_func
=
NULL
;
interp
->
eval_frame
=
_PyEval_EvalFrameDefault
;
interp
->
eval_frame
=
_PyEval_EvalFrameDefault
;
interp
->
co_extra_user_count
=
0
;
#ifdef HAVE_DLOPEN
#ifdef HAVE_DLOPEN
#if HAVE_DECL_RTLD_NOW
#if HAVE_DECL_RTLD_NOW
interp
->
dlopenflags
=
RTLD_NOW
;
interp
->
dlopenflags
=
RTLD_NOW
;
...
@@ -162,13 +148,6 @@ PyInterpreterState_New(void)
...
@@ -162,13 +148,6 @@ PyInterpreterState_New(void)
interp
->
dlopenflags
=
RTLD_LAZY
;
interp
->
dlopenflags
=
RTLD_LAZY
;
#endif
#endif
#endif
#endif
#ifdef HAVE_FORK
interp
->
before_forkers
=
NULL
;
interp
->
after_forkers_parent
=
NULL
;
interp
->
after_forkers_child
=
NULL
;
#endif
interp
->
pyexitfunc
=
NULL
;
interp
->
pyexitmodule
=
NULL
;
HEAD_LOCK
();
HEAD_LOCK
();
if
(
_PyRuntime
.
interpreters
.
next_id
<
0
)
{
if
(
_PyRuntime
.
interpreters
.
next_id
<
0
)
{
...
@@ -223,6 +202,9 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
...
@@ -223,6 +202,9 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
Py_CLEAR
(
interp
->
after_forkers_parent
);
Py_CLEAR
(
interp
->
after_forkers_parent
);
Py_CLEAR
(
interp
->
after_forkers_child
);
Py_CLEAR
(
interp
->
after_forkers_child
);
#endif
#endif
// XXX Once we have one allocator per interpreter (i.e.
// per-interpreter GC) we must ensure that all of the interpreter's
// objects have been cleaned up at the point.
}
}
...
@@ -334,28 +316,39 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
...
@@ -334,28 +316,39 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
}
}
PyInterpreterState
*
static
PyInterpreterState
*
_PyInterpreterState_LookUpID
(
PY_INT64_T
requested_id
)
interp_look_up_id
(
PY_INT64_T
requested_id
)
{
{
if
(
requested_id
<
0
)
goto
error
;
PyInterpreterState
*
interp
=
PyInterpreterState_Head
();
PyInterpreterState
*
interp
=
PyInterpreterState_Head
();
while
(
interp
!=
NULL
)
{
while
(
interp
!=
NULL
)
{
PY_INT64_T
id
=
PyInterpreterState_GetID
(
interp
);
PY_INT64_T
id
=
PyInterpreterState_GetID
(
interp
);
if
(
id
<
0
)
if
(
id
<
0
)
{
return
NULL
;
return
NULL
;
if
(
requested_id
==
id
)
}
if
(
requested_id
==
id
)
{
return
interp
;
return
interp
;
}
interp
=
PyInterpreterState_Next
(
interp
);
interp
=
PyInterpreterState_Next
(
interp
);
}
}
error:
PyErr_Format
(
PyExc_RuntimeError
,
"unrecognized interpreter ID %lld"
,
requested_id
);
return
NULL
;
return
NULL
;
}
}
PyInterpreterState
*
_PyInterpreterState_LookUpID
(
PY_INT64_T
requested_id
)
{
PyInterpreterState
*
interp
=
NULL
;
if
(
requested_id
>=
0
)
{
HEAD_LOCK
();
interp
=
interp_look_up_id
(
requested_id
);
HEAD_UNLOCK
();
}
if
(
interp
==
NULL
&&
!
PyErr_Occurred
())
{
PyErr_Format
(
PyExc_RuntimeError
,
"unrecognized interpreter ID %lld"
,
requested_id
);
}
return
interp
;
}
int
int
_PyInterpreterState_IDInitref
(
PyInterpreterState
*
interp
)
_PyInterpreterState_IDInitref
(
PyInterpreterState
*
interp
)
...
...
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