o
    b'                     @   sx   d Z ddlmZmZ ddlmZ ddlmZ ddl	m
Z
mZ ddlmZ ddlmZ ddlmZ e ZG d	d
 d
ZdS )z
twisted.python.threadpool: a pool of threads to which we dispatch tasks.

In most cases you can just use C{reactor.callInThread} and friends
instead of creating a thread pool directly.
    )Threadcurrent_thread)List)pool)contextlog)
deprecated)Failure)Versionc                   @   s   e Zd ZdZdZdZdZdZdZe	Z
eeedddd	d
deZeeZd,ddZedd Zedd Zedd Zedd ZeZdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Z d-d(d)Z!d*d+ Z"dS ).
ThreadPoola  
    This class (hopefully) generalizes the functionality of a pool of threads
    to which work can be dispatched.

    L{callInThread} and L{stop} should only be called from a single thread.

    @ivar started: Whether or not the thread pool is currently running.
    @type started: L{bool}

    @ivar threads: List of workers currently running in this thread pool.
    @type threads: L{list}

    @ivar _pool: A hook for testing.
    @type _pool: callable compatible with L{_pool}
          FNTwisted      r   zthreading.current_thread)versionreplacementc                    sb   |dksJ d||ksJ d| _ | _| _g  _ fdd} fdd} || _dS )	ac  
        Create a new threadpool.

        @param minthreads: minimum number of threads in the pool
        @type minthreads: L{int}

        @param maxthreads: maximum number of threads in the pool
        @type maxthreads: L{int}

        @param name: The name to give this threadpool; visible in log messages.
        @type name: native L{str}
        r   minimum is negativeminimum is greater than maximumc                     s(    j | d  i|} j| |S )Nname)threadFactory_generateNamethreadsappend)akwthreadself ;/usr/lib/python3/dist-packages/twisted/python/threadpool.pytrackingThreadFactoryL   s   z2ThreadPool.__init__.<locals>.trackingThreadFactoryc                      s    j sdS  jS )Nr   )startedmaxr   r   r   r    currentLimitS   s   z)ThreadPool.__init__.<locals>.currentLimitN)minr#   r   r   _pool_team)r   
minthreads
maxthreadsr   r!   r$   r   r   r    __init__8   s   zThreadPool.__init__c                 C   s   | j  }|j|j S )a  
        For legacy compatibility purposes, return a total number of workers.

        @return: the current number of workers, both idle and busy (but not
            those that have been quit by L{ThreadPool.adjustPoolsize})
        @rtype: L{int}
        )r'   
statisticsidleWorkerCountbusyWorkerCount)r   statsr   r   r    workersZ   s   
	zThreadPool.workersc                 C      dg| j  j S )z
        For legacy compatibility purposes, return the number of busy workers as
        expressed by a list the length of that number.

        @return: the number of workers currently processing a work item.
        @rtype: L{list} of L{None}
        N)r'   r+   r-   r   r   r   r    workingf   s   	zThreadPool.workingc                 C   r0   )a,  
        For legacy compatibility purposes, return the number of idle workers as
        expressed by a list the length of that number.

        @return: the number of workers currently alive (with an allocated
            thread) but waiting for new work.
        @rtype: L{list} of L{None}
        N)r'   r+   r,   r   r   r   r    waitersq   s   
zThreadPool.waitersc                    s   G  fddd}| S )z
        For legacy compatibility purposes, return an object with a C{qsize}
        method that indicates the amount of work not yet allocated to a worker.

        @return: an object with a C{qsize} method.
        c                       s   e Zd Z fddZdS )z$ThreadPool._queue.<locals>.NotAQueuec                    s    j  jS )a  
                Pretend to be a Python threading Queue and return the
                number of as-yet-unconsumed tasks.

                @return: the amount of backlogged work not yet dispatched to a
                    worker.
                @rtype: L{int}
                )r'   r+   backloggedWorkCount)qr   r   r    qsize   s   	z*ThreadPool._queue.<locals>.NotAQueue.qsizeN)__name__
__module____qualname__r5   r   r   r   r    	NotAQueue   s    r9   r   )r   r9   r   r   r    _queue}   s   	zThreadPool._queuec                 C   s8   d| _ d| _|   | j j}|r| j| dS dS )z'
        Start the threadpool.
        FTN)joinedr"   adjustPoolsizer'   r+   r3   grow)r   backlogr   r   r    start   s   zThreadPool.startc                 C      | j d dS )z
        Increase the number of available workers for the thread pool by 1, up
        to the maximum allowed by L{ThreadPool.max}.
        r   N)r'   r=   r   r   r   r    startAWorker      zThreadPool.startAWorkerc                 C   s   d| j pt|  d| j S )z
        Generate a name for a new pool thread.

        @return: A distinctive name for the thread.
        @rtype: native L{str}
        zPoolThread--)r   idr/   r   r   r   r    r      s   zThreadPool._generateNamec                 C   r@   )zn
        Decrease the number of available workers by 1, by quitting one as soon
        as it's idle.
        r   N)r'   shrinkr   r   r   r    stopAWorker   rB   zThreadPool.stopAWorkerc                 C   s"   t | d| t| | j| j d S )N__dict__)setattrr   r*   r%   r#   r   stater   r   r    __setstate__   s   zThreadPool.__setstate__c                 C   s   i }| j |d< | j|d< |S )Nr%   r#   )r%   r#   rI   r   r   r    __getstate__   s   

zThreadPool.__getstate__c                 O   s   | j d|g|R i | dS )a   
        Call a callable object in a separate thread.

        @param func: callable object to be called in separate thread

        @param args: positional arguments to be passed to C{func}

        @param kw: keyword args to be passed to C{func}
        N)callInThreadWithCallback)r   funcargsr   r   r   r    callInThread   s   
zThreadPool.callInThreadc                    sP   | j rdS tj jd fdd fdd_|_| j dS )a$  
        Call a callable object in a separate thread and call C{onResult} with
        the return value, or a L{twisted.python.failure.Failure} if the
        callable raises an exception.

        The callable is allowed to block, but the C{onResult} function must not
        block and should perform as little work as possible.

        A typical action for C{onResult} for a threadpool used with a Twisted
        reactor would be to schedule a L{twisted.internet.defer.Deferred} to
        fire in the main reactor thread using C{.callFromThread}.  Note that
        C{onResult} is called inside the separate thread, not inside the
        reactor thread.

        @param onResult: a callable with the signature C{(success, result)}.
            If the callable returns normally, C{onResult} is called with
            C{(True, result)} where C{result} is the return value of the
            callable.  If the callable throws an exception, C{onResult} is
            called with C{(False, failure)}.

            Optionally, C{onResult} may be L{None}, in which case it is not
            called at all.

        @param func: callable object to be called in separate thread

        @param args: positional arguments to be passed to C{func}

        @param kw: keyword arguments to be passed to C{func}
        Nc                     sj   z   } d}W n ty   t } d}Y nw d  _  jd ur* ||  d  _d S |s3t|  d S d S )NTF)theWorkBaseExceptionr	   onResultr   err)resultok)	inContextr   r    rX      s   

z6ThreadPool.callInThreadWithCallback.<locals>.inContextc                      s   t jg R i S )N)r   callr   )rO   ctxrN   r   r   r    <lambda>  s    z5ThreadPool.callInThreadWithCallback.<locals>.<lambda>)	r;   r   theContextTrackercurrentContextcontextsrR   rT   r'   do)r   rT   rN   rO   r   r   )rO   rZ   rN   rX   r   r    rM      s   z#ThreadPool.callInThreadWithCallbackc                 C   s.   d| _ d| _| j  | jD ]}|  qdS )z9
        Shutdown the threads in the threadpool.
        TFN)r;   r"   r'   quitr   join)r   r   r   r   r    stop  s   


zThreadPool.stopc                 C   s   |du r| j }|du r| j}|dksJ d||ksJ d|| _ || _| js)dS | j| jkr9| j| j| j  | j| j k rK| j| j | j  dS dS )z
        Adjust the number of available threads by setting C{min} and C{max} to
        new values.

        @param minthreads: The new value for L{ThreadPool.min}.

        @param maxthreads: The new value for L{ThreadPool.max}.
        Nr   r   r   )r%   r#   r"   r/   r'   rE   r=   )r   r(   r)   r   r   r    r<     s   	zThreadPool.adjustPoolsizec                 C   s:   t d| j  t d| j  t d| j  dS )zw
        Dump some plain-text informational messages to the log about the state
        of this L{ThreadPool}.
        z	waiters: z	workers: ztotal: N)r   msgr2   r1   r   r   r   r   r    	dumpStats2  s   zThreadPool.dumpStats)r   r   N)NN)#r6   r7   r8   __doc__r%   r#   r;   r"   r   r   r   staticmethodr   r
   r   currentThreadr&   r*   propertyr/   r1   r2   r:   r4   r?   rA   r   rF   rK   rL   rP   rM   rb   r<   rd   r   r   r   r    r      sL    
"




	;

r   N)re   	threadingr   r   typingr   twisted._threadsr   r&   twisted.pythonr   r   twisted.python.deprecater   twisted.python.failurer	   twisted.python.versionsr
   object
WorkerStopr   r   r   r   r    <module>   s   