2
0

pythonThread.cxx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file pythonThread.cxx
  10. * @author drose
  11. * @date 2007-04-13
  12. */
  13. #include "pythonThread.h"
  14. #include "pnotify.h"
  15. #ifdef HAVE_PYTHON
  16. #include "py_panda.h"
  17. TypeHandle PythonThread::_type_handle;
  18. /**
  19. *
  20. */
  21. PythonThread::
  22. PythonThread(PyObject *function, PyObject *args,
  23. const std::string &name, const std::string &sync_name) :
  24. Thread(name, sync_name)
  25. {
  26. _function = function;
  27. Py_INCREF(_function);
  28. _args = nullptr;
  29. _result = nullptr;
  30. if (!PyCallable_Check(_function)) {
  31. nassert_raise("Invalid function passed to PythonThread constructor");
  32. }
  33. set_args(args);
  34. #if !defined(SIMPLE_THREADS) && defined(WITH_THREAD) && PY_VERSION_HEX < 0x03090000
  35. // Ensure that the Python threading system is initialized and ready to go.
  36. // WITH_THREAD symbol defined within Python.h
  37. // PyEval_InitThreads is now a deprecated no-op in Python 3.9+
  38. PyEval_InitThreads();
  39. #endif
  40. }
  41. /**
  42. *
  43. */
  44. PythonThread::
  45. ~PythonThread() {
  46. // Unfortunately, we need to grab the GIL to release these things,
  47. // since the destructor could be called from any thread.
  48. #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
  49. PyGILState_STATE gstate;
  50. gstate = PyGILState_Ensure();
  51. #endif
  52. Py_DECREF(_function);
  53. Py_XDECREF(_args);
  54. Py_XDECREF(_result);
  55. #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
  56. PyGILState_Release(gstate);
  57. #endif
  58. }
  59. /**
  60. * Blocks the calling process until the thread terminates. If the thread has
  61. * already terminated, this returns immediately.
  62. *
  63. * The PythonThread flavor of this function returns the same value returned by
  64. * the thread function.
  65. */
  66. PyObject *PythonThread::
  67. join() {
  68. Thread::join();
  69. if (_result == nullptr) {
  70. // No result; return None.
  71. Py_INCREF(Py_None);
  72. return Py_None;
  73. }
  74. Py_INCREF(_result);
  75. return _result;
  76. }
  77. /**
  78. *
  79. */
  80. PyObject *PythonThread::
  81. get_args() const {
  82. return _args;
  83. }
  84. /**
  85. *
  86. */
  87. void PythonThread::
  88. set_args(PyObject *args) {
  89. Py_XDECREF(_args);
  90. if (args == Py_None) {
  91. // None means no arguments; create an empty tuple.
  92. _args = PyTuple_New(0);
  93. } else {
  94. _args = nullptr;
  95. if (PySequence_Check(args)) {
  96. _args = PySequence_Tuple(args);
  97. }
  98. if (_args == nullptr) {
  99. Dtool_Raise_TypeError("PythonThread args must be a tuple");
  100. }
  101. }
  102. }
  103. #ifdef HAVE_PYTHON
  104. /**
  105. * Internal function to safely call a Python function within a sub-thread,
  106. * that might execute in parallel with existing Python code. The return value
  107. * is the return value of the Python function, or NULL if there was an
  108. * exception.
  109. */
  110. PyObject *PythonThread::
  111. call_python_func(PyObject *function, PyObject *args) {
  112. Thread *current_thread = get_current_thread();
  113. // Create a new Python thread state data structure, so Python can properly
  114. // lock itself.
  115. PyObject *result = nullptr;
  116. if (current_thread == get_main_thread()) {
  117. // In the main thread, just call the function.
  118. result = PyObject_Call(function, args, nullptr);
  119. if (result == nullptr) {
  120. if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) {
  121. // If we caught SystemExit, let it pass by without bothering to print
  122. // a callback.
  123. } else {
  124. // Temporarily save and restore the exception state so we can print a
  125. // callback on-the-spot.
  126. PyObject *exc, *val, *tb;
  127. PyErr_Fetch(&exc, &val, &tb);
  128. Py_XINCREF(exc);
  129. Py_XINCREF(val);
  130. Py_XINCREF(tb);
  131. PyErr_Restore(exc, val, tb);
  132. PyErr_Print();
  133. PyErr_Restore(exc, val, tb);
  134. }
  135. }
  136. } else {
  137. #ifndef HAVE_THREADS
  138. // Shouldn't be possible to come here without having some kind of
  139. // threading support enabled.
  140. nassert_raise("threading support disabled");
  141. return nullptr;
  142. #else
  143. #ifdef SIMPLE_THREADS
  144. // We can't use the PyGILState interface, which assumes we are using true
  145. // OS-level threading. PyGILState enforces policies like only one thread
  146. // state per OS-level thread, which is not true in the case of
  147. // SIMPLE_THREADS.
  148. // For some reason I don't fully understand, I'm getting a crash when I
  149. // clean up old PyThreadState objects with PyThreadState_Delete(). It
  150. // appears that the thread state is still referenced somewhere at the time
  151. // I call delete, and the crash occurs because I've deleted an active
  152. // pointer.
  153. // Storing these pointers in a vector for permanent recycling seems to
  154. // avoid this problem. I wish I understood better what's going wrong, but
  155. // I guess this workaround will do.
  156. static pvector<PyThreadState *> thread_states;
  157. PyThreadState *orig_thread_state = PyThreadState_Get();
  158. PyInterpreterState *istate = orig_thread_state->interp;
  159. PyThreadState *new_thread_state;
  160. if (thread_states.empty()) {
  161. new_thread_state = PyThreadState_New(istate);
  162. } else {
  163. new_thread_state = thread_states.back();
  164. thread_states.pop_back();
  165. }
  166. PyThreadState_Swap(new_thread_state);
  167. // Call the user's function.
  168. result = PyObject_Call(function, args, nullptr);
  169. if (result == nullptr && PyErr_Occurred()) {
  170. // We got an exception. Move the exception from the current thread into
  171. // the main thread, so it can be handled there.
  172. PyObject *exc, *val, *tb;
  173. PyErr_Fetch(&exc, &val, &tb);
  174. thread_cat.error()
  175. << "Exception occurred within " << *current_thread << "\n";
  176. // Temporarily restore the exception state so we can print a callback
  177. // on-the-spot.
  178. Py_XINCREF(exc);
  179. Py_XINCREF(val);
  180. Py_XINCREF(tb);
  181. PyErr_Restore(exc, val, tb);
  182. PyErr_Print();
  183. PyThreadState_Swap(orig_thread_state);
  184. thread_states.push_back(new_thread_state);
  185. // PyThreadState_Clear(new_thread_state);
  186. // PyThreadState_Delete(new_thread_state);
  187. PyErr_Restore(exc, val, tb);
  188. // Now attempt to force the main thread to the head of the ready queue,
  189. // so it can respond to the exception immediately. This only works if
  190. // the main thread is not blocked, of course.
  191. Thread::get_main_thread()->preempt();
  192. } else {
  193. // No exception. Restore the thread state normally.
  194. PyThreadState_Swap(orig_thread_state);
  195. thread_states.push_back(new_thread_state);
  196. // PyThreadState_Clear(new_thread_state);
  197. // PyThreadState_Delete(new_thread_state);
  198. }
  199. #else // SIMPLE_THREADS
  200. // With true threading enabled, we're better off using PyGILState.
  201. PyGILState_STATE gstate;
  202. gstate = PyGILState_Ensure();
  203. // Call the user's function.
  204. result = PyObject_Call(function, args, nullptr);
  205. if (result == nullptr && PyErr_Occurred()) {
  206. // We got an exception. Move the exception from the current thread into
  207. // the main thread, so it can be handled there.
  208. PyObject *exc, *val, *tb;
  209. PyErr_Fetch(&exc, &val, &tb);
  210. // Temporarily restore the exception state so we can print a callback
  211. // on-the-spot, except if it's a SystemExit, which would cause PyErr_Print
  212. // to exit the process immediately.
  213. if (exc != PyExc_SystemExit) {
  214. thread_cat.error()
  215. << "Exception occurred within " << *current_thread << "\n";
  216. Py_XINCREF(exc);
  217. Py_XINCREF(val);
  218. Py_XINCREF(tb);
  219. PyErr_Restore(exc, val, tb);
  220. PyErr_Print();
  221. } else {
  222. thread_cat.info()
  223. << "SystemExit occurred within " << *current_thread << "\n";
  224. }
  225. PyGILState_Release(gstate);
  226. if (PyGILState_Check()) {
  227. PyErr_Restore(exc, val, tb);
  228. }
  229. } else {
  230. // No exception. Restore the thread state normally.
  231. PyGILState_Release(gstate);
  232. }
  233. #endif // SIMPLE_THREADS
  234. #endif // HAVE_THREADS
  235. }
  236. return result;
  237. }
  238. #endif // HAVE_PYTHON
  239. /**
  240. *
  241. */
  242. void PythonThread::
  243. thread_main() {
  244. _result = call_python_func(_function, _args);
  245. }
  246. #endif // HAVE_PYTHON