[PythonCE] Non-Python threads crash on errno access
generic3.20.fusion at neverbox.com
Tue Jun 27 09:13:39 CEST 2006
We have a scenario where a Python program uses a C++ module. The C++
module creates its own threads, and these threads sometimes call back
into Python (after first acquiring the GIL, of course). This works
quite nicely on Linux and desktop Windows, but crashes on CE. After
some debugging I discovered the cause: PythonCE uses its own errno
macro which pulls a pointer out of thread-local storage and
dereferences it. This works fine if the thread was started in Python,
since new threads have a valid address placed into the thread-local
storage slot. Non-Python threads, however, have the default initial
value for the slot which happens to be zero, so dereferencing it
crashes the program.
As far as I can tell, there is no way to work around this that does
not involve modifying the PythonCE source. I think we need some call
we can make to initialize the thread-local storage for a non-Python
thread. The solution is complicated somewhat by the fact that I want
to be able to initialize the same thread multiple times without
breaking it. The reason for this probably requires some explanation.
The straight-forward approach would be to have any new non-Python
thread call an initialization function when it starts, then call a
de-register function when it finishes (just like Python threads
currently do). This approach falls short because it assumes that the
creator of a thread knows whether or not that thread will ever call
Python. This makes it impossible to take a general-purpose,
Python-agnostic C++ module that uses threads and a callback mechanism
and expose it to Python in a way that allows callbacks to be written
Because of this, the only sensible approach is to surround the call
into Python with our register-thread and de-register-thread functions.
This is really not an extra burden, because we already have to
surround it with the GIL-acquiring and releasing functions.
Now, assume that a thread created in C++ calls into Python, which
calls back into C++, which calls into Python again. Since the calls
into Python are surrounded by the thread registration/de-registration
functions, the registration needs to be smart enough to do nothing the
second time, and only de-register the last time.
I think I have a solution, but it's not very nice. I'd like to see
some suggestions about how to handle this in a more elegant way, and
hopefully a permanent solution added to the official distribution.
More information about the PythonCE