
    ij                     "   d Z ddlZddlZddlZddlZddlZ eej                  j                  dd            Z	 e
ej                  j                  dd            Zd Z G d d	      Zd
 Zd Zd Zedk(  r e         ej$                  d       yy)aT  Reproducer for the free-threaded GC crash in issue #515.

https://github.com/python-greenlet/greenlet/issues/515

Before the fix, ``set_initial_state`` copied the parent thread state's
``_PyCStackRef`` list head into each new greenlet. Those nodes sit on the
parent greenlet's C stack, so once the child starts running on its own stack
and overwrites that region their ``next`` pointers dangle. The free-threaded
collector walks ``c_stack_refs`` for every thread, so a GC on any thread ends
up chasing those dangling nodes (inside ``gc_collect_main`` ->
``gc_visit_thread_stacks``) while such a child is active, and segfaults.

The fiddly part is getting a *non-empty* list to inherit at all. The
interpreter only holds a ``_PyCStackRef`` transiently, while it is resolving an
attribute -- ``_Py_LoadAttr_StackRefSteal`` pins ``self`` across ``obj.attr()``
-- so the greenlet has to be primed from inside that window. Priming it from a
property getter does exactly that; it is also the same deep-attribute context
Playwright's sync bridge happens to start its fiber from. A churn thread then
keeps the collector busy while the dispatcher runs on its stale list.

A fixed build prints "ISSUE 515 OK"; a regressed one segfaults in about a
second. With-GIL builds are unaffected -- ordinary refcounting keeps the nodes
alive -- so there it simply prints the OK line.
    NREPRO_SECONDS4REPRO_THREADS6c                  v    dj                         j                         j                         j                         S )Nabc)upperlowerstriptitle     ^/root/.hermes/venv/lib/python3.12/site-packages/greenlet/tests/fail_issue_515_freethread_gc.py_busyr   &   s+     ;;= &&(..00r   c                   4    e Zd Zd Zd Zed        Zd Zd Zy)Bridgec                     || _         t        j                         | _        t        j                  | j                        | _        y N)stopgreenlet
getcurrentmain_loopdisp)selfr   s     r   __init__zBridge.__init__-   s/    	'')	%%djj1	r   c                     | j                   d   sEt        d      D ]  }t                 | j                  j	                          | j                   d   sDy y )Nr   2   )r   ranger   r   switch)r   _s     r   r   zBridge._loop2   sB    ))A,2Y II ))A,r   c                 8    | j                   j                          y r   r   r    r   s    r   _primezBridge._prime8   s    
 			r   c                     | j                   S r   )r%   r$   s    r   startzBridge.start@   s    
 {{r   c                 8    | j                   j                          y r   r#   r$   s    r   resumezBridge.resumeG   s    		r   N)	__name__
__module____qualname__r   r   propertyr%   r'   r)   r   r   r   r   r   ,   s*    2
  r   r   c                 r    t        |       }|j                          | d   s|j                          | d   sy y )Nr   )r   r'   r)   )r   bridges     r   workerr0   K   s/    D\F
LLN 1g 1gr   c                     | d   s^t        d      D cg c]  }|d d	 }}t        ||dd        D ]
  \  }}||d<    |d   |d   d<   ~t        j                          | d   s]y y c c}w )Nr   i  )inext   r3   )r   zipgccollect)r   r2   nodesabs        r   churnr<   T   s|    1g 27s<Aq$'<<uQRy) 	DAqAfI	!!Hb	&


 1g =s   A%c            	         dg} t        j                  t        | fd      g}|t        t              D cg c]  }t        j                  t
        | fd      ! c}z  }|D ]  }|j                           t        j                         j                  t               d| d<   |D ]  }|j                  d        t        d       y c c}w )NFT)targetargsdaemonr      )timeoutzISSUE 515 OK)	threadingThreadr<   r   NWORKERSr0   r'   EventwaitDURATIONjoinprint)r   threadsr!   ts       r   r   r   `   s    7DuD74HIGx*   dWTJ * *G 		OO8$DG 	q	.*s   $C__main__)__doc__r7   ossysrC   r   floatenvirongetrH   intrE   r   r   r0   r<   r   r*   exitr   r   r   <module>rV      s   0 
 	 
   56rzz~~os341 >	 zFCHHQK r   