@@ -429,81 +429,14 @@ PyAPI_FUNC(void) _Py_NO_RETURN _PyObject_AssertFailed(
429429 const char * function );
430430
431431
432- /* Trashcan mechanism, thanks to Christian Tismer.
433-
434- When deallocating a container object, it's possible to trigger an unbounded
435- chain of deallocations, as each Py_DECREF in turn drops the refcount on "the
436- next" object in the chain to 0. This can easily lead to stack overflows,
437- especially in threads (which typically have less stack space to work with).
438-
439- A container object can avoid this by bracketing the body of its tp_dealloc
440- function with a pair of macros:
441-
442- static void
443- mytype_dealloc(mytype *p)
444- {
445- ... declarations go here ...
446-
447- PyObject_GC_UnTrack(p); // must untrack first
448- Py_TRASHCAN_BEGIN(p, mytype_dealloc)
449- ... The body of the deallocator goes here, including all calls ...
450- ... to Py_DECREF on contained objects. ...
451- Py_TRASHCAN_END // there should be no code after this
452- }
453-
454- CAUTION: Never return from the middle of the body! If the body needs to
455- "get out early", put a label immediately before the Py_TRASHCAN_END
456- call, and goto it. Else the call-depth counter (see below) will stay
457- above 0 forever, and the trashcan will never get emptied.
458-
459- How it works: The BEGIN macro increments a call-depth counter. So long
460- as this counter is small, the body of the deallocator is run directly without
461- further ado. But if the counter gets large, it instead adds p to a list of
462- objects to be deallocated later, skips the body of the deallocator, and
463- resumes execution after the END macro. The tp_dealloc routine then returns
464- without deallocating anything (and so unbounded call-stack depth is avoided).
465-
466- When the call stack finishes unwinding again, code generated by the END macro
467- notices this, and calls another routine to deallocate all the objects that
468- may have been added to the list of deferred deallocations. In effect, a
469- chain of N deallocations is broken into (N-1)/(Py_TRASHCAN_HEADROOM-1) pieces,
470- with the call stack never exceeding a depth of Py_TRASHCAN_HEADROOM.
471-
472- Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base
473- class, we need to ensure that the trashcan is only triggered on the tp_dealloc
474- of the actual class being deallocated. Otherwise we might end up with a
475- partially-deallocated object. To check this, the tp_dealloc function must be
476- passed as second argument to Py_TRASHCAN_BEGIN().
477- */
478-
479-
480432PyAPI_FUNC (void ) _PyTrash_thread_deposit_object (PyThreadState * tstate , PyObject * op );
481433PyAPI_FUNC (void ) _PyTrash_thread_destroy_chain (PyThreadState * tstate );
482434
483-
484- /* Python 3.10 private API, invoked by the Py_TRASHCAN_BEGIN(). */
485-
486- /* To avoid raising recursion errors during dealloc trigger trashcan before we reach
487- * recursion limit. To avoid trashing, we don't attempt to empty the trashcan until
488- * we have headroom above the trigger limit */
489- #define Py_TRASHCAN_HEADROOM 50
490-
491- /* Helper function for Py_TRASHCAN_BEGIN */
492435PyAPI_FUNC (int ) _Py_ReachedRecursionLimitWithMargin (PyThreadState * tstate , int margin_count );
493436
494- #define Py_TRASHCAN_BEGIN (op , dealloc ) \
495- do { \
496- PyThreadState *tstate = PyThreadState_Get(); \
497- if (_Py_ReachedRecursionLimitWithMargin(tstate, 2) && Py_TYPE(op)->tp_dealloc == (destructor)dealloc) { \
498- _PyTrash_thread_deposit_object(tstate, (PyObject *)op); \
499- break; \
500- }
501- /* The body of the deallocator is here. */
502- #define Py_TRASHCAN_END \
503- if (tstate->delete_later && !_Py_ReachedRecursionLimitWithMargin(tstate, 4)) { \
504- _PyTrash_thread_destroy_chain(tstate); \
505- } \
506- } while (0);
437+ /* For backwards compatibility with the old trashcan mechanism */
438+ #define Py_TRASHCAN_BEGIN (op , dealloc )
439+ #define Py_TRASHCAN_END
507440
508441
509442PyAPI_FUNC (void * ) PyObject_GetItemData (PyObject * obj );
0 commit comments