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