| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ac2cfe6 commit dda5d6e
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,8 +17,8 @@ struct _frame; | |||
| 17 | 17 | ||
| 18 | 18 | extern void _Py_FinishPendingCalls(PyThreadState *tstate); | |
| 19 | 19 | extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); | |
| 20 | - extern void _PyEval_InitState(struct _ceval_state *); | ||
| 21 | - extern void _PyEval_FiniThreads(PyThreadState *tstate); | ||
| 20 | + extern int _PyEval_InitState(struct _ceval_state *ceval); | ||
| 21 | + extern void _PyEval_FiniState(struct _ceval_state *ceval); | ||
| 22 | 22 | PyAPI_FUNC(void) _PyEval_SignalReceived(PyThreadState *tstate); | |
| 23 | 23 | PyAPI_FUNC(int) _PyEval_AddPendingCall( | |
| 24 | 24 | PyThreadState *tstate, | |
@@ -51,7 +51,8 @@ extern PyObject *_PyEval_EvalCode( | |||
| 51 | 51 | PyObject *name, PyObject *qualname); | |
| 52 | 52 | ||
| 53 | 53 | extern int _PyEval_ThreadsInitialized(_PyRuntimeState *runtime); | |
| 54 | - extern PyStatus _PyEval_InitThreads(PyThreadState *tstate); | ||
| 54 | + extern PyStatus _PyEval_InitGIL(PyThreadState *tstate); | ||
| 55 | + extern void _PyEval_FiniGIL(PyThreadState *tstate); | ||
| 55 | 56 | ||
| 56 | 57 | extern void _PyEval_ReleaseLock(PyThreadState *tstate); | |
| 57 | 58 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -275,54 +275,52 @@ PyEval_ThreadsInitialized(void) | |||
| 275 | 275 | } | |
| 276 | 276 | ||
| 277 | 277 | PyStatus | |
| 278 | - _PyEval_InitThreads(PyThreadState *tstate) | ||
| 278 | + _PyEval_InitGIL(PyThreadState *tstate) | ||
| 279 | 279 | { | |
| 280 | - assert(is_tstate_valid(tstate)); | ||
| 280 | + if (!_Py_IsMainInterpreter(tstate)) { | ||
| 281 | + /* Currently, the GIL is shared by all interpreters, | ||
| 282 | + and only the main interpreter is responsible to create | ||
| 283 | + and destroy it. */ | ||
| 284 | + return _PyStatus_OK(); | ||
| 285 | + } | ||
| 281 | 286 | ||
| 282 | - if (_Py_IsMainInterpreter(tstate)) { | ||
| 283 | - struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; | ||
| 284 | - if (gil_created(gil)) { | ||
| 285 | - return _PyStatus_OK(); | ||
| 286 | - } | ||
| 287 | + struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; | ||
| 288 | + assert(!gil_created(gil)); | ||
| 287 | 289 | ||
| 288 | - PyThread_init_thread(); | ||
| 289 | - create_gil(gil); | ||
| 290 | + PyThread_init_thread(); | ||
| 291 | + create_gil(gil); | ||
| 290 | 292 | ||
| 291 | - take_gil(tstate); | ||
| 292 | - } | ||
| 293 | - | ||
| 294 | - struct _pending_calls *pending = &tstate->interp->ceval.pending; | ||
| 295 | - assert(pending->lock == NULL); | ||
| 296 | - pending->lock = PyThread_allocate_lock(); | ||
| 297 | - if (pending->lock == NULL) { | ||
| 298 | - return _PyStatus_NO_MEMORY(); | ||
| 299 | - } | ||
| 293 | + take_gil(tstate); | ||
| 300 | 294 | ||
| 295 | + assert(gil_created(gil)); | ||
| 301 | 296 | return _PyStatus_OK(); | |
| 302 | 297 | } | |
| 303 | 298 | ||
| 304 | 299 | void | |
| 305 | - PyEval_InitThreads(void) | ||
| 300 | + _PyEval_FiniGIL(PyThreadState *tstate) | ||
| 306 | 301 | { | |
| 307 | - /* Do nothing: kept for backward compatibility */ | ||
| 308 | - } | ||
| 302 | + if (!_Py_IsMainInterpreter(tstate)) { | ||
| 303 | + /* Currently, the GIL is shared by all interpreters, | ||
| 304 | + and only the main interpreter is responsible to create | ||
| 305 | + and destroy it. */ | ||
| 306 | + return; | ||
| 307 | + } | ||
| 309 | 308 | ||
| 310 | - void | ||
| 311 | - _PyEval_FiniThreads(PyThreadState *tstate) | ||
| 312 | - { | ||
| 313 | 309 | struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; | |
| 314 | 310 | if (!gil_created(gil)) { | |
| 311 | + /* First Py_InitializeFromConfig() call: the GIL doesn't exist | ||
| 312 | + yet: do nothing. */ | ||
| 315 | 313 | return; | |
| 316 | 314 | } | |
| 317 | 315 | ||
| 318 | 316 | destroy_gil(gil); | |
| 319 | 317 | assert(!gil_created(gil)); | |
| 318 | + } | ||
| 320 | 319 | ||
| 321 | - struct _pending_calls *pending = &tstate->interp->ceval.pending; | ||
| 322 | - if (pending->lock != NULL) { | ||
| 323 | - PyThread_free_lock(pending->lock); | ||
| 324 | - pending->lock = NULL; | ||
| 325 | - } | ||
| 320 | + void | ||
| 321 | + PyEval_InitThreads(void) | ||
| 322 | + { | ||
| 323 | + /* Do nothing: kept for backward compatibility */ | ||
| 326 | 324 | } | |
| 327 | 325 | ||
| 328 | 326 | void | |
@@ -544,6 +542,10 @@ _PyEval_AddPendingCall(PyThreadState *tstate, | |||
| 544 | 542 | { | |
| 545 | 543 | struct _pending_calls *pending = &tstate->interp->ceval.pending; | |
| 546 | 544 | ||
| 545 | + /* Ensure that _PyEval_InitPendingCalls() was called | ||
| 546 | + and that _PyEval_FiniPendingCalls() is not called yet. */ | ||
| 547 | + assert(pending->lock != NULL); | ||
| 548 | + | ||
| 547 | 549 | PyThread_acquire_lock(pending->lock, WAIT_LOCK); | |
| 548 | 550 | if (pending->finishing) { | |
| 549 | 551 | PyThread_release_lock(pending->lock); | |
@@ -721,10 +723,27 @@ _PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval) | |||
| 721 | 723 | _gil_initialize(&ceval->gil); | |
| 722 | 724 | } | |
| 723 | 725 | ||
| 724 | - void | ||
| 726 | + int | ||
| 725 | 727 | _PyEval_InitState(struct _ceval_state *ceval) | |
| 726 | 728 | { | |
| 727 | - /* PyInterpreterState_New() initializes ceval to zero */ | ||
| 729 | + struct _pending_calls *pending = &ceval->pending; | ||
| 730 | + assert(pending->lock == NULL); | ||
| 731 | + | ||
| 732 | + pending->lock = PyThread_allocate_lock(); | ||
| 733 | + if (pending->lock == NULL) { | ||
| 734 | + return -1; | ||
| 735 | + } | ||
| 736 | + return 0; | ||
| 737 | + } | ||
| 738 | + | ||
| 739 | + void | ||
| 740 | + _PyEval_FiniState(struct _ceval_state *ceval) | ||
| 741 | + { | ||
| 742 | + struct _pending_calls *pending = &ceval->pending; | ||
| 743 | + if (pending->lock != NULL) { | ||
| 744 | + PyThread_free_lock(pending->lock); | ||
| 745 | + pending->lock = NULL; | ||
| 746 | + } | ||
| 728 | 747 | } | |
| 729 | 748 | ||
| 730 | 749 | int | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -523,6 +523,31 @@ pycore_init_runtime(_PyRuntimeState *runtime, | |||
| 523 | 523 | } | |
| 524 | 524 | ||
| 525 | 525 | ||
| 526 | + static PyStatus | ||
| 527 | + init_interp_create_gil(PyThreadState *tstate) | ||
| 528 | + { | ||
| 529 | + PyStatus status; | ||
| 530 | + | ||
| 531 | + /* finalize_interp_delete() comment explains why _PyEval_FiniGIL() is | ||
| 532 | + only called here. */ | ||
| 533 | + _PyEval_FiniGIL(tstate); | ||
| 534 | + | ||
| 535 | + /* Auto-thread-state API */ | ||
| 536 | + status = _PyGILState_Init(tstate); | ||
| 537 | + if (_PyStatus_EXCEPTION(status)) { | ||
| 538 | + return status; | ||
| 539 | + } | ||
| 540 | + | ||
| 541 | + /* Create the GIL and take it */ | ||
| 542 | + status = _PyEval_InitGIL(tstate); | ||
| 543 | + if (_PyStatus_EXCEPTION(status)) { | ||
| 544 | + return status; | ||
| 545 | + } | ||
| 546 | + | ||
| 547 | + return _PyStatus_OK(); | ||
| 548 | + } | ||
| 549 | + | ||
| 550 | + | ||
| 526 | 551 | static PyStatus | |
| 527 | 552 | pycore_create_interpreter(_PyRuntimeState *runtime, | |
| 528 | 553 | const PyConfig *config, | |
@@ -544,21 +569,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, | |||
| 544 | 569 | } | |
| 545 | 570 | (void) PyThreadState_Swap(tstate); | |
| 546 | 571 | ||
| 547 | - /* We can't call _PyEval_FiniThreads() in Py_FinalizeEx because | ||
| 548 | - destroying the GIL might fail when it is being referenced from | ||
| 549 | - another running thread (see issue #9901). | ||
| 550 | - Instead we destroy the previously created GIL here, which ensures | ||
| 551 | - that we can call Py_Initialize / Py_FinalizeEx multiple times. */ | ||
| 552 | - _PyEval_FiniThreads(tstate); | ||
| 553 | - | ||
| 554 | - /* Auto-thread-state API */ | ||
| 555 | - status = _PyGILState_Init(tstate); | ||
| 556 | - if (_PyStatus_EXCEPTION(status)) { | ||
| 557 | - return status; | ||
| 558 | - } | ||
| 559 | - | ||
| 560 | - /* Create the GIL and the pending calls lock */ | ||
| 561 | - status = _PyEval_InitThreads(tstate); | ||
| 572 | + status = init_interp_create_gil(tstate); | ||
| 562 | 573 | if (_PyStatus_EXCEPTION(status)) { | |
| 563 | 574 | return status; | |
| 564 | 575 | } | |
@@ -1323,6 +1334,12 @@ finalize_interp_delete(PyThreadState *tstate) | |||
| 1323 | 1334 | _PyGILState_Fini(tstate); | |
| 1324 | 1335 | } | |
| 1325 | 1336 | ||
| 1337 | + /* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can | ||
| 1338 | + fail when it is being awaited by another running daemon thread (see | ||
| 1339 | + bpo-9901). Instead pycore_create_interpreter() destroys the previously | ||
| 1340 | + created GIL, which ensures that Py_Initialize / Py_FinalizeEx can be | ||
| 1341 | + called multiple times. */ | ||
| 1342 | + | ||
| 1326 | 1343 | PyInterpreterState_Delete(tstate->interp); | |
| 1327 | 1344 | } | |
| 1328 | 1345 | ||
@@ -1578,8 +1595,7 @@ new_interpreter(PyThreadState **tstate_p) | |||
| 1578 | 1595 | goto error; | |
| 1579 | 1596 | } | |
| 1580 | 1597 | ||
| 1581 | - /* Create the pending calls lock */ | ||
| 1582 | - status = _PyEval_InitThreads(tstate); | ||
| 1598 | + status = init_interp_create_gil(tstate); | ||
| 1583 | 1599 | if (_PyStatus_EXCEPTION(status)) { | |
| 1584 | 1600 | return status; | |
| 1585 | 1601 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -222,7 +222,10 @@ PyInterpreterState_New(void) | |||
| 222 | 222 | _PyRuntimeState *runtime = &_PyRuntime; | |
| 223 | 223 | interp->runtime = runtime; | |
| 224 | 224 | ||
| 225 | - _PyEval_InitState(&interp->ceval); | ||
| 225 | + if (_PyEval_InitState(&interp->ceval) < 0) { | ||
| 226 | + goto out_of_memory; | ||
| 227 | + } | ||
| 228 | + | ||
| 226 | 229 | _PyGC_InitState(&interp->gc); | |
| 227 | 230 | PyConfig_InitPythonConfig(&interp->config); | |
| 228 | 231 | ||
@@ -267,6 +270,14 @@ PyInterpreterState_New(void) | |||
| 267 | 270 | interp->audit_hooks = NULL; | |
| 268 | 271 | ||
| 269 | 272 | return interp; | |
| 273 | + | ||
| 274 | + out_of_memory: | ||
| 275 | + if (tstate != NULL) { | ||
| 276 | + _PyErr_NoMemory(tstate); | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + PyMem_RawFree(interp); | ||
| 280 | + return NULL; | ||
| 270 | 281 | } | |
| 271 | 282 | ||
| 272 | 283 | ||
@@ -335,6 +346,8 @@ PyInterpreterState_Delete(PyInterpreterState *interp) | |||
| 335 | 346 | struct pyinterpreters *interpreters = &runtime->interpreters; | |
| 336 | 347 | zapthreads(interp, 0); | |
| 337 | 348 | ||
| 349 | + _PyEval_FiniState(&interp->ceval); | ||
| 350 | + | ||
| 338 | 351 | /* Delete current thread. After this, many C API calls become crashy. */ | |
| 339 | 352 | _PyThreadState_Swap(&runtime->gilstate, NULL); | |
| 340 | 353 | ||
@@ -352,13 +365,15 @@ PyInterpreterState_Delete(PyInterpreterState *interp) | |||
| 352 | 365 | Py_FatalError("remaining threads"); | |
| 353 | 366 | } | |
| 354 | 367 | *p = interp->next; | |
| 368 | + | ||
| 355 | 369 | if (interpreters->main == interp) { | |
| 356 | 370 | interpreters->main = NULL; | |
| 357 | 371 | if (interpreters->head != NULL) { | |
| 358 | 372 | Py_FatalError("remaining subinterpreters"); | |
| 359 | 373 | } | |
| 360 | 374 | } | |
| 361 | 375 | HEAD_UNLOCK(runtime); | |
| 376 | + | ||
| 362 | 377 | if (interp->id_mutex != NULL) { | |
| 363 | 378 | PyThread_free_lock(interp->id_mutex); | |
| 364 | 379 | } | |
@@ -1198,6 +1213,12 @@ PyThreadState_IsCurrent(PyThreadState *tstate) | |||
| 1198 | 1213 | PyStatus | |
| 1199 | 1214 | _PyGILState_Init(PyThreadState *tstate) | |
| 1200 | 1215 | { | |
| 1216 | + if (!_Py_IsMainInterpreter(tstate)) { | ||
| 1217 | + /* Currently, PyGILState is shared by all interpreters. The main | ||
| 1218 | + * interpreter is responsible to initialize it. */ | ||
| 1219 | + return _PyStatus_OK(); | ||
| 1220 | + } | ||
| 1221 | + | ||
| 1201 | 1222 | /* must init with valid states */ | |
| 1202 | 1223 | assert(tstate != NULL); | |
| 1203 | 1224 | assert(tstate->interp != NULL); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments