16 #include "mainThread.h"
17 #include "externalThread.h"
18 #include "config_pipeline.h"
19 #include "mutexDebug.h"
20 #include "conditionVarDebug.h"
21 #include "conditionVarFullDebug.h"
23 Thread *Thread::_main_thread;
24 Thread *Thread::_external_thread;
46 Thread(
const string &name,
const string &sync_name) :
48 _sync_name(sync_name),
53 _pstats_callback = NULL;
59 _python_data = Py_None;
60 Py_INCREF(_python_data);
64 _blocked_on_mutex = NULL;
65 _waiting_on_cvar = NULL;
66 _waiting_on_cvar_full = NULL;
69 #if defined(HAVE_PYTHON) && !defined(SIMPLE_THREADS)
72 #ifdef WITH_THREAD // This symbol defined within Python.h
74 #if PY_VERSION_HEX >= 0x03020000
91 Py_DECREF(_python_data);
95 nassertv(_blocked_on_mutex == NULL &&
96 _waiting_on_cvar == NULL &&
97 _waiting_on_cvar_full == NULL);
128 bind_thread(const
string &name, const
string &sync_name) {
129 Thread *current_thread = get_current_thread();
130 if (current_thread != get_external_thread()) {
132 nassertr(current_thread->get_name() == name &&
133 current_thread->
get_sync_name() == sync_name, current_thread);
134 return current_thread;
138 ThreadImpl::bind_thread(thread);
158 set_pipeline_stage(
int pipeline_stage) {
159 #ifdef THREADED_PIPELINE
160 _pipeline_stage = pipeline_stage;
162 if (pipeline_stage != 0) {
163 pipeline_cat.warning()
164 <<
"Requested pipeline stage " << pipeline_stage
165 <<
" but multithreaded render pipelines not enabled in build.\n";
177 output(ostream &out)
const {
178 out << get_type() <<
" " << get_name();
192 if (_blocked_on_mutex != (MutexDebug *)NULL) {
193 _blocked_on_mutex->output_with_holder(out);
194 }
else if (_waiting_on_cvar != (ConditionVarDebug *)NULL) {
195 out << *_waiting_on_cvar;
196 }
else if (_waiting_on_cvar_full != (ConditionVarFullDebug *)NULL) {
197 out << *_waiting_on_cvar_full;
199 #endif // DEBUG_THREADS
208 write_status(ostream &out) {
209 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
210 ThreadImpl::write_status(out);
242 start(ThreadPriority priority,
bool joinable) {
243 nassertr(!_started,
false);
245 if (!support_threads) {
246 thread_cat->warning()
247 << *
this <<
" could not be started: support-threads is false.\n";
251 _joinable = joinable;
252 _started = _impl.start(priority, joinable);
255 thread_cat->warning()
256 << *
this <<
" could not be started!\n";
273 set_python_data(PyObject *python_data) {
274 Py_DECREF(_python_data);
275 _python_data = python_data;
276 Py_INCREF(_python_data);
278 #endif // HAVE_PYTHON
288 get_python_data()
const {
289 Py_INCREF(_python_data);
292 #endif // HAVE_PYTHON
305 call_python_func(PyObject *
function, PyObject *args) {
310 PyObject *result = NULL;
314 result = PyObject_Call(
function, args, NULL);
316 if (result == (PyObject *)NULL) {
317 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) {
324 PyObject *exc, *val, *tb;
325 PyErr_Fetch(&exc, &val, &tb);
330 PyErr_Restore(exc, val, tb);
333 PyErr_Restore(exc, val, tb);
341 nassertr(
false, NULL);
344 #ifdef SIMPLE_THREADS
361 PyThreadState *orig_thread_state = PyThreadState_Get();
362 PyInterpreterState *istate = orig_thread_state->interp;
363 PyThreadState *new_thread_state;
364 if (thread_states.empty()) {
365 new_thread_state = PyThreadState_New(istate);
367 new_thread_state = thread_states.back();
368 thread_states.pop_back();
370 PyThreadState_Swap(new_thread_state);
373 result = PyObject_Call(
function, args, NULL);
374 if (result == (PyObject *)NULL && PyErr_Occurred()) {
377 PyObject *exc, *val, *tb;
378 PyErr_Fetch(&exc, &val, &tb);
381 <<
"Exception occurred within " << *
this <<
"\n";
388 PyErr_Restore(exc, val, tb);
391 PyThreadState_Swap(orig_thread_state);
392 thread_states.push_back(new_thread_state);
396 PyErr_Restore(exc, val, tb);
405 PyThreadState *state = PyThreadState_Swap(orig_thread_state);
406 thread_states.push_back(new_thread_state);
411 #else // SIMPLE_THREADS
413 PyGILState_STATE gstate;
414 gstate = PyGILState_Ensure();
417 result = PyObject_Call(
function, args, NULL);
418 if (result == (PyObject *)NULL && PyErr_Occurred()) {
421 PyObject *exc, *val, *tb;
422 PyErr_Fetch(&exc, &val, &tb);
425 <<
"Exception occurred within " << *
this <<
"\n";
432 PyErr_Restore(exc, val, tb);
435 PyGILState_Release(gstate);
437 PyErr_Restore(exc, val, tb);
440 PyGILState_Release(gstate);
444 #endif // SIMPLE_THREADS
445 #endif // HAVE_THREADS
450 #endif // HAVE_PYTHON
462 handle_python_exception() {
501 <<
"Exception occurred within " << *
this <<
"\n";
508 #endif // HAVE_PYTHON
520 static int count = 0;
522 if (count == 1 && _main_thread == (
Thread *)NULL) {
535 init_external_thread() {
536 if (_external_thread == (
Thread *)NULL) {
538 _external_thread->
ref();
virtual ~PStatsCallback()
Since this class is just an interface definition, there is no need to have a destructor.
void output_blocker(ostream &out) const
Writes a description of the mutex or condition variable that this thread is blocked on...
const string & get_sync_name() const
Returns the sync name of the thread.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
void preempt()
Indicates that this thread should run as soon as possible, preemptying any other threads that may be ...
This is our own Panda specialization on the default STL vector.
static Thread * get_main_thread()
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process...
virtual void activate_hook(Thread *thread)
Called when the thread is activated (resumes execution).
The special "external thread" class.
A base class for all things which can have a name.
The special "main thread" class.
A thread; that is, a lightweight process.
void ref() const
Explicitly increments the reference count.
TypeHandle is the identifier used to differentiate C++ class types.
virtual void deactivate_hook(Thread *thread)
Called when the thread is deactivated (swapped for another running thread).
bool start(ThreadPriority priority, bool joinable)
Starts the thread executing.