TGreenlet.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
  2. /**
  3. * Implementation of greenlet::Greenlet.
  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 TGREENLET_CPP
  13. #define TGREENLET_CPP
  14. #include "greenlet_internal.hpp"
  15. #include "TGreenlet.hpp"
  16. #include "TGreenletGlobals.cpp"
  17. #include "TThreadStateDestroy.cpp"
  18. namespace greenlet {
  19. Greenlet::Greenlet(PyGreenlet* p)
  20. : Greenlet(p, StackState())
  21. {
  22. }
  23. Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack)
  24. : _self(p), stack_state(initial_stack)
  25. {
  26. assert(p->pimpl == nullptr);
  27. p->pimpl = this;
  28. }
  29. Greenlet::~Greenlet()
  30. {
  31. // XXX: Can't do this. tp_clear is a virtual function, and by the
  32. // time we're here, we've sliced off our child classes.
  33. //this->tp_clear();
  34. this->_self->pimpl = nullptr;
  35. }
  36. bool
  37. Greenlet::force_slp_switch_error() const noexcept
  38. {
  39. return false;
  40. }
  41. void
  42. Greenlet::release_args()
  43. {
  44. this->switch_args.CLEAR();
  45. }
  46. /**
  47. * CAUTION: This will allocate memory and may trigger garbage
  48. * collection and arbitrary Python code.
  49. */
  50. OwnedObject
  51. Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state))
  52. {
  53. // If we're killed because we lost all references in the
  54. // middle of a switch, that's ok. Don't reset the args/kwargs,
  55. // we still want to pass them to the parent.
  56. PyErr_SetString(mod_globs->PyExc_GreenletExit,
  57. "Killing the greenlet because all references have vanished.");
  58. // To get here it had to have run before
  59. return this->g_switch();
  60. }
  61. inline void
  62. Greenlet::slp_restore_state() noexcept
  63. {
  64. #ifdef SLP_BEFORE_RESTORE_STATE
  65. SLP_BEFORE_RESTORE_STATE();
  66. #endif
  67. this->stack_state.copy_heap_to_stack(
  68. this->thread_state()->borrow_current()->stack_state);
  69. }
  70. inline int
  71. Greenlet::slp_save_state(char *const stackref) noexcept
  72. {
  73. // XXX: This used to happen in the middle, before saving, but
  74. // after finding the next owner. Does that matter? This is
  75. // only defined for Sparc/GCC where it flushes register
  76. // windows to the stack (I think)
  77. #ifdef SLP_BEFORE_SAVE_STATE
  78. SLP_BEFORE_SAVE_STATE();
  79. #endif
  80. return this->stack_state.copy_stack_to_heap(stackref,
  81. this->thread_state()->borrow_current()->stack_state);
  82. }
  83. /**
  84. * CAUTION: This will allocate memory and may trigger garbage
  85. * collection and arbitrary Python code.
  86. */
  87. OwnedObject
  88. Greenlet::on_switchstack_or_initialstub_failure(
  89. Greenlet* target,
  90. const Greenlet::switchstack_result_t& err,
  91. const bool target_was_me,
  92. const bool was_initial_stub)
  93. {
  94. // If we get here, either g_initialstub()
  95. // failed, or g_switchstack() failed. Either one of those
  96. // cases SHOULD leave us in the original greenlet with a valid stack.
  97. if (!PyErr_Occurred()) {
  98. PyErr_SetString(
  99. PyExc_SystemError,
  100. was_initial_stub
  101. ? "Failed to switch stacks into a greenlet for the first time."
  102. : "Failed to switch stacks into a running greenlet.");
  103. }
  104. this->release_args();
  105. if (target && !target_was_me) {
  106. target->murder_in_place();
  107. }
  108. assert(!err.the_new_current_greenlet);
  109. assert(!err.origin_greenlet);
  110. return OwnedObject();
  111. }
  112. OwnedGreenlet
  113. Greenlet::g_switchstack_success() noexcept
  114. {
  115. PyThreadState* tstate = PyThreadState_GET();
  116. // restore the saved state
  117. this->python_state >> tstate;
  118. this->exception_state >> tstate;
  119. // The thread state hasn't been changed yet.
  120. ThreadState* thread_state = this->thread_state();
  121. OwnedGreenlet result(thread_state->get_current());
  122. thread_state->set_current(this->self());
  123. //assert(thread_state->borrow_current().borrow() == this->_self);
  124. return result;
  125. }
  126. Greenlet::switchstack_result_t
  127. Greenlet::g_switchstack(void)
  128. {
  129. // if any of these assertions fail, it's likely because we
  130. // switched away and tried to switch back to us. Early stages of
  131. // switching are not reentrant because we re-use ``this->args()``.
  132. // Switching away would happen if we trigger a garbage collection
  133. // (by just using some Python APIs that happen to allocate Python
  134. // objects) and some garbage had weakref callbacks or __del__ that
  135. // switches (people don't write code like that by hand, but with
  136. // gevent it's possible without realizing it)
  137. assert(this->args() || PyErr_Occurred());
  138. { /* save state */
  139. if (this->thread_state()->is_current(this->self())) {
  140. // Hmm, nothing to do.
  141. // TODO: Does this bypass trace events that are
  142. // important?
  143. return switchstack_result_t(0,
  144. this, this->thread_state()->borrow_current());
  145. }
  146. BorrowedGreenlet current = this->thread_state()->borrow_current();
  147. PyThreadState* tstate = PyThreadState_GET();
  148. current->python_state << tstate;
  149. current->exception_state << tstate;
  150. this->python_state.will_switch_from(tstate);
  151. switching_thread_state = this;
  152. current->expose_frames();
  153. }
  154. assert(this->args() || PyErr_Occurred());
  155. // If this is the first switch into a greenlet, this will
  156. // return twice, once with 1 in the new greenlet, once with 0
  157. // in the origin.
  158. int err;
  159. if (this->force_slp_switch_error()) {
  160. err = -1;
  161. }
  162. else {
  163. err = slp_switch();
  164. }
  165. if (err < 0) { /* error */
  166. // Tested by
  167. // test_greenlet.TestBrokenGreenlets.test_failed_to_slp_switch_into_running
  168. //
  169. // It's not clear if it's worth trying to clean up and
  170. // continue here. Failing to switch stacks is a big deal which
  171. // may not be recoverable (who knows what state the stack is in).
  172. // Also, we've stolen references in preparation for calling
  173. // ``g_switchstack_success()`` and we don't have a clean
  174. // mechanism for backing that all out.
  175. Py_FatalError("greenlet: Failed low-level slp_switch(). The stack is probably corrupt.");
  176. }
  177. // No stack-based variables are valid anymore.
  178. // But the global is volatile so we can reload it without the
  179. // compiler caching it from earlier.
  180. Greenlet* greenlet_that_switched_in = switching_thread_state; // aka this
  181. switching_thread_state = nullptr;
  182. // except that no stack variables are valid, we would:
  183. // assert(this == greenlet_that_switched_in);
  184. // switchstack success is where we restore the exception state,
  185. // etc. It returns the origin greenlet because its convenient.
  186. OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success();
  187. assert(greenlet_that_switched_in->args() || PyErr_Occurred());
  188. return switchstack_result_t(err, greenlet_that_switched_in, origin);
  189. }
  190. inline void
  191. Greenlet::check_switch_allowed() const
  192. {
  193. // TODO: Make this take a parameter of the current greenlet,
  194. // or current main greenlet, to make the check for
  195. // cross-thread switching cheaper. Surely somewhere up the
  196. // call stack we've already accessed the thread local variable.
  197. // We expect to always have a main greenlet now; accessing the thread state
  198. // created it. However, if we get here and cleanup has already
  199. // begun because we're a greenlet that was running in a
  200. // (now dead) thread, these invariants will not hold true. In
  201. // fact, accessing `this->thread_state` may not even be possible.
  202. // If the thread this greenlet was running in is dead,
  203. // we'll still have a reference to a main greenlet, but the
  204. // thread state pointer we have is bogus.
  205. // TODO: Give the objects an API to determine if they belong
  206. // to a dead thread.
  207. const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage();
  208. if (!main_greenlet) {
  209. throw PyErrOccurred(mod_globs->PyExc_GreenletError,
  210. "cannot switch to a garbage collected greenlet");
  211. }
  212. if (!main_greenlet->thread_state()) {
  213. throw PyErrOccurred(mod_globs->PyExc_GreenletError,
  214. "cannot switch to a different thread (which happens to have exited)");
  215. }
  216. // The main greenlet we found was from the .parent lineage.
  217. // That may or may not have any relationship to the main
  218. // greenlet of the running thread. We can't actually access
  219. // our this->thread_state members to try to check that,
  220. // because it could be in the process of getting destroyed,
  221. // but setting the main_greenlet->thread_state member to NULL
  222. // may not be visible yet. So we need to check against the
  223. // current thread state (once the cheaper checks are out of
  224. // the way)
  225. const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet();
  226. if (
  227. // lineage main greenlet is not this thread's greenlet
  228. current_main_greenlet != main_greenlet
  229. || (
  230. // atteched to some thread
  231. this->main_greenlet()
  232. // XXX: Same condition as above. Was this supposed to be
  233. // this->main_greenlet()?
  234. && current_main_greenlet != main_greenlet)
  235. // switching into a known dead thread (XXX: which, if we get here,
  236. // is bad, because we just accessed the thread state, which is
  237. // gone!)
  238. || (!current_main_greenlet->thread_state())) {
  239. // CAUTION: This may trigger memory allocations, gc, and
  240. // arbitrary Python code.
  241. throw PyErrOccurred(
  242. mod_globs->PyExc_GreenletError,
  243. "Cannot switch to a different thread\n\tCurrent: %R\n\tExpected: %R",
  244. current_main_greenlet, main_greenlet);
  245. }
  246. }
  247. const OwnedObject
  248. Greenlet::context() const
  249. {
  250. using greenlet::PythonStateContext;
  251. OwnedObject result;
  252. if (this->is_currently_running_in_some_thread()) {
  253. /* Currently running greenlet: context is stored in the thread state,
  254. not the greenlet object. */
  255. if (GET_THREAD_STATE().state().is_current(this->self())) {
  256. result = PythonStateContext::context(PyThreadState_GET());
  257. }
  258. else {
  259. throw ValueError(
  260. "cannot get context of a "
  261. "greenlet that is running in a different thread");
  262. }
  263. }
  264. else {
  265. /* Greenlet is not running: just return context. */
  266. result = this->python_state.context();
  267. }
  268. if (!result) {
  269. result = OwnedObject::None();
  270. }
  271. return result;
  272. }
  273. void
  274. Greenlet::context(BorrowedObject given)
  275. {
  276. using greenlet::PythonStateContext;
  277. if (!given) {
  278. throw AttributeError("can't delete context attribute");
  279. }
  280. if (given.is_None()) {
  281. /* "Empty context" is stored as NULL, not None. */
  282. given = nullptr;
  283. }
  284. //checks type, incrs refcnt
  285. greenlet::refs::OwnedContext context(given);
  286. PyThreadState* tstate = PyThreadState_GET();
  287. if (this->is_currently_running_in_some_thread()) {
  288. if (!GET_THREAD_STATE().state().is_current(this->self())) {
  289. throw ValueError("cannot set context of a greenlet"
  290. " that is running in a different thread");
  291. }
  292. /* Currently running greenlet: context is stored in the thread state,
  293. not the greenlet object. */
  294. OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate));
  295. PythonStateContext::context(tstate, context.relinquish_ownership());
  296. }
  297. else {
  298. /* Greenlet is not running: just set context. Note that the
  299. greenlet may be dead.*/
  300. this->python_state.context() = context;
  301. }
  302. }
  303. /**
  304. * CAUTION: May invoke arbitrary Python code.
  305. *
  306. * Figure out what the result of ``greenlet.switch(arg, kwargs)``
  307. * should be and transfers ownership of it to the left-hand-side.
  308. *
  309. * If switch() was just passed an arg tuple, then we'll just return that.
  310. * If only keyword arguments were passed, then we'll pass the keyword
  311. * argument dict. Otherwise, we'll create a tuple of (args, kwargs) and
  312. * return both.
  313. *
  314. * CAUTION: This may allocate a new tuple object, which may
  315. * cause the Python garbage collector to run, which in turn may
  316. * run arbitrary Python code that switches.
  317. */
  318. OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept
  319. {
  320. // Because this may invoke arbitrary Python code, which could
  321. // result in switching back to us, we need to get the
  322. // arguments locally on the stack.
  323. assert(rhs);
  324. OwnedObject args = rhs.args();
  325. OwnedObject kwargs = rhs.kwargs();
  326. rhs.CLEAR();
  327. // We shouldn't be called twice for the same switch.
  328. assert(args || kwargs);
  329. assert(!rhs);
  330. if (!kwargs) {
  331. lhs = args;
  332. }
  333. else if (!PyDict_Size(kwargs.borrow())) {
  334. lhs = args;
  335. }
  336. else if (!PySequence_Length(args.borrow())) {
  337. lhs = kwargs;
  338. }
  339. else {
  340. // PyTuple_Pack allocates memory, may GC, may run arbitrary
  341. // Python code.
  342. lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow()));
  343. }
  344. return lhs;
  345. }
  346. static OwnedObject
  347. g_handle_exit(const OwnedObject& greenlet_result)
  348. {
  349. if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) {
  350. /* catch and ignore GreenletExit */
  351. PyErrFetchParam val;
  352. PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam());
  353. if (!val) {
  354. return OwnedObject::None();
  355. }
  356. return OwnedObject(val);
  357. }
  358. if (greenlet_result) {
  359. // package the result into a 1-tuple
  360. // PyTuple_Pack increments the reference of its arguments,
  361. // so we always need to decref the greenlet result;
  362. // the owner will do that.
  363. return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow()));
  364. }
  365. return OwnedObject();
  366. }
  367. /**
  368. * May run arbitrary Python code.
  369. */
  370. OwnedObject
  371. Greenlet::g_switch_finish(const switchstack_result_t& err)
  372. {
  373. assert(err.the_new_current_greenlet == this);
  374. ThreadState& state = *this->thread_state();
  375. // Because calling the trace function could do arbitrary things,
  376. // including switching away from this greenlet and then maybe
  377. // switching back, we need to capture the arguments now so that
  378. // they don't change.
  379. OwnedObject result;
  380. if (this->args()) {
  381. result <<= this->args();
  382. }
  383. else {
  384. assert(PyErr_Occurred());
  385. }
  386. assert(!this->args());
  387. try {
  388. // Our only caller handles the bad error case
  389. assert(err.status >= 0);
  390. assert(state.borrow_current() == this->self());
  391. if (OwnedObject tracefunc = state.get_tracefunc()) {
  392. assert(result || PyErr_Occurred());
  393. g_calltrace(tracefunc,
  394. result ? mod_globs->event_switch : mod_globs->event_throw,
  395. err.origin_greenlet,
  396. this->self());
  397. }
  398. // The above could have invoked arbitrary Python code, but
  399. // it couldn't switch back to this object and *also*
  400. // throw an exception, so the args won't have changed.
  401. if (PyErr_Occurred()) {
  402. // We get here if we fell of the end of the run() function
  403. // raising an exception. The switch itself was
  404. // successful, but the function raised.
  405. // valgrind reports that memory allocated here can still
  406. // be reached after a test run.
  407. throw PyErrOccurred::from_current();
  408. }
  409. return result;
  410. }
  411. catch (const PyErrOccurred&) {
  412. /* Turn switch errors into switch throws */
  413. /* Turn trace errors into switch throws */
  414. this->release_args();
  415. throw;
  416. }
  417. }
  418. void
  419. Greenlet::g_calltrace(const OwnedObject& tracefunc,
  420. const greenlet::refs::ImmortalEventName& event,
  421. const BorrowedGreenlet& origin,
  422. const BorrowedGreenlet& target)
  423. {
  424. PyErrPieces saved_exc;
  425. try {
  426. TracingGuard tracing_guard;
  427. // TODO: We have saved the active exception (if any) that's
  428. // about to be raised. In the 'throw' case, we could provide
  429. // the exception to the tracefunction, which seems very helpful.
  430. tracing_guard.CallTraceFunction(tracefunc, event, origin, target);
  431. }
  432. catch (const PyErrOccurred&) {
  433. // In case of exceptions trace function is removed,
  434. // and any existing exception is replaced with the tracing
  435. // exception.
  436. GET_THREAD_STATE().state().set_tracefunc(Py_None);
  437. throw;
  438. }
  439. saved_exc.PyErrRestore();
  440. assert(
  441. (event == mod_globs->event_throw && PyErr_Occurred())
  442. || (event == mod_globs->event_switch && !PyErr_Occurred())
  443. );
  444. }
  445. void
  446. Greenlet::murder_in_place()
  447. {
  448. if (this->active()) {
  449. assert(!this->is_currently_running_in_some_thread());
  450. this->deactivate_and_free();
  451. }
  452. }
  453. inline void
  454. Greenlet::deactivate_and_free()
  455. {
  456. if (!this->active()) {
  457. return;
  458. }
  459. // Throw away any saved stack.
  460. this->stack_state = StackState();
  461. assert(!this->stack_state.active());
  462. // Throw away any Python references.
  463. // We're holding a borrowed reference to the last
  464. // frame we executed. Since we borrowed it, the
  465. // normal traversal, clear, and dealloc functions
  466. // ignore it, meaning it leaks. (The thread state
  467. // object can't find it to clear it when that's
  468. // deallocated either, because by definition if we
  469. // got an object on this list, it wasn't
  470. // running and the thread state doesn't have
  471. // this frame.)
  472. // So here, we *do* clear it.
  473. this->python_state.tp_clear(true);
  474. }
  475. bool
  476. Greenlet::belongs_to_thread(const ThreadState* thread_state) const
  477. {
  478. if (!this->thread_state() // not running anywhere, or thread
  479. // exited
  480. || !thread_state) { // same, or there is no thread state.
  481. return false;
  482. }
  483. return true;
  484. }
  485. void
  486. Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state)
  487. {
  488. /* Cannot raise an exception to kill the greenlet if
  489. it is not running in the same thread! */
  490. if (this->belongs_to_thread(current_thread_state)) {
  491. assert(current_thread_state);
  492. // To get here it had to have run before
  493. /* Send the greenlet a GreenletExit exception. */
  494. // We don't care about the return value, only whether an
  495. // exception happened.
  496. this->throw_GreenletExit_during_dealloc(*current_thread_state);
  497. return;
  498. }
  499. // Not the same thread! Temporarily save the greenlet
  500. // into its thread's deleteme list, *if* it exists.
  501. // If that thread has already exited, and processed its pending
  502. // cleanup, we'll never be able to clean everything up: we won't
  503. // be able to raise an exception.
  504. // That's mostly OK! Since we can't add it to a list, our refcount
  505. // won't increase, and we'll go ahead with the DECREFs later.
  506. ThreadState *const thread_state = this->thread_state();
  507. if (thread_state) {
  508. thread_state->delete_when_thread_running(this->self());
  509. }
  510. else {
  511. // The thread is dead, we can't raise an exception.
  512. // We need to make it look non-active, though, so that dealloc
  513. // finishes killing it.
  514. this->deactivate_and_free();
  515. }
  516. return;
  517. }
  518. int
  519. Greenlet::tp_traverse(visitproc visit, void* arg)
  520. {
  521. int result;
  522. if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) {
  523. return result;
  524. }
  525. //XXX: This is ugly. But so is handling everything having to do
  526. //with the top frame.
  527. bool visit_top_frame = this->was_running_in_dead_thread();
  528. // When true, the thread is dead. Our implicit weak reference to the
  529. // frame is now all that's left; we consider ourselves to
  530. // strongly own it now.
  531. if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) {
  532. return result;
  533. }
  534. return 0;
  535. }
  536. int
  537. Greenlet::tp_clear()
  538. {
  539. bool own_top_frame = this->was_running_in_dead_thread();
  540. this->exception_state.tp_clear();
  541. this->python_state.tp_clear(own_top_frame);
  542. return 0;
  543. }
  544. bool Greenlet::is_currently_running_in_some_thread() const
  545. {
  546. return this->stack_state.active() && !this->python_state.top_frame();
  547. }
  548. #if GREENLET_PY312
  549. void GREENLET_NOINLINE(Greenlet::expose_frames)()
  550. {
  551. if (!this->python_state.top_frame()) {
  552. return;
  553. }
  554. _PyInterpreterFrame* last_complete_iframe = nullptr;
  555. _PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame;
  556. while (iframe) {
  557. // We must make a copy before looking at the iframe contents,
  558. // since iframe might point to a portion of the greenlet's C stack
  559. // that was spilled when switching greenlets.
  560. _PyInterpreterFrame iframe_copy;
  561. this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe));
  562. if (!_PyFrame_IsIncomplete(&iframe_copy)) {
  563. // If the iframe were OWNED_BY_CSTACK then it would always be
  564. // incomplete. Since it's not incomplete, it's not on the C stack
  565. // and we can access it through the original `iframe` pointer
  566. // directly. This is important since GetFrameObject might
  567. // lazily _create_ the frame object and we don't want the
  568. // interpreter to lose track of it.
  569. assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK);
  570. // We really want to just write:
  571. // PyFrameObject* frame = _PyFrame_GetFrameObject(iframe);
  572. // but _PyFrame_GetFrameObject calls _PyFrame_MakeAndSetFrameObject
  573. // which is not a visible symbol in libpython. The easiest
  574. // way to get a public function to call it is using
  575. // PyFrame_GetBack, which is defined as follows:
  576. // assert(frame != NULL);
  577. // assert(!_PyFrame_IsIncomplete(frame->f_frame));
  578. // PyFrameObject *back = frame->f_back;
  579. // if (back == NULL) {
  580. // _PyInterpreterFrame *prev = frame->f_frame->previous;
  581. // prev = _PyFrame_GetFirstComplete(prev);
  582. // if (prev) {
  583. // back = _PyFrame_GetFrameObject(prev);
  584. // }
  585. // }
  586. // return (PyFrameObject*)Py_XNewRef(back);
  587. if (!iframe->frame_obj) {
  588. PyFrameObject dummy_frame;
  589. _PyInterpreterFrame dummy_iframe;
  590. dummy_frame.f_back = nullptr;
  591. dummy_frame.f_frame = &dummy_iframe;
  592. // force the iframe to be considered complete without
  593. // needing to check its code object:
  594. dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR;
  595. dummy_iframe.previous = iframe;
  596. assert(!_PyFrame_IsIncomplete(&dummy_iframe));
  597. // Drop the returned reference immediately; the iframe
  598. // continues to hold a strong reference
  599. Py_XDECREF(PyFrame_GetBack(&dummy_frame));
  600. assert(iframe->frame_obj);
  601. }
  602. // This is a complete frame, so make the last one of those we saw
  603. // point at it, bypassing any incomplete frames (which may have
  604. // been on the C stack) in between the two. We're overwriting
  605. // last_complete_iframe->previous and need that to be reversible,
  606. // so we store the original previous ptr in the frame object
  607. // (which we must have created on a previous iteration through
  608. // this loop). The frame object has a bunch of storage that is
  609. // only used when its iframe is OWNED_BY_FRAME_OBJECT, which only
  610. // occurs when the frame object outlives the frame's execution,
  611. // which can't have happened yet because the frame is currently
  612. // executing as far as the interpreter is concerned. So, we can
  613. // reuse it for our own purposes.
  614. assert(iframe->owner == FRAME_OWNED_BY_THREAD
  615. || iframe->owner == FRAME_OWNED_BY_GENERATOR);
  616. if (last_complete_iframe) {
  617. assert(last_complete_iframe->frame_obj);
  618. memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
  619. &last_complete_iframe->previous, sizeof(void *));
  620. last_complete_iframe->previous = iframe;
  621. }
  622. last_complete_iframe = iframe;
  623. }
  624. // Frames that are OWNED_BY_FRAME_OBJECT are linked via the
  625. // frame's f_back while all others are linked via the iframe's
  626. // previous ptr. Since all the frames we traverse are running
  627. // as far as the interpreter is concerned, we don't have to
  628. // worry about the OWNED_BY_FRAME_OBJECT case.
  629. iframe = iframe_copy.previous;
  630. }
  631. // Give the outermost complete iframe a null previous pointer to
  632. // account for any potential incomplete/C-stack iframes between it
  633. // and the actual top-of-stack
  634. if (last_complete_iframe) {
  635. assert(last_complete_iframe->frame_obj);
  636. memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
  637. &last_complete_iframe->previous, sizeof(void *));
  638. last_complete_iframe->previous = nullptr;
  639. }
  640. }
  641. #else
  642. void Greenlet::expose_frames()
  643. {
  644. }
  645. #endif
  646. }; // namespace greenlet
  647. #endif