Hi, I'm developing a software which embeds Python as scripting language.
The software acts as webserver and for each request it peeks a thread
from a pool which in turn loads a python script to generate the response
(something like mod_python).
Since each http request is "independent" from others one, I need to
create a new interpreter with its own dictionary every time.
I'm exposing lots of C++ wrapped code and, in order to provide a sort of
"parallelism" between each request, I'm using this mechanism for each
P = python core
A = my application
P: invokes the registered C callback
A: PyEval_SaveThread (allows others threads to run/resume their scripts)
A: invoke C/C++ application's functions (which don't touch CPython API)
A: PyEval_RestoreThread (takes back the lock)
P: resume the execution of the script
(the above schema is the same of
Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS documented in ceval.h at
The problem I have encountered is that when I process two requests
simultaneously, Python reports the fatal error "ceval: orphan tstate".
I'm not an expert of the CPython internals API but I take a look at the
file ceval.c (actually I'm using python 2x but in the 3x version I
noticed it's the same) and the code involved is:
/* Give another thread a chance */
if (PyThreadState_Swap(NULL) != tstate)
Py_FatalError("ceval: tstate mix-up");
/* Other threads may run now */
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError("ceval: orphan tstate");
Can anyone explain me the meaning of those fatal errors (in particular
the "orphan tstate" one)? Why the return value should be null?
As far as I understand after the "PyThread_release_lock" others threads
are allowed to run and, if you take a look again at my above schema,
PyThreadState_Swap is supposed to be called between
PyThread_release_lock/PyThread_acquire_lock, exactly where the comment
"Other threads may run now" is placed. If i changed the code in order to
not fire a fatal error after the second PyThreadState_Swap everything
seems to work fine, but I'm afraid it's not the "proper" solution and I
need to understand the meaning of that fatal error.
Sorry for the long post and for my bad english, I hope that someone
could really help me.
Question: should the CPython source compile cleanly and work
correctly on (mostly ancient or hypothetical) machines that use
ones' complement or sign-and-magnitude to represent signed integers?
I'd like to explicitly document and make use of the following assumptions
about the underlying C implementation for CPython. These assumptions
go beyond what's guaranteed by the various C and C++ standards, but
seem to be almost universally satisfied on modern machines:
- signed integers are represented using two's complement
- for signed integers the bit pattern 100....000 is not a trap representation;
hence INT_MIN = -INT_MAX-1, LONG_MIN = -LONG_MAX-1, etc.
- conversion from an unsigned type to a signed type wraps modulo
2**(width of unsigned type).
Any thoughts, comments or objections? This may seem academic
(and perhaps it is), but it affects the possible solutions to e.g.,
The assumptions listed above are already tacitly used in various bits
of the CPython source (Objects/intobject.c notably makes use of the
first two assumptions in the implementations of int_and, int_or and
int_xor), while other bits of code make a special effort to *not* assume
more than the C standards allow. Whatever the answer to the initial
question is, it seems worth having an explicitly documented policy.
If we want Python's core source to remain 100% standards-compliant,
then int_and, int_or, etc. should be rewritten with ones' complement
and sign-and-magnitude machines in mind. That's certainly feasible,
but it seems silly to do such a rewrite without a good reason.
Python-dev agreement that ones' complement machines should be
supported would, of course, be a good reason.
I have some code that exhibits behavior that might be a python import bug.
The code is part of a set of unit tests. One test in passes when no .pyc files
exist, but fails when the pyc file is present on disk. My code is not doing any
thing special with import or pickle or anything "fancy". I have confirmed the
behavior in 2.6.4, as well the svn 2.6 version. The svn 2.7 version
All builds were production builds (not debug).
The code that shows this problem is owned by my company, I'm not sure
if I would be able to produce it to create a bug report. But I do have some time
to help debug the problem.
What steps should I take to try to isolate the problem?
Thanks for any info.