@@ -607,93 +607,6 @@ it carefully, it may save lots of calls to Py_INCREF() and Py_DECREF() at
607607times.
608608*/
609609
610-
611- /* Trashcan mechanism, thanks to Christian Tismer.
612-
613- When deallocating a container object, it's possible to trigger an unbounded
614- chain of deallocations, as each Py_DECREF in turn drops the refcount on "the
615- next" object in the chain to 0. This can easily lead to stack overflows,
616- especially in threads (which typically have less stack space to work with).
617-
618- A container object can avoid this by bracketing the body of its tp_dealloc
619- function with a pair of macros:
620-
621- static void
622- mytype_dealloc(mytype *p)
623- {
624- ... declarations go here ...
625-
626- PyObject_GC_UnTrack(p); // must untrack first
627- Py_TRASHCAN_BEGIN(p, mytype_dealloc)
628- ... The body of the deallocator goes here, including all calls ...
629- ... to Py_DECREF on contained objects. ...
630- Py_TRASHCAN_END // there should be no code after this
631- }
632-
633- CAUTION: Never return from the middle of the body! If the body needs to
634- "get out early", put a label immediately before the Py_TRASHCAN_END
635- call, and goto it. Else the call-depth counter (see below) will stay
636- above 0 forever, and the trashcan will never get emptied.
637-
638- How it works: The BEGIN macro increments a call-depth counter. So long
639- as this counter is small, the body of the deallocator is run directly without
640- further ado. But if the counter gets large, it instead adds p to a list of
641- objects to be deallocated later, skips the body of the deallocator, and
642- resumes execution after the END macro. The tp_dealloc routine then returns
643- without deallocating anything (and so unbounded call-stack depth is avoided).
644-
645- When the call stack finishes unwinding again, code generated by the END macro
646- notices this, and calls another routine to deallocate all the objects that
647- may have been added to the list of deferred deallocations. In effect, a
648- chain of N deallocations is broken into (N-1)/(PyTrash_UNWIND_LEVEL-1) pieces,
649- with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL.
650-
651- Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base
652- class, we need to ensure that the trashcan is only triggered on the tp_dealloc
653- of the actual class being deallocated. Otherwise we might end up with a
654- partially-deallocated object. To check this, the tp_dealloc function must be
655- passed as second argument to Py_TRASHCAN_BEGIN().
656- */
657-
658- /* The new thread-safe private API, invoked by the macros below. */
659- PyAPI_FUNC (void ) _PyTrash_thread_deposit_object (PyObject * );
660- PyAPI_FUNC (void ) _PyTrash_thread_destroy_chain (void );
661-
662- #define PyTrash_UNWIND_LEVEL 50
663-
664- #define Py_TRASHCAN_BEGIN_CONDITION (op , cond ) \
665- do { \
666- PyThreadState *_tstate = NULL; \
667- /* If "cond" is false, then _tstate remains NULL and the deallocator \
668- * is run normally without involving the trashcan */ \
669- if (cond ) { \
670- _tstate = PyThreadState_GET (); \
671- if (_tstate -> trash_delete_nesting >= PyTrash_UNWIND_LEVEL ) { \
672- /* Store the object (to be deallocated later) and jump past \
673- * Py_TRASHCAN_END, skipping the body of the deallocator */ \
674- _PyTrash_thread_deposit_object (_PyObject_CAST (op )); \
675- break ; \
676- } \
677- ++ _tstate -> trash_delete_nesting ; \
678- }
679- /* The body of the deallocator is here. */
680- #define Py_TRASHCAN_END \
681- if (_tstate) { \
682- --_tstate->trash_delete_nesting; \
683- if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \
684- _PyTrash_thread_destroy_chain(); \
685- } \
686- } while (0);
687-
688- #define Py_TRASHCAN_BEGIN (op , dealloc ) Py_TRASHCAN_BEGIN_CONDITION(op, \
689- Py_TYPE(op)->tp_dealloc == (destructor)(dealloc))
690-
691- /* For backwards compatibility, these macros enable the trashcan
692- * unconditionally */
693- #define Py_TRASHCAN_SAFE_BEGIN (op ) Py_TRASHCAN_BEGIN_CONDITION(op, 1)
694- #define Py_TRASHCAN_SAFE_END (op ) Py_TRASHCAN_END
695-
696-
697610#ifndef Py_LIMITED_API
698611# define Py_CPYTHON_OBJECT_H
699612# include "cpython/object.h"
0 commit comments