Author vstinner
Recipients eric.snow, ncoghlan, pablogsal, vstinner
Date 2020-03-19.02:14:10
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1584584052.19.0.918723275106.issue36479@roundup.psfhosted.org>
In-reply-to
Content
I suggest to close this issue, I don't think that it can be implemented because of daemon threads.

--

> This behavior should instead be triggered by the thread's interpreter finalizing rather than the runtime.

What is the motivation for that?

--

take_gil() cannot access interp->finalizing since interp memory is freed during Python finalization.

take_gil() can only rely on a global variable like _PyRuntime to check if a daemon thread must exit during the Python finalization.

I modified take_gil() recently to fix 2 or 3 different crashes caused by daemon threads during Python finalization. Extract of ceval.c:

/* Check if a Python thread must exit immediately, rather than taking the GIL
   if Py_Finalize() has been called.

   When this function is called by a daemon thread after Py_Finalize() has been
   called, the GIL does no longer exist.

   tstate must be non-NULL. */
static inline int
tstate_must_exit(PyThreadState *tstate)
{
    /* bpo-39877: Access _PyRuntime directly rather than using
       tstate->interp->runtime to support calls from Python daemon threads.
       After Py_Finalize() has been called, tstate can be a dangling pointer:
       point to PyThreadState freed memory. */
    _PyRuntimeState *runtime = &_PyRuntime;
    PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime);
    return (finalizing != NULL && finalizing != tstate);
}


And simplified take_gil():

static void
take_gil(PyThreadState *tstate)
{
    if (tstate_must_exit(tstate)) {
        /* bpo-39877: If Py_Finalize() has been called and tstate is not the
           thread which called Py_Finalize(), exit immediately the thread.

           This code path can be reached by a daemon thread after Py_Finalize()
           completes. In this case, tstate is a dangling pointer: points to
           PyThreadState freed memory. */
        PyThread_exit_thread();
    }

    (... logic to acquire the GIL ...)

    if (must_exit) {
        /* bpo-36475: If Py_Finalize() has been called and tstate is not
           the thread which called Py_Finalize(), exit immediately the
           thread.

           This code path can be reached by a daemon thread which was waiting
           in take_gil() while the main thread called
           wait_for_thread_shutdown() from Py_Finalize(). */
        drop_gil(ceval, ceval2, tstate);
        PyThread_exit_thread();
    }
}
History
Date User Action Args
2020-03-19 02:14:12vstinnersetrecipients: + vstinner, ncoghlan, eric.snow, pablogsal
2020-03-19 02:14:12vstinnersetmessageid: <1584584052.19.0.918723275106.issue36479@roundup.psfhosted.org>
2020-03-19 02:14:12vstinnerlinkissue36479 messages
2020-03-19 02:14:10vstinnercreate