o
    iP                     @  sv  U d dl mZ d dl mZ d dlZd dlZd dlZd dlZd dlm	Z	 d dlm
Z
 d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ erUd dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ eddgZde d< eg dZ!de d< dZ"de d< d/ddZ#d0d$d%Z$d1d'd(Z%G d)d* d*Z&G d+d, d,Z'G d-d. d.ej(Z)dS )2    )absolute_import)annotationsN)CodeType)	FrameType)
ModuleType)TracebackType)TYPE_CHECKING)Any)Callable)Optional)	UnionType)ddup)config)
_threading)	collector)_task)Tracer_acquire_releasezfrozenset[str]ACQUIRE_RELEASE_CO_NAMES)acquirerelease	__enter____exit__
__aenter__	__aexit__ENTER_EXIT_CO_NAMES   intCALLER_FRAME_INDEXreturntuple[int, str]c                  C  s   t  } | t| fS N)_thread	get_identr   get_thread_name)	thread_id r'   U/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/profiling/collector/_lock.py_current_thread%   s   r)   module_namestr
class_nameCallable[..., Any]c                 C  s6   ddl }|| }t||}t|tr|jr|jS |S )znReconstruct the original lock class when unpickling. Since this is a module-level function, it can be pickled.r   N)	importlibimport_modulegetattr
isinstance_LockAllocatorWrapper_original_class)r*   r,   r.   moduleobjr'   r'   r(   _get_original_lock_class*   s   

r6   r	   c                 C  s:   | dkr|dkrd\} }n|dkrd\} }t | |}| S )zNCreate an instance of the original lock class when unpickling a _ProfiledLock.r#   lock)	threadingLockRLock)r8   r:   )r6   )r*   r,   
lock_classr'   r'   r(   _create_original_lock_instance8   s   

r<   c                   @  s   e Zd ZdZdZ	dBdCddZdDddZdEddZdFddZdGddZ	dHddZ
dIdd ZdJd#d$ZdJd%d&ZdJd'd(ZdKd+d,ZdJd-d.ZdLd/d0ZdJd1d2ZdMd3d4ZdNd8d9ZdOd=d>ZdPd?d@ZdAS )Q_ProfiledLockz
    Lightweight lock wrapper that profiles lock acquire/release operations.
    It intercepts lock methods without the overhead of a full proxy object.
    )__wrapped__tracercapture_samplerinit_locationacquired_timenameis_internalFwrappedr	   r?   Optional[Tracer]r@   collector.CaptureSamplerrD   boolr    Nonec                 C  sz   || _ || _|| _ztt}W n ty    tjr d| _	Y nw |j
}tj|j d|j | _	d | _d | _|| _d S )Nz	unknown:0:)r>   r?   r@   sys	_getframer   
ValueErrorr   enable_assertsrA   f_codeospathbasenameco_filenamef_linenorB   rC   rD   )selfrE   r?   r@   rD   framecoder'   r'   r(   __init__U   s   

z_ProfiledLock.__init__otherc                 C  s    t |tr| j|jkS | j|kS r"   )r1   r=   r>   rU   rY   r'   r'   r(   __eq__r   s   

z_ProfiledLock.__eq__rC   r+   c                 C  s   t | j|S r"   )r0   r>   )rU   rC   r'   r'   r(   __getattr__w   s   z_ProfiledLock.__getattr__r   c                 C  s
   t | jS r"   )hashr>   rU   r'   r'   r(   __hash__{   s   
z_ProfiledLock.__hash__c                 C  s   d| j d| j dS )Nz<_ProfiledLock(z) at >)r>   rA   r^   r'   r'   r(   __repr__~   s   z_ProfiledLock.__repr__1tuple[Callable[[str, str], Any], tuple[str, str]]c                 C  s   t | j}t|j|jffS )zSupport pickling by returning the wrapped lock.

        In the context of multiprocessing, the child process will get the unwrapped lock class, which will be re-wrapped
        if profiling is enabled there.
        )typer>   r<   
__module____qualname__)rU   wrapped_typer'   r'   r(   
__reduce__   s   

z_ProfiledLock.__reduce__c                 C  s
   | j  S )z&Return True if lock is currently held.)r>   lockedr^   r'   r'   r(   rh      s   
z_ProfiledLock.lockedargskwargsc                 O     | j | jjg|R i |S r"   )r   r>   r   rU   ri   rj   r'   r'   r(   r         z_ProfiledLock.acquirec                 O  rk   r"   )r   r>   r   rl   r'   r'   r(   r      rm   z_ProfiledLock.__enter__c                 O  rk   r"   )r   r>   r   rl   r'   r'   r(   r      rm   z_ProfiledLock.__aenter__
inner_funcr-   c              
   O  s  | j  stjr| jd u sJ d| j||i |S t }d }d }z	||i |}W n tyD } z||jf}W Y d }~nd }~ww t }|| _| j	ssz| 
  | j||dd W n tyj   tjrh Y n	 tyr   Y nw |d ur|\}	}
|	|
|S )NzCExpected acquired_time to be None when acquire is not sampled, got T)
is_acquire)r@   capturer   rN   rB   timemonotonic_nsBaseException__traceback__rD   _update_name_flush_sampleAssertionError	Exceptionwith_traceback)rU   rn   ri   rj   startresult
error_infoexcenderrtbr'   r'   r(   r      s@   


z_ProfiledLock._acquirec                 O  rk   r"   )r   r>   r   rl   r'   r'   r(   r      rm   z_ProfiledLock.releasec                 O  s    | j | jjg|R i | d S r"   )r   r>   r   rl   r'   r'   r(   r      s    z_ProfiledLock.__exit__c                 O  rk   r"   )r   r>   r   rl   r'   r'   r(   r      rm   z_ProfiledLock.__aexit__c           
   
   O  s   t | dd }d | _d }d }z	||i |}W n ty- } z||jf}W Y d }~nd }~ww |rU| jsUz| j|t dd W n tyL   t	j
rJ Y n	 tyT   Y nw |d urb|\}}	||	|S )NrB   F)r~   ro   )r0   rB   rs   rt   rD   rv   rq   rr   rw   r   rN   rx   ry   )
rU   rn   ri   rj   rz   r{   r|   r}   r   r   r'   r'   r(   r      s0   

z_ProfiledLock._releaserz   r~   ro   c                 C  s  | j rdS zrt }|| | jr| j d| j n| j}|| || }|r0||d n||d t	 \}}t
 \}	}
}||	 ||
 t|}|||| | jdure|| j  |pktt}|| |  W dS  ty   tjr Y dS  ty   Y dS w )z!Push lock profiling data to ddup.NrJ      )rD   r   SampleHandlepush_monotonic_nsrC   rA   push_lock_namepush_acquirepush_releaser)   r   get_taskpush_task_idpush_task_namer   get_thread_native_idpush_threadinfor?   	push_spancurrent_spanrK   rL   r   push_pyframesflush_samplerw   r   rN   rx   )rU   rz   r~   ro   handle	lock_nameduration_nsr&   thread_nametask_id	task_name
task_framethread_native_idrV   r'   r'   r(   rv      s:   







z_ProfiledLock._flush_samplevar_dictdict[str, Any]Optional[str]c              
   C  s   |  D ]@\}}|dst|trq|| u r|  S tjjrDt|D ] }z|ds9t||| u r9|W     S W q# t	yC   Y q#w qd S )N__)
items
startswithr1   r   r   r7   name_inspect_dirdirr0   AttributeError)rU   r   rC   value	attributer'   r'   r(   
_find_name  s    z_ProfiledLock._find_namec                 C  s   | j durdS zDtjr5td}|jjtvr td|jj dtd}|jjt	vr5td|jj dtt
}| |jpG| |jpGd| _ W dS  tyY   tjrV Y dS  tyb   Y dS w )z/Get lock variable name from the caller's frame.Nr   zUnexpected frame in stack: ''    )rC   r   rN   rK   rL   rO   co_namer   rw   r   r   r   f_locals	f_globalsrx   )rU   rV   r'   r'   r(   ru   ,  s&   



$z_ProfiledLock._update_nameN)F)
rE   r	   r?   rF   r@   rG   rD   rH   r    rI   )rY   r	   r    rH   rC   r+   r    r	   )r    r   )r    r+   )r    rb   )r    rH   )ri   r	   rj   r	   r    r	   )rn   r-   ri   r	   rj   r	   r    r	   ri   r	   rj   r	   r    rI   )rn   r-   ri   r	   rj   r	   r    rI   )rz   r   r~   r   ro   rH   r    rI   )r   r   r    r   r    rI   )__name__rd   re   __doc__	__slots__rX   r[   r\   r_   ra   rg   rh   r   r   r   r   r   r   r   r   rv   r   ru   r'   r'   r'   r(   r=   E   s,    










'




4r=   c                   @  sf   e Zd ZdZdZd&dd	Zd'ddZd(d)ddZd*ddZd+ddZ	d+ddZ
d,d!d"Zd-d$d%ZdS ).r2   a  Wrapper for lock allocator functions that prevents method binding.

    For simple locks (Lock, RLock), this wrapper just intercepts instantiation.

    For class-based locks with inheritance (Semaphore, BoundedSemaphore), this wrapper
    also handles the case where a subclass calls Parent.__init__(self, value). Example:

        # In Python's threading.py:
        class BoundedSemaphore(Semaphore):
            def __init__(self, value=1):
                Semaphore.__init__(self, value)  # <-- We intercept this!
                self._initial_value = value

    When we patch threading.Semaphore with this wrapper, the call to Semaphore.__init__
    goes to our __init__, which detects the inheritance case and delegates to the
    original Semaphore.__init__.
    )_funcr3   ri   r	   rj   r    rI   c                 O  s   |r!t | dr!| jd ur!|d }t|| jr!| jj|i | d S |  |  |rC|d | _|dp?t|dkr>|d | _d S d | _d S |d| _|d| _d S )Nr3   r   original_classr   func)hasattrr3   r1   rX   r   getlen)rU   ri   rj   	first_argr'   r'   r(   rX   `  s   
.z_LockAllocatorWrapper.__init__r=   c                 O  s   | j |i |S r"   )r   rl   r'   r'   r(   __call__|  s   z_LockAllocatorWrapper.__call__NinstanceownerOptional[type[Any]]c                 C  s   | S r"   r'   )rU   r   r   r'   r'   r(   __get__  s   z_LockAllocatorWrapper.__get__rC   r+   c                 C  s:   t | d}|d urt||S tdt| j d| d)Nr3   r   z' object has no attribute ')object__getattribute__r0   r   rc   r   )rU   rC   r   r'   r'   r(   r\     s   
z!_LockAllocatorWrapper.__getattr__rY   type[Any] | Noner   c                 C  s   t | jtr| j|B S tS )zCSupport PEP 604 type union syntax (e.g., asyncio.Condition | None).r1   r3   rc   NotImplementedrZ   r'   r'   r(   __or__     z_LockAllocatorWrapper.__or__c                 C  s   t | jtr|| jB S tS )zCSupport PEP 604 type union syntax (e.g., None | asyncio.Condition).r   rZ   r'   r'   r(   __ror__  r   z_LockAllocatorWrapper.__ror__basestuple[Any, ...]tuple[type[Any], ...]c                 C  s   | j fS )a  Support subclassing the wrapped lock type (PEP 560).

        When custom lock types inherit from a wrapped lock
        (e.g. neo4j's AsyncRLock that inherits from asyncio.Lock), program error with:
        > TypeError: _LockAllocatorWrapper.__init__() takes 2 positional arguments but 4 were given

        This method returns the actual object type to be used as the base class.
        )r3   )rU   r   r'   r'   r(   __mro_entries__  s   	z%_LockAllocatorWrapper.__mro_entries__@tuple[Callable[[str, str], Callable[..., Any]], tuple[str, str]]c                 C  s&   | j du r	tdt| j j| j jffS )zSupport pickling by returning the original class.

        In the context of multiprocessing, the child process will get the unwrapped lock class, which will be re-wrapped
        if profiling is enabled there.
        Nz1Cannot pickle uninitialized _LockAllocatorWrapper)r3   	TypeErrorr6   rd   re   r^   r'   r'   r(   rg     s
   
z _LockAllocatorWrapper.__reduce__r   ri   r	   rj   r	   r    r=   r"   )r   r	   r   r   r    r2   r   )rY   r   r    r   )r   r   r    r   )r    r   )r   rd   re   r   r   rX   r   r   r\   r   r   r   rg   r'   r'   r'   r(   r2   K  s    



	

r2   c                      s   e Zd ZU dZded< ded< ded< dZd	ed
< 	d"d# fddZd$ddZd%ddZd& fddZ	d& fddZ
d&ddZd&d d!Z  ZS )'LockCollectorzRecord lock usage.z	type[Any]PROFILED_LOCK_CLASSr   MODULEr+   PATCHED_LOCK_NAMENr   INTERNAL_MODULE_FILEr?   rF   ri   r	   rj   r    rI   c                   s"   t  j|i | || _d | _d S r"   )superrX   r?   _original_lock)rU   r?   ri   rj   	__class__r'   r(   rX     s   
zLockCollector.__init__r-   c                 C  s   t | j| jS r"   )r0   r   r   r^   r'   r'   r(   _get_patch_target  s   zLockCollector._get_patch_targetr   c                 C  s   t | j| j| d S r"   )setattrr   r   )rU   r   r'   r'   r(   _set_patch_target  s   zLockCollector._set_patch_targetc                   s"   t   |   tt|   dS )zStart collecting lock usage.N)r   initialize_gevent_supportpatchr   r   _start_servicer^   r   r'   r(   r     s   zLockCollector._start_servicec                   s   t t|   |   dS )zStop collecting lock usage.N)r   r   _stop_serviceunpatchr^   r   r'   r(   r     s   zLockCollector._stop_servicec                   sT     _jj  du rddl}|j d fdd	}t|d
 dS )z.Patch the module for tracking lock allocation.Nr   ri   r	   rj   r    r=   c               
     s   d}z%t djj} r&|r&tjtj|}tjtj }||k}W n tt	t
fy3   Y nw j| i |jj|dS )zSimple wrapper that returns profiled locks.

            Detects if the lock is being created from within the stdlib module
            (i.e., internal to Semaphore/Condition) to avoid double-counting.
            Fr   )rE   r?   r@   rD   )rK   rL   rO   rS   rP   rQ   normpathrealpathrM   r   OSErrorr   r?   _capture_sampler)ri   rj   rD   caller_filenameinternal_fileinternal_module_fileoriginal_lockrU   r'   r(   _profiled_allocate_lock  s"   z4LockCollector.patch.<locals>._profiled_allocate_lock)r   r   )r   r   r   r8   __file__r   r2   )rU   threading_moduler   r'   r   r(   r     s   
zLockCollector.patchc                 C  s   |  | j dS )z:Unpatch the threading module for tracking lock allocation.N)r   r   r^   r'   r'   r(   r     s   zLockCollector.unpatchr"   )r?   rF   ri   r	   rj   r	   r    rI   )r    r-   )r   r	   r    rI   r   )r   rd   re   r   __annotations__r   rX   r   r   r   r   r   r   __classcell__r'   r'   r   r(   r     s   
 



+r   )r    r!   )r*   r+   r,   r+   r    r-   )r*   r+   r,   r+   r    r	   )*
__future__r   r   r#   os.pathrP   rK   rq   typesr   r   r   r   typingr   r	   r
   r   r   "ddtrace.internal.datadog.profilingr   #ddtrace.internal.settings.profilingr   ddtrace.profilingr   r   ddtrace.profiling.collectorr   ddtrace.tracer   	frozensetr   r   r   r   r)   r6   r<   r=   r2   CaptureSamplerCollectorr   r'   r'   r'   r(   <module>   sF    


  c