Qucs-S S-parameter Viewer & RF Synthesis Tools
Loading...
Searching...
No Matches
TUserGreenlet.cpp
1/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
12#ifndef T_USER_GREENLET_CPP
13#define T_USER_GREENLET_CPP
14
15#include "greenlet_internal.hpp"
16#include "TGreenlet.hpp"
17
18#include "TThreadStateDestroy.cpp"
19
20
21namespace greenlet {
23greenlet::PythonAllocator<UserGreenlet> UserGreenlet::allocator;
24
25void* UserGreenlet::operator new(size_t UNUSED(count))
26{
27 return allocator.allocate(1);
28}
29
30
31void UserGreenlet::operator delete(void* ptr)
32{
33 return allocator.deallocate(static_cast<UserGreenlet*>(ptr),
34 1);
35}
36
37
38UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent)
39 : Greenlet(p), _parent(the_parent)
40{
41}
42
43UserGreenlet::~UserGreenlet()
44{
45 // Python 3.11: If we don't clear out the raw frame datastack
46 // when deleting an unfinished greenlet,
47 // TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails.
48 this->python_state.did_finish(nullptr);
49 this->tp_clear();
50}
51
52
54UserGreenlet::main_greenlet() const
55{
56 return this->_main_greenlet;
57}
58
59
61UserGreenlet::find_main_greenlet_in_lineage() const
62{
63 if (this->started()) {
64 assert(this->_main_greenlet);
65 return BorrowedMainGreenlet(this->_main_greenlet);
66 }
67
68 if (!this->_parent) {
69 /* garbage collected greenlet in chain */
70 // XXX: WHAT?
71 return BorrowedMainGreenlet(nullptr);
72 }
73
74 return this->_parent->find_main_greenlet_in_lineage();
75}
76
77
82OwnedObject
83UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state)
84{
85 /* The dying greenlet cannot be a parent of ts_current
86 because the 'parent' field chain would hold a
87 reference */
88 UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state);
89
90 // We don't care about the return value, only whether an
91 // exception happened. Whether or not an exception happens,
92 // we need to restore the parent in case the greenlet gets
93 // resurrected.
94 return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state);
95}
96
98UserGreenlet::thread_state() const noexcept
99{
100 // TODO: maybe make this throw, if the thread state isn't there?
101 // if (!this->main_greenlet) {
102 // throw std::runtime_error("No thread state"); // TODO: Better exception
103 // }
104 if (!this->_main_greenlet) {
105 return nullptr;
106 }
107 return this->_main_greenlet->thread_state();
108}
109
110
111bool
112UserGreenlet::was_running_in_dead_thread() const noexcept
113{
114 return this->_main_greenlet && !this->thread_state();
115}
116
117OwnedObject
118UserGreenlet::g_switch()
119{
120 assert(this->args() || PyErr_Occurred());
121
122 try {
123 this->check_switch_allowed();
124 }
125 catch (const PyErrOccurred&) {
126 this->release_args();
127 throw;
128 }
129
130 // Switching greenlets used to attempt to clean out ones that need
131 // deleted *if* we detected a thread switch. Should it still do
132 // that?
133 // An issue is that if we delete a greenlet from another thread,
134 // it gets queued to this thread, and ``kill_greenlet()`` switches
135 // back into the greenlet
136
137 /* find the real target by ignoring dead greenlets,
138 and if necessary starting a greenlet. */
139 switchstack_result_t err;
140 Greenlet* target = this;
141 // TODO: probably cleaner to handle the case where we do
142 // switch to ourself separately from the other cases.
143 // This can probably even further be simplified if we keep
144 // track of the switching_state we're going for and just call
145 // into g_switch() if it's not ourself. The main problem with that
146 // is that we would be using more stack space.
147 bool target_was_me = true;
148 bool was_initial_stub = false;
149 while (target) {
150 if (target->active()) {
151 if (!target_was_me) {
152 target->args() <<= this->args();
153 assert(!this->args());
154 }
155 err = target->g_switchstack();
156 break;
157 }
158 if (!target->started()) {
159 // We never encounter a main greenlet that's not started.
160 assert(!target->main());
161 UserGreenlet* real_target = static_cast<UserGreenlet*>(target);
162 assert(real_target);
163 void* dummymarker;
164 was_initial_stub = true;
165 if (!target_was_me) {
166 target->args() <<= this->args();
167 assert(!this->args());
168 }
169 try {
170 // This can only throw back to us while we're
171 // still in this greenlet. Once the new greenlet
172 // is bootstrapped, it has its own exception state.
173 err = real_target->g_initialstub(&dummymarker);
174 }
175 catch (const PyErrOccurred&) {
176 this->release_args();
177 throw;
178 }
179 catch (const GreenletStartedWhileInPython&) {
180 // The greenlet was started sometime before this
181 // greenlet actually switched to it, i.e.,
182 // "concurrent" calls to switch() or throw().
183 // We need to retry the switch.
184 // Note that the current greenlet has been reset
185 // to this one (or we wouldn't be running!)
186 continue;
187 }
188 break;
189 }
190
191 target = target->parent();
192 target_was_me = false;
193 }
194 // The ``this`` pointer and all other stack or register based
195 // variables are invalid now, at least where things succeed
196 // above.
197 // But this one, probably not so much? It's not clear if it's
198 // safe to throw an exception at this point.
199
200 if (err.status < 0) {
201 // If we get here, either g_initialstub()
202 // failed, or g_switchstack() failed. Either one of those
203 // cases SHOULD leave us in the original greenlet with a valid
204 // stack.
205 return this->on_switchstack_or_initialstub_failure(target, err, target_was_me, was_initial_stub);
206 }
207
208 // err.the_new_current_greenlet would be the same as ``target``,
209 // if target wasn't probably corrupt.
210 return err.the_new_current_greenlet->g_switch_finish(err);
211}
212
213
214
215Greenlet::switchstack_result_t
216UserGreenlet::g_initialstub(void* mark)
217{
218 OwnedObject run;
219
220 // We need to grab a reference to the current switch arguments
221 // in case we're entered concurrently during the call to
222 // GetAttr() and have to try again.
223 // We'll restore them when we return in that case.
224 // Scope them tightly to avoid ref leaks.
225 {
226 SwitchingArgs args(this->args());
227
228 /* save exception in case getattr clears it */
229 PyErrPieces saved;
230
231 /*
232 self.run is the object to call in the new greenlet.
233 This could run arbitrary python code and switch greenlets!
234 */
235 run = this->self().PyRequireAttr(mod_globs->str_run);
236 /* restore saved exception */
237 saved.PyErrRestore();
238
239
240 /* recheck that it's safe to switch in case greenlet reparented anywhere above */
241 this->check_switch_allowed();
242
243 /* by the time we got here another start could happen elsewhere,
244 * that means it should now be a regular switch.
245 * This can happen if the Python code is a subclass that implements
246 * __getattribute__ or __getattr__, or makes ``run`` a descriptor;
247 * all of those can run arbitrary code that switches back into
248 * this greenlet.
249 */
250 if (this->stack_state.started()) {
251 // the successful switch cleared these out, we need to
252 // restore our version. They will be copied on up to the
253 // next target.
254 assert(!this->args());
255 this->args() <<= args;
256 throw GreenletStartedWhileInPython();
257 }
258 }
259
260 // Sweet, if we got here, we have the go-ahead and will switch
261 // greenlets.
262 // Nothing we do from here on out should allow for a thread or
263 // greenlet switch: No arbitrary calls to Python, including
264 // decref'ing
265
266#if GREENLET_USE_CFRAME
267 /* OK, we need it, we're about to switch greenlets, save the state. */
268 /*
269 See green_new(). This is a stack-allocated variable used
270 while *self* is in PyObject_Call().
271 We want to defer copying the state info until we're sure
272 we need it and are in a stable place to do so.
273 */
274 _PyCFrame trace_info;
275
276 this->python_state.set_new_cframe(trace_info);
277#endif
278 /* start the greenlet */
279 ThreadState& thread_state = GET_THREAD_STATE().state();
280 this->stack_state = StackState(mark,
281 thread_state.borrow_current()->stack_state);
282 this->python_state.set_initial_state(PyThreadState_GET());
283 this->exception_state.clear();
284 this->_main_greenlet = thread_state.get_main_greenlet();
285
286 /* perform the initial switch */
287 switchstack_result_t err = this->g_switchstack();
288 /* returns twice!
289 The 1st time with ``err == 1``: we are in the new greenlet.
290 This one owns a greenlet that used to be current.
291 The 2nd time with ``err <= 0``: back in the caller's
292 greenlet; this happens if the child finishes or switches
293 explicitly to us. Either way, the ``err`` variable is
294 created twice at the same memory location, but possibly
295 having different ``origin`` values. Note that it's not
296 constructed for the second time until the switch actually happens.
297 */
298 if (err.status == 1) {
299 // In the new greenlet.
300
301 // This never returns! Calling inner_bootstrap steals
302 // the contents of our run object within this stack frame, so
303 // it is not valid to do anything with it.
304 try {
305 this->inner_bootstrap(err.origin_greenlet.relinquish_ownership(),
306 run.relinquish_ownership());
307 }
308 // Getting a C++ exception here isn't good. It's probably a
309 // bug in the underlying greenlet, meaning it's probably a
310 // C++ extension. We're going to abort anyway, but try to
311 // display some nice information *if* possible. Some obscure
312 // platforms don't properly support this (old 32-bit Arm, see see
313 // https://github.com/python-greenlet/greenlet/issues/385); that's not
314 // great, but should usually be OK because, as mentioned above, we're
315 // terminating anyway.
316 //
317 // The catching is tested by
318 // ``test_cpp.CPPTests.test_unhandled_exception_in_greenlet_aborts``.
319 //
320 // PyErrOccurred can theoretically be thrown by
321 // inner_bootstrap() -> g_switch_finish(), but that should
322 // never make it back to here. It is a std::exception and
323 // would be caught if it is.
324 catch (const std::exception& e) {
325 std::string base = "greenlet: Unhandled C++ exception: ";
326 base += e.what();
327 Py_FatalError(base.c_str());
328 }
329 catch (...) {
330 // Some compilers/runtimes use exceptions internally.
331 // It appears that GCC on Linux with libstdc++ throws an
332 // exception internally at process shutdown time to unwind
333 // stacks and clean up resources. Depending on exactly
334 // where we are when the process exits, that could result
335 // in an unknown exception getting here. If we
336 // Py_FatalError() or abort() here, we interfere with
337 // orderly process shutdown. Throwing the exception on up
338 // is the right thing to do.
339 //
340 // gevent's ``examples/dns_mass_resolve.py`` demonstrates this.
341#ifndef NDEBUG
342 fprintf(stderr,
343 "greenlet: inner_bootstrap threw unknown exception; "
344 "is the process terminating?\n");
345#endif
346 throw;
347 }
348 Py_FatalError("greenlet: inner_bootstrap returned with no exception.\n");
349 }
350
351
352 // In contrast, notice that we're keeping the origin greenlet
353 // around as an owned reference; we need it to call the trace
354 // function for the switch back into the parent. It was only
355 // captured at the time the switch actually happened, though,
356 // so we haven't been keeping an extra reference around this
357 // whole time.
358
359 /* back in the parent */
360 if (err.status < 0) {
361 /* start failed badly, restore greenlet state */
362 this->stack_state = StackState();
363 this->_main_greenlet.CLEAR();
364 // CAUTION: This may run arbitrary Python code.
365 run.CLEAR(); // inner_bootstrap didn't run, we own the reference.
366 }
367
368 // In the success case, the spawned code (inner_bootstrap) will
369 // take care of decrefing this, so we relinquish ownership so as
370 // to not double-decref.
371
372 run.relinquish_ownership();
373
374 return err;
375}
376
377
378void
379UserGreenlet::inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run)
380{
381 // The arguments here would be another great place for move.
382 // As it is, we take them as a reference so that when we clear
383 // them we clear what's on the stack above us. Do that NOW, and
384 // without using a C++ RAII object,
385 // so there's no way that exiting the parent frame can clear it,
386 // or we clear it unexpectedly. This arises in the context of the
387 // interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325
388 //PyObject* run = _run.relinquish_ownership();
389
390 /* in the new greenlet */
391 assert(this->thread_state()->borrow_current() == BorrowedGreenlet(this->_self));
392 // C++ exceptions cannot propagate to the parent greenlet from
393 // here. (TODO: Do we need a catch(...) clause, perhaps on the
394 // function itself? ALl we could do is terminate the program.)
395 // NOTE: On 32-bit Windows, the call chain is extremely
396 // important here in ways that are subtle, having to do with
397 // the depth of the SEH list. The call to restore it MUST NOT
398 // add a new SEH handler to the list, or we'll restore it to
399 // the wrong thing.
400 this->thread_state()->restore_exception_state();
401 /* stack variables from above are no good and also will not unwind! */
402 // EXCEPT: That can't be true, we access run, among others, here.
403
404 this->stack_state.set_active(); /* running */
405
406 // We're about to possibly run Python code again, which
407 // could switch back/away to/from us, so we need to grab the
408 // arguments locally.
409 SwitchingArgs args;
410 args <<= this->args();
411 assert(!this->args());
412
413 // XXX: We could clear this much earlier, right?
414 // Or would that introduce the possibility of running Python
415 // code when we don't want to?
416 // CAUTION: This may run arbitrary Python code.
417 this->_run_callable.CLEAR();
418
419
420 // The first switch we need to manually call the trace
421 // function here instead of in g_switch_finish, because we
422 // never return there.
423 if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) {
424 OwnedGreenlet trace_origin;
425 trace_origin = origin_greenlet;
426 try {
427 g_calltrace(tracefunc,
428 args ? mod_globs->event_switch : mod_globs->event_throw,
429 trace_origin,
430 this->_self);
431 }
432 catch (const PyErrOccurred&) {
433 /* Turn trace errors into switch throws */
434 args.CLEAR();
435 }
436 }
437
438 // We no longer need the origin, it was only here for
439 // tracing.
440 // We may never actually exit this stack frame so we need
441 // to explicitly clear it.
442 // This could run Python code and switch.
443 Py_CLEAR(origin_greenlet);
444
445 OwnedObject result;
446 if (!args) {
447 /* pending exception */
448 result = NULL;
449 }
450 else {
451 /* call g.run(*args, **kwargs) */
452 // This could result in further switches
453 try {
454 //result = run.PyCall(args.args(), args.kwargs());
455 // CAUTION: Just invoking this, before the function even
456 // runs, may cause memory allocations, which may trigger
457 // GC, which may run arbitrary Python code.
458 result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow()));
459 }
460 catch (...) {
461 // Unhandled C++ exception!
462
463 // If we declare ourselves as noexcept, if we don't catch
464 // this here, most platforms will just abort() the
465 // process. But on 64-bit Windows with older versions of
466 // the C runtime, this can actually corrupt memory and
467 // just return. We see this when compiling with the
468 // Windows 7.0 SDK targeting Windows Server 2008, but not
469 // when using the Appveyor Visual Studio 2019 image. So
470 // this currently only affects Python 2.7 on Windows 64.
471 // That is, the tests pass and the runtime aborts
472 // everywhere else.
473 //
474 // However, if we catch it and try to continue with a
475 // Python error, then all Windows 64 bit platforms corrupt
476 // memory. So all we can do is manually abort, hopefully
477 // with a good error message. (Note that the above was
478 // tested WITHOUT the `/EHr` switch being used at compile
479 // time, so MSVC may have "optimized" out important
480 // checking. Using that switch, we may be in a better
481 // place in terms of memory corruption.) But sometimes it
482 // can't be caught here at all, which is confusing but not
483 // terribly surprising; so again, the G_NOEXCEPT_WIN32
484 // plus "/EHr".
485 //
486 // Hopefully the basic C stdlib is still functional enough
487 // for us to at least print an error.
488 //
489 // It gets more complicated than that, though, on some
490 // platforms, specifically at least Linux/gcc/libstdc++. They use
491 // an exception to unwind the stack when a background
492 // thread exits. (See comments about noexcept.) So this
493 // may not actually represent anything untoward. On those
494 // platforms we allow throws of this to propagate, or
495 // attempt to anyway.
496# if defined(WIN32) || defined(_WIN32)
497 Py_FatalError(
498 "greenlet: Unhandled C++ exception from a greenlet run function. "
499 "Because memory is likely corrupted, terminating process.");
500 std::abort();
501#else
502 throw;
503#endif
504 }
505 }
506 // These lines may run arbitrary code
507 args.CLEAR();
508 Py_CLEAR(run);
509
510 if (!result
511 && mod_globs->PyExc_GreenletExit.PyExceptionMatches()
512 && (this->args())) {
513 // This can happen, for example, if our only reference
514 // goes away after we switch back to the parent.
515 // See test_dealloc_switch_args_not_lost
516 PyErrPieces clear_error;
517 result <<= this->args();
518 result = single_result(result);
519 }
520 this->release_args();
521 this->python_state.did_finish(PyThreadState_GET());
522
523 result = g_handle_exit(result);
524 assert(this->thread_state()->borrow_current() == this->_self);
525
526 /* jump back to parent */
527 this->stack_state.set_inactive(); /* dead */
528
529
530 // TODO: Can we decref some things here? Release our main greenlet
531 // and maybe parent?
532 for (Greenlet* parent = this->_parent;
533 parent;
534 parent = parent->parent()) {
535 // We need to somewhere consume a reference to
536 // the result; in most cases we'll never have control
537 // back in this stack frame again. Calling
538 // green_switch actually adds another reference!
539 // This would probably be clearer with a specific API
540 // to hand results to the parent.
541 parent->args() <<= result;
542 assert(!result);
543 // The parent greenlet now owns the result; in the
544 // typical case we'll never get back here to assign to
545 // result and thus release the reference.
546 try {
547 result = parent->g_switch();
548 }
549 catch (const PyErrOccurred&) {
550 // Ignore, keep passing the error on up.
551 }
552
553 /* Return here means switch to parent failed,
554 * in which case we throw *current* exception
555 * to the next parent in chain.
556 */
557 assert(!result);
558 }
559 /* We ran out of parents, cannot continue */
560 PyErr_WriteUnraisable(this->self().borrow_o());
561 Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; "
562 "cannot continue");
563 std::abort();
564}
565
566void
567UserGreenlet::run(const BorrowedObject nrun)
568{
569 if (this->started()) {
570 throw AttributeError(
571 "run cannot be set "
572 "after the start of the greenlet");
573 }
574 this->_run_callable = nrun;
575}
576
577const OwnedGreenlet
578UserGreenlet::parent() const
579{
580 return this->_parent;
581}
582
583void
584UserGreenlet::parent(const BorrowedObject raw_new_parent)
585{
586 if (!raw_new_parent) {
587 throw AttributeError("can't delete attribute");
588 }
589
590 BorrowedMainGreenlet main_greenlet_of_new_parent;
591 BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could
592 // throw
593 // TypeError!
594 for (BorrowedGreenlet p = new_parent; p; p = p->parent()) {
595 if (p == this->self()) {
596 throw ValueError("cyclic parent chain");
597 }
598 main_greenlet_of_new_parent = p->main_greenlet();
599 }
600
601 if (!main_greenlet_of_new_parent) {
602 throw ValueError("parent must not be garbage collected");
603 }
604
605 if (this->started()
606 && this->_main_greenlet != main_greenlet_of_new_parent) {
607 throw ValueError("parent cannot be on a different thread");
608 }
609
610 this->_parent = new_parent;
611}
612
613void
614UserGreenlet::murder_in_place()
615{
616 this->_main_greenlet.CLEAR();
617 Greenlet::murder_in_place();
618}
619
620bool
621UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const
622{
623 return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet();
624}
625
626
627int
628UserGreenlet::tp_traverse(visitproc visit, void* arg)
629{
630 Py_VISIT(this->_parent.borrow_o());
631 Py_VISIT(this->_main_greenlet.borrow_o());
632 Py_VISIT(this->_run_callable.borrow_o());
633
634 return Greenlet::tp_traverse(visit, arg);
635}
636
637int
638UserGreenlet::tp_clear()
639{
640 Greenlet::tp_clear();
641 this->_parent.CLEAR();
642 this->_main_greenlet.CLEAR();
643 this->_run_callable.CLEAR();
644 return 0;
645}
646
647UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p,
648 const ThreadState& thread_state)
649 : oldparent(p->_parent),
650 greenlet(p)
651{
652 p->_parent = thread_state.get_current();
653}
654
655UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard()
656{
657 this->greenlet->_parent = oldparent;
658 oldparent.CLEAR();
659}
660
661}; //namespace greenlet
662#endif
Definition TThreadState.hpp:87
Definition greenlet_refs.hpp:600
Definition greenlet_refs.hpp:995
Definition __init__.py:1
Definition greenlet.h:22
Definition greenlet_allocator.hpp:17