[New-bugs-announce] [issue1683] Thread local storage and PyGILState_* mucked up by os.fork()

roudkerk report at bugs.python.org
Fri Dec 21 19:53:46 CET 2007


New submission from roudkerk:

I got a report that one of the tests for processing
(http://cheeseshop.python.org/pypi/processing) was failing with

    Fatal Python error: Invalid thread state for this thread

when run with a debug interpreter.  This appears to be caused by the
interaction between os.fork() and threads.  The following attached
program reliably reproduces the problem for me on Ubuntu edgy for x86.

All that happens is that the parent process starts a subthread then
forks, and then the child process starts a subthread.

With the normal interpreter I get

    started thread -1211028576 in process 18683
    I am thread -1211028576 in process 18683
    started thread -1211028576 in process 18685
    I am thread -1211028576 in process 18685

as expected, but with the debug interpreter I get

    started thread -1210782816 in process 18687
    I am thread -1210782816 in process 18687
    started thread -1210782816 in process 18689
    Fatal Python error: Invalid thread state for this thread
    [5817 refs]

Notice that the child process is reusing a thread id that was 
being used by the parent process at the time of the fork.

The code raising the error seems to be in pystate.c:

    PyThreadState *
    PyThreadState_Swap(PyThreadState *new)
    {
            PyThreadState *old = _PyThreadState_Current;

            _PyThreadState_Current = new;
            /* It should not be possible for more than one thread state
               to be used for a thread.  Check this the best we can in
debug 
               builds.
            */
    #if defined(Py_DEBUG) && defined(WITH_THREAD)
            if (new) {
                    PyThreadState *check = PyGILState_GetThisThreadState();
                    if (check && check != new)
                            Py_FatalError("Invalid thread state for this
thread");
            }
    #endif
            return old;
    }

It looks as though PyGILState_GetThisThreadState() is returning the
thread state of the thread from the parent process which has the same
id as the current thread.  Therefore the check fails.

I think the thread local storage implementation in thread.c should
provide a function _PyThread_ReInitTLS() which PyOS_AfterFork() can
call.  I think _PyThread_ReInitTLS() just needs to remove and free
each "struct key" in the linked list which does not match the id of
the calling thread.

----------
components: Interpreter Core
files: dbg2.py
messages: 58954
nosy: roudkerk
severity: normal
status: open
title: Thread local storage and PyGILState_* mucked up by os.fork()
type: crash
versions: Python 2.4, Python 2.5
Added file: http://bugs.python.org/file9023/dbg2.py

__________________________________
Tracker <report at bugs.python.org>
<http://bugs.python.org/issue1683>
__________________________________
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dbg2.py
Type: text/x-python
Size: 517 bytes
Desc: not available
Url : http://mail.python.org/pipermail/new-bugs-announce/attachments/20071221/6cefb22c/attachment.py 


More information about the New-bugs-announce mailing list