TThreadStateDestroy.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
  2. /**
  3. * Implementation of the ThreadState destructors.
  4. *
  5. * Format with:
  6. * clang-format -i --style=file src/greenlet/greenlet.c
  7. *
  8. *
  9. * Fix missing braces with:
  10. * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
  11. */
  12. #ifndef T_THREADSTATE_DESTROY
  13. #define T_THREADSTATE_DESTROY
  14. #include "TGreenlet.hpp"
  15. #include "greenlet_thread_support.hpp"
  16. #include "greenlet_compiler_compat.hpp"
  17. #include "TGreenletGlobals.cpp"
  18. #include "TThreadState.hpp"
  19. #include "TThreadStateCreator.hpp"
  20. namespace greenlet {
  21. extern "C" {
  22. struct ThreadState_DestroyNoGIL
  23. {
  24. /**
  25. This function uses the same lock that the PendingCallback does
  26. */
  27. static void
  28. MarkGreenletDeadAndQueueCleanup(ThreadState* const state)
  29. {
  30. #if GREENLET_BROKEN_THREAD_LOCAL_CLEANUP_JUST_LEAK
  31. return;
  32. #endif
  33. // We are *NOT* holding the GIL. Our thread is in the middle
  34. // of its death throes and the Python thread state is already
  35. // gone so we can't use most Python APIs. One that is safe is
  36. // ``Py_AddPendingCall``, unless the interpreter itself has
  37. // been torn down. There is a limited number of calls that can
  38. // be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we
  39. // coalesce these calls using our own queue.
  40. if (!MarkGreenletDeadIfNeeded(state)) {
  41. // No state, or no greenlet
  42. return;
  43. }
  44. // XXX: Because we don't have the GIL, this is a race condition.
  45. if (!PyInterpreterState_Head()) {
  46. // We have to leak the thread state, if the
  47. // interpreter has shut down when we're getting
  48. // deallocated, we can't run the cleanup code that
  49. // deleting it would imply.
  50. return;
  51. }
  52. AddToCleanupQueue(state);
  53. }
  54. private:
  55. // If the state has an allocated main greenlet:
  56. // - mark the greenlet as dead by disassociating it from the state;
  57. // - return 1
  58. // Otherwise, return 0.
  59. static bool
  60. MarkGreenletDeadIfNeeded(ThreadState* const state)
  61. {
  62. if (state && state->has_main_greenlet()) {
  63. // mark the thread as dead ASAP.
  64. // this is racy! If we try to throw or switch to a
  65. // greenlet from this thread from some other thread before
  66. // we clear the state pointer, it won't realize the state
  67. // is dead which can crash the process.
  68. PyGreenlet* p(state->borrow_main_greenlet().borrow());
  69. assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr);
  70. dynamic_cast<MainGreenlet*>(p->pimpl)->thread_state(nullptr);
  71. return true;
  72. }
  73. return false;
  74. }
  75. static void
  76. AddToCleanupQueue(ThreadState* const state)
  77. {
  78. assert(state && state->has_main_greenlet());
  79. // NOTE: Because we're not holding the GIL here, some other
  80. // Python thread could run and call ``os.fork()``, which would
  81. // be bad if that happened while we are holding the cleanup
  82. // lock (it wouldn't function in the child process).
  83. // Make a best effort to try to keep the duration we hold the
  84. // lock short.
  85. // TODO: On platforms that support it, use ``pthread_atfork`` to
  86. // drop this lock.
  87. LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock);
  88. mod_globs->queue_to_destroy(state);
  89. if (mod_globs->thread_states_to_destroy.size() == 1) {
  90. // We added the first item to the queue. We need to schedule
  91. // the cleanup.
  92. // A size greater than 1 means that we have already added the pending call,
  93. // and in fact, it may be executing now.
  94. // If it is executing, our lock makes sure that it will see the item we just added
  95. // to the queue on its next iteration (after we release the lock)
  96. //
  97. // A size of 1 means there is no pending call, OR the pending call is
  98. // currently executing, has dropped the lock, and is deleting the last item
  99. // from the queue; its next iteration will go ahead and delete the item we just added.
  100. // And the pending call we schedule here will have no work to do.
  101. int result = AddPendingCall(
  102. PendingCallback_DestroyQueueWithGIL,
  103. nullptr);
  104. if (result < 0) {
  105. // Hmm, what can we do here?
  106. fprintf(stderr,
  107. "greenlet: WARNING: failed in call to Py_AddPendingCall; "
  108. "expect a memory leak.\n");
  109. }
  110. }
  111. }
  112. static int
  113. PendingCallback_DestroyQueueWithGIL(void* UNUSED(arg))
  114. {
  115. // We're holding the GIL here, so no Python code should be able to
  116. // run to call ``os.fork()``.
  117. while (1) {
  118. ThreadState* to_destroy;
  119. {
  120. LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock);
  121. if (mod_globs->thread_states_to_destroy.empty()) {
  122. break;
  123. }
  124. to_destroy = mod_globs->take_next_to_destroy();
  125. }
  126. assert(to_destroy);
  127. assert(to_destroy->has_main_greenlet());
  128. // Drop the lock while we do the actual deletion.
  129. // This allows other calls to MarkGreenletDeadAndQueueCleanup
  130. // to enter and add to our queue.
  131. DestroyOneWithGIL(to_destroy);
  132. }
  133. return 0;
  134. }
  135. static void
  136. DestroyOneWithGIL(const ThreadState* const state)
  137. {
  138. // Holding the GIL.
  139. // Passed a non-shared pointer to the actual thread state.
  140. // state -> main greenlet
  141. assert(state->has_main_greenlet());
  142. PyGreenlet* main(state->borrow_main_greenlet());
  143. // When we need to do cross-thread operations, we check this.
  144. // A NULL value means the thread died some time ago.
  145. // We do this here, rather than in a Python dealloc function
  146. // for the greenlet, in case there's still a reference out
  147. // there.
  148. dynamic_cast<MainGreenlet*>(main->pimpl)->thread_state(nullptr);
  149. delete state; // Deleting this runs the destructor, DECREFs the main greenlet.
  150. }
  151. static int AddPendingCall(int (*func)(void*), void* arg)
  152. {
  153. // If the interpreter is in the middle of finalizing, we can't add a
  154. // pending call. Trying to do so will end up in a SIGSEGV, as
  155. // Py_AddPendingCall will not be able to get the interpreter and will
  156. // try to dereference a NULL pointer. It's possible this can still
  157. // segfault if we happen to get context switched, and maybe we should
  158. // just always implement our own AddPendingCall, but I'd like to see if
  159. // this works first
  160. #if GREENLET_PY313
  161. if (Py_IsFinalizing()) {
  162. #else
  163. if (_Py_IsFinalizing()) {
  164. #endif
  165. #ifdef GREENLET_DEBUG
  166. // No need to log in the general case. Yes, we'll leak,
  167. // but we're shutting down so it should be ok.
  168. fprintf(stderr,
  169. "greenlet: WARNING: Interpreter is finalizing. Ignoring "
  170. "call to Py_AddPendingCall; \n");
  171. #endif
  172. return 0;
  173. }
  174. return Py_AddPendingCall(func, arg);
  175. }
  176. };
  177. };
  178. }; // namespace greenlet
  179. // The intent when GET_THREAD_STATE() is needed multiple times in a
  180. // function is to take a reference to its return value in a local
  181. // variable, to avoid the thread-local indirection. On some platforms
  182. // (macOS), accessing a thread-local involves a function call (plus an
  183. // initial function call in each function that uses a thread local);
  184. // in contrast, static volatile variables are at some pre-computed
  185. // offset.
  186. typedef greenlet::ThreadStateCreator<greenlet::ThreadState_DestroyNoGIL::MarkGreenletDeadAndQueueCleanup> ThreadStateCreator;
  187. static thread_local ThreadStateCreator g_thread_state_global;
  188. #define GET_THREAD_STATE() g_thread_state_global
  189. #endif //T_THREADSTATE_DESTROY