@@ -2692,27 +2692,27 @@ Py_ReprLeave(PyObject *obj)
2692
2692
* call-stack depth gets large. op must be a currently untracked gc'ed
2693
2693
* object, with refcount 0. Py_DECREF must already have been called on it.
2694
2694
*/
2695
- static void
2696
- _PyTrash_thread_deposit_object ( struct _py_trashcan * trash , PyObject * op )
2695
+ void
2696
+ PyTrash_thread_deposit_object ( PyThreadState * tstate , PyObject * op )
2697
2697
{
2698
2698
_PyObject_ASSERT (op , _PyObject_IS_GC (op ));
2699
2699
_PyObject_ASSERT (op , !_PyObject_GC_IS_TRACKED (op ));
2700
2700
_PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
2701
2701
#ifdef Py_GIL_DISABLED
2702
2702
_PyObject_ASSERT (op , op -> ob_tid == 0 );
2703
- op -> ob_tid = (uintptr_t )trash -> delete_later ;
2703
+ op -> ob_tid = (uintptr_t )tstate -> delete_later ;
2704
2704
#else
2705
- _PyGCHead_SET_PREV (_Py_AS_GC (op ), (PyGC_Head * )trash -> delete_later );
2705
+ _PyGCHead_SET_PREV (_Py_AS_GC (op ), (PyGC_Head * )tstate -> delete_later );
2706
2706
#endif
2707
- trash -> delete_later = op ;
2707
+ tstate -> delete_later = op ;
2708
2708
}
2709
2709
2710
2710
/* Deallocate all the objects in the gcstate->trash_delete_later list.
2711
2711
* Called when the call-stack unwinds again. */
2712
- static void
2713
- _PyTrash_thread_destroy_chain ( struct _py_trashcan * trash )
2712
+ void
2713
+ PyTrash_thread_destroy_chain ( PyThreadState * tstate )
2714
2714
{
2715
- /* We need to increase trash_delete_nesting here, otherwise,
2715
+ /* We need to increase c_recursion_remaining here, otherwise,
2716
2716
_PyTrash_thread_destroy_chain will be called recursively
2717
2717
and then possibly crash. An example that may crash without
2718
2718
increase:
@@ -2723,17 +2723,17 @@ _PyTrash_thread_destroy_chain(struct _py_trashcan *trash)
2723
2723
tups = [(tup,) for tup in tups]
2724
2724
del tups
2725
2725
*/
2726
- assert (trash -> delete_nesting == 0 );
2727
- ++ trash -> delete_nesting ;
2728
- while (trash -> delete_later ) {
2729
- PyObject * op = trash -> delete_later ;
2726
+ assert (tstate -> c_recursion_remaining > 50 );
2727
+ tstate -> c_recursion_remaining -- ;
2728
+ while (tstate -> delete_later ) {
2729
+ PyObject * op = tstate -> delete_later ;
2730
2730
destructor dealloc = Py_TYPE (op )-> tp_dealloc ;
2731
2731
2732
2732
#ifdef Py_GIL_DISABLED
2733
- trash -> delete_later = (PyObject * ) op -> ob_tid ;
2733
+ tstate -> delete_later = (PyObject * ) op -> ob_tid ;
2734
2734
op -> ob_tid = 0 ;
2735
2735
#else
2736
- trash -> delete_later = (PyObject * ) _PyGCHead_PREV (_Py_AS_GC (op ));
2736
+ tstate -> delete_later = (PyObject * ) _PyGCHead_PREV (_Py_AS_GC (op ));
2737
2737
#endif
2738
2738
2739
2739
/* Call the deallocator directly. This used to try to
@@ -2744,92 +2744,10 @@ _PyTrash_thread_destroy_chain(struct _py_trashcan *trash)
2744
2744
*/
2745
2745
_PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
2746
2746
(* dealloc )(op );
2747
- assert (trash -> delete_nesting == 1 );
2748
- }
2749
- -- trash -> delete_nesting ;
2750
- }
2751
-
2752
-
2753
- static struct _py_trashcan *
2754
- _PyTrash_get_state (PyThreadState * tstate )
2755
- {
2756
- if (tstate != NULL ) {
2757
- return & tstate -> trash ;
2758
- }
2759
- // The current thread must be finalizing.
2760
- // Fall back to using thread-local state.
2761
- // XXX Use thread-local variable syntax?
2762
- assert (PyThread_tss_is_created (& _PyRuntime .trashTSSkey ));
2763
- struct _py_trashcan * trash =
2764
- (struct _py_trashcan * )PyThread_tss_get (& _PyRuntime .trashTSSkey );
2765
- if (trash == NULL ) {
2766
- trash = PyMem_RawMalloc (sizeof (struct _py_trashcan ));
2767
- if (trash == NULL ) {
2768
- Py_FatalError ("Out of memory" );
2769
- }
2770
- PyThread_tss_set (& _PyRuntime .trashTSSkey , (void * )trash );
2771
- }
2772
- return trash ;
2773
- }
2774
-
2775
- static void
2776
- _PyTrash_clear_state (PyThreadState * tstate )
2777
- {
2778
- if (tstate != NULL ) {
2779
- assert (tstate -> trash .delete_later == NULL );
2780
- return ;
2781
- }
2782
- if (PyThread_tss_is_created (& _PyRuntime .trashTSSkey )) {
2783
- struct _py_trashcan * trash =
2784
- (struct _py_trashcan * )PyThread_tss_get (& _PyRuntime .trashTSSkey );
2785
- if (trash != NULL ) {
2786
- PyThread_tss_set (& _PyRuntime .trashTSSkey , (void * )NULL );
2787
- PyMem_RawFree (trash );
2788
- }
2789
2747
}
2748
+ tstate -> c_recursion_remaining ++ ;
2790
2749
}
2791
2750
2792
-
2793
- int
2794
- _PyTrash_begin (PyThreadState * tstate , PyObject * op )
2795
- {
2796
- // XXX Make sure the GIL is held.
2797
- struct _py_trashcan * trash = _PyTrash_get_state (tstate );
2798
- if (trash -> delete_nesting >= _PyTrash_UNWIND_LEVEL ) {
2799
- /* Store the object (to be deallocated later) and jump past
2800
- * Py_TRASHCAN_END, skipping the body of the deallocator */
2801
- _PyTrash_thread_deposit_object (trash , op );
2802
- return 1 ;
2803
- }
2804
- ++ trash -> delete_nesting ;
2805
- return 0 ;
2806
- }
2807
-
2808
-
2809
- void
2810
- _PyTrash_end (PyThreadState * tstate )
2811
- {
2812
- // XXX Make sure the GIL is held.
2813
- struct _py_trashcan * trash = _PyTrash_get_state (tstate );
2814
- -- trash -> delete_nesting ;
2815
- if (trash -> delete_nesting <= 0 ) {
2816
- if (trash -> delete_later != NULL ) {
2817
- _PyTrash_thread_destroy_chain (trash );
2818
- }
2819
- _PyTrash_clear_state (tstate );
2820
- }
2821
- }
2822
-
2823
-
2824
- /* bpo-40170: It's only be used in Py_TRASHCAN_BEGIN macro to hide
2825
- implementation details. */
2826
- int
2827
- _PyTrash_cond (PyObject * op , destructor dealloc )
2828
- {
2829
- return Py_TYPE (op )-> tp_dealloc == dealloc ;
2830
- }
2831
-
2832
-
2833
2751
void _Py_NO_RETURN
2834
2752
_PyObject_AssertFailed (PyObject * obj , const char * expr , const char * msg ,
2835
2753
const char * file , int line , const char * function )
0 commit comments