
    "e                          d dl mZ d dlmZ d dlmZmZmZ d dlZd dl	Z	d dl
mZ d dlZd dlmZ d dlmZ dZ G d	 d
e      Z G d de      Z G d de      Zd Zy)    )	threading)PyDBDaemonThread)thread_get_ident
IS_CPYTHONNULLN)	pydev_log)is_current_thread_main_thread)pydevd_utilsFc                   .    e Zd ZdZd Zd Zd Zd Zd Zy)_TimeoutThreadam  
    The idea in this class is that it should be usually stopped waiting
    for the next event to be called (paused in a threading.Event.wait).

    When a new handle is added it sets the event so that it processes the handles and
    then keeps on waiting as needed again.

    This is done so that it's a bit more optimized than creating many Timer threads.
    c                     t        j                  | |       t        j                         | _        g | _        t        j                         | _        y N)r   __init__r   Event_event_handlesLock_lockselfpy_dbs     ?/usr/lib/python3/dist-packages/_pydevd_bundle/pydevd_timeout.pyr   z_TimeoutThread.__init__   s7    !!$.oo'
 ^^%
    c                 "   d }| j                   st        r.|t        j                  d       nt        j                  d|       | j                  j                  |       | j                   rg | _        y | j                         }| j                   sy y )Nz1pydevd_timeout: Wait until a new handle is added.z#pydevd_timeout: Next wait time: %s.)_kill_received_DEBUGr   criticalr   waitr   process_handles)r   	wait_times     r   _on_runz_TimeoutThread._on_run#   sw    	%%$&&'Z[&&'LiXKKY'"" ",,.I %%r   c                    | j                   5  t        rt        j                  d       | j                  j                          | j                  }g x}| _        t        j                         }d}|D ]  }||j                  k  re|j                  sYt        rt        j                  d|       |j                  |       ||j                  }Z|j                  |k  sj|j                  }wt        rt        j                  d|       |j                           |
	 ddd       y||z
  }|dk  rt        j                  d|       |cddd       S # 1 sw Y   yxY w)zx
        :return int:
            Returns the time we should be waiting for to process the next event properly.
        z"pydevd_timeout: Processing handlesNz(pydevd_timeout: Handle NOT processed: %sz$pydevd_timeout: Handle processed: %sr   z5pydevd_timeout: Expected timeout to be > 0. Found: %s)r   r   r   r   r   clearr   timeabs_timeoutdisposedappendexec_on_timeout)r   handlesnew_handlescurtimemin_handle_timeouthandletimeouts          r   r   z_TimeoutThread.process_handles3   s@   
 ZZ '	""#GHKKmmG*,,K$-
 iikG!%! -V///!**+UW]^&&v.)1-3-?-?*++.@@-3-?-?* !**+QSYZ**,!-$ ")C'	 '	F -w6a<&&'^`ghO'	 '	 '	s   CE>E!!EEc                     t        j                  |        | j                  5  | j                  j	                          d d d        y # 1 sw Y   y xY wr   )r   do_kill_pydev_threadr   r   setr   s    r   r0   z#_TimeoutThread.do_kill_pydev_threada   s:    --d3ZZ 	KKOO	 	 	s   AAc                     | j                   5  | j                  j                  |       | j                  j	                          d d d        y # 1 sw Y   y xY wr   )r   r   r'   r   r1   )r   r-   s     r   add_on_timeout_handlez$_TimeoutThread.add_on_timeout_handlef   s>    ZZ 	MM  (KKOO	 	 	s   6AAN)	__name__
__module____qualname____doc__r   r!   r   r0   r4    r   r   r   r      s!    &/ ,\
r   r   c                   .    e Zd Zd Zd Zd Zd Zd ZeZy)_OnTimeoutHandlec                     d|d| _         t        j                  |      | _        || _        || _        |i }|| _        d| _        y )Nz_OnTimeoutHandle()F)_strweakrefref_trackerr%   
on_timeoutkwargsr&   )r   trackerr%   rB   rC   s        r   r   z_OnTimeoutHandle.__init__n   sC    .8:	G,&$>Fr   c                    | j                   }| j                  }| j                  s<d| _        d | _         d | _        	 t        rt	        j
                  d||        |di | y y # t        $ r t	        j                  d       Y y w xY w)NTz6pydevd_timeout: Calling on timeout: %s with kwargs: %sz.pydevd_timeout: Exception on callback timeout.r9   )rC   rB   r&   r   r   r   	Exception	exception)r   rC   rB   s      r   r(   z _OnTimeoutHandle.exec_on_timeouty   s    __
}} DMDK"DOV&&'_akmst$V$   V##$TUVs   %A" "BBc                      y r   r9   r2   s    r   	__enter__z_OnTimeoutHandle.__enter__   s    r   c                     | j                         }|t        }n|j                  }|5  d| _        d | _        d | _        d d d        y # 1 sw Y   y xY w)NT)rA   r   r   r&   rC   rB   )r   exc_typeexc_valexc_tbrD   locks         r   __exit__z_OnTimeoutHandle.__exit__   sM    --/?D==D 	# DMDK"DO	# 	# 	#s   AAc                     | j                   S r   )r>   r2   s    r   __str__z_OnTimeoutHandle.__str__   s    yyr   N)	r5   r6   r7   r   r(   rI   rO   rQ   __repr__r9   r   r   r;   r;   l   s#    	V$# Hr   r;   c                       e Zd ZdZd ZddZy)TimeoutTrackerzC
    This is a helper class to track the timeout of something.
    c                 x    d | _         t        j                         | _        t	        j
                  |      | _        y r   )_threadr   r   r   r?   r@   _py_dbr   s     r   r   zTimeoutTracker.__init__   s'    ^^%
kk%(r   Nc                    | j                   5  | j                  St        rt        j                  d       t        | j                               | _        | j                  j                          t        j                         }t        | ||z   ||      }t        rt        j                  d|       | j                  j                  |       |cddd       S # 1 sw Y   yxY w)a  
        This can be called regularly to always execute the given function after a given timeout:

        call_on_timeout(py_db, 10, on_timeout)


        Or as a context manager to stop the method from being called if it finishes before the timeout
        elapses:

        with call_on_timeout(py_db, 10, on_timeout):
            ...

        Note: the callback will be called from a PyDBDaemonThread.
        Nz'pydevd_timeout: Created _TimeoutThread.z!pydevd_timeout: Added handle: %s.)r   rV   r   r   r   r   rW   startr$   r;   r4   )r   r.   rB   rC   r+   r-   s         r   call_on_timeoutzTimeoutTracker.call_on_timeout   s     ZZ 	||#&&'PQ-dkkm<""$iikG%dGg,=z6RF""#FOLL..v6	 	 	s   B=CCr   )r5   r6   r7   r8   r   rZ   r9   r   r   rT   rT      s    )
r   rT   c                  r    t               t               rt        j                         fd} | S fd} | S )aQ  
    The idea here is returning a callback that when called will generate a KeyboardInterrupt
    in the thread that called this function.

    If this is the main thread, this means that it'll emulate a Ctrl+C (which may stop I/O
    and sleep operations).

    For other threads, this will call PyThreadState_SetAsyncExc to raise
    a KeyboardInterrupt before the next instruction (so, it won't really interrupt I/O or
    sleep operations).

    :return callable:
        Returns a callback that will interrupt the current thread (this may be called
        from an auxiliary thread).
    c                  Z    t        j                  d       t        j                          y )Nz"Callback to interrupt main thread.)r   debugr
   interrupt_main_thread)main_threads   r   raise_on_this_threadzCcreate_interrupt_this_thread_callback.<locals>.raise_on_this_thread   s    OO@A..{;r   c                      t         rat        j                  d        t        j                  j                  t        j                         t        j                  t                     y t        j                  d       y )NzInterrupt thread: %sz=It is only possible to interrupt non-main threads in CPython.)	r   r   r]   ctypes	pythonapiPyThreadState_SetAsyncExcc_long	py_objectKeyboardInterrupt)tids   r   r`   zCcreate_interrupt_this_thread_callback.<locals>.raise_on_this_thread   sM     6<  ::6==;MvO_O_`qOrs _`r   )r   r	   r   current_thread)r`   r_   rh   s    @@r   %create_interrupt_this_thread_callbackrj      s<      
C$&..0	<   	a  r   )"_pydev_bundle._pydev_saved_modulesr   #_pydevd_bundle.pydevd_daemon_threadr   _pydevd_bundle.pydevd_constantsr   r   r   rb   r$   _pydev_bundler   r?   _pydevd_bundle.pydevd_utilsr	   _pydevd_bundler
   r   r   objectr;   rT   rj   r9   r   r   <module>rr      sW    8 @ N N   #  E '	[% [|2v 2j&V &R% r   