a
    mzfa<                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 dZ
G dd dZe Ze ZG dd dejZG d	d
 d
ZdS )z8A thread-based worker pool.

.. spelling::

   joinable
    N)	pass_none)WorkerThread
ThreadPoolc                   @   s    e Zd ZdZdd Zdd ZdS )	TrueyZerozDObject which equals and does math like the integer 0 but evals True.c                 C   s   |S N selfotherr   r   H/var/www/media/lib/python3.9/site-packages/cheroot/workers/threadpool.py__add__   s    zTrueyZero.__add__c                 C   s   |S r   r   r   r   r   r   __radd__   s    zTrueyZero.__radd__N)__name__
__module____qualname____doc__r   r   r   r   r   r   r      s   r   c                   @   s4   e Zd ZdZdZdZdZdd Zdd Zdd	 Z	dS )
r   aF  Thread which continuously polls a Queue for Connection objects.

    Due to the timing issues of polling a Queue, a WorkerThread does not
    check its own 'ready' flag after it has started. To stop the thread,
    it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
    (one for each running WorkerThread).
    NFc                    sv   d _ | _d _d _d _d _d _ fdd fdd fdd fddd	d d
d d _tj	
  dS )zInitialize WorkerThread instance.

        Args:
            server (cheroot.server.HTTPServer): web server object
                receiving this request
        Fr   Nc                    s    j  jd u rtp jj  S r   )requests_seen
start_time	trueyzeroconnsr	   r   r   <lambda>I   s
   
z'WorkerThread.__init__.<locals>.<lambda>c                    s    j  jd u rtp jjj  S r   )
bytes_readr   r   r   rfiler   r   r   r   r   N   s
   
c                    s    j  jd u rtp jjj  S r   )bytes_writtenr   r   r   wfiler   r   r   r   r   S   s
   
c                    s"    j  jd u rtpt  j  S r   )	work_timer   r   timer   r   r   r   r   X   s
   
c                 S   s   | d | | d | pd S )N
Bytes Read	Work Timeư>r   r   r   r   r   r   ]   s   
c                 S   s   | d | | d | pd S )NBytes Writtenr!   r"   r   r   r   r   r   r   `   s   
)ZRequestsr    r#   r!   zRead ThroughputzWrite Throughput)readyserverr   r   r   r   r   stats	threadingThread__init__)r	   r%   r   r   r   r)   9   s    



zWorkerThread.__init__c              
   C   s   | j | jj d | j< d| _zz|   W n ttfyz } z6|jpD|}| jjd|t	j
d || j_W Y d}~nRd}~0  ty } z2| jjd|dt	jdd || j_ W Y d}~n
d}~0 0 W d	| _nd	| _0 dS )
a0  Set up incoming HTTP connection processing loop.

        This is the thread's entry-point. It performs lop-layer
        exception handling and interrupt processing.
        :exc:`KeyboardInterrupt` and :exc:`SystemExit` bubbling up
        from the inner-layer code constitute a global server interrupt
        request. When they happen, the worker thread exits.

        :raises BaseException: when an unexpected non-interrupt
                               exception leaks from the inner layers

        # noqa: DAR401 KeyboardInterrupt SystemExit
        zWorker ThreadsTz%Setting the server interrupt flag to levelNzAA fatal exception happened. Setting the server interrupt flag to z and giving up.

Please, report this on the Cheroot tracker at <https://github.com/cherrypy/cheroot/issues/new/choose>, providing a full reproducer with as much context and details as possible.r+   	tracebackF)r&   r%   namer$   &_process_connections_until_interruptedKeyboardInterrupt
SystemExit	__cause__	error_logloggingDEBUGZ	interruptBaseExceptionCRITICAL)r	   Zinterrupt_excZinterrupt_causeZunderlying_excr   r   r   runf   s,    

zWorkerThread.runc                 C   sV  | j j }|tu rdS || _| j jd }|r8t | _d}zz| }W n t	y* } zd}| j j
d|jd|jd|dtjd W Y d}~W |r| j | n|  |r|  j|j7  _|  j|jj7  _|  j|jj7  _|  jt | j 7  _d| _d| _q W Y d}~n4d}~0  ttfy } zHd}| j j
d	|jd|jd|dtjd tt||W Y d}~nd}~0  tyT } z| j j
d
|tjdd W Y d}~W |r| j | n|  |r8|  j|j7  _|  j|jj7  _|  j|jj7  _|  jt | j 7  _d| _d| _q W Y d}~n
d}~0 0 W |rl| j | n|  |r|  j|j7  _|  j|jj7  _|  j|jj7  _|  jt | j 7  _d| _d| _q |r| j | n|  |rH|  j|j7  _|  j|jj7  _|  j|jj7  _|  jt | j 7  _d| _d| _0 q dS )a  Process incoming HTTP connections in an infinite loop.

        Retrieves incoming connections from thread pool, processing
        them one by one.

        :raises SystemExit: on the internal requests to stop the
                            server instance
        NZEnabledFz8Got a connection error while handling a connection from :z ()r*   z?Got a server shutdown request while handling a connection from z8Unhandled error while processing an incoming connection Tr,   )r%   requestsget_SHUTDOWNREQUESTr   r&   r   r   communicateConnectionErrorr3   Zremote_addrZremote_portr4   INFOZput_conncloser   r   r   r   r   r   r0   r1   r5   strr6   ERROR)r	   r   Zis_stats_enabledZkeep_conn_openZconnection_errorshutdown_requestZunhandled_errorr   r   r   r/      s    

&z3WorkerThread._process_connections_until_interrupted)
r   r   r   r   r   r%   r$   r)   r8   r/   r   r   r   r   r   %   s   -,r   c                   @   s   e Zd ZdZdddZdd Zedd	 Zd
d Zdd Z	dd Z
dd Zdd ZdddZeedd Zdd Zedd ZdS ) r   zA Request Queue for an HTTPServer which pools threads.

    ThreadPool objects must provide min, get(), put(obj), start()
    and stop(timeout) attributes.
    
   c                 C   s   |dk rt d|d|tdkr&n4t|tr8|dkrJtd|dn|dk rZtd}||k rxt d|d	|d
|| _|| _|| _g | _t	j
|d| _|| _| jj| _t | _dS )an  Initialize HTTP requests queue instance.

        Args:
            server (cheroot.server.HTTPServer): web server object
                receiving this request
            min (int): minimum number of worker threads
            max (int): maximum number of worker threads (-1/inf for no max)
            accepted_queue_size (int): maximum number of active
                requests in queue
            accepted_queue_timeout (int): timeout for putting request
                into queue

        :raises ValueError: if the min/max values are invalid
        :raises TypeError: if the max is not an integer or inf
           zmin=z must be > 0infr   zIExpected an integer or the infinity value for the `max` argument but got .zmax=z must be > min=z (or infinity for no max))maxsizeN)
ValueErrorfloat
isinstanceint	TypeErrorr%   minmax_threadsqueueQueue_queue_queue_put_timeoutr<   collectionsdeque_pending_shutdowns)r	   r%   rP   rQ   Zaccepted_queue_sizeZaccepted_queue_timeoutr   r   r   r)      s0    
zThreadPool.__init__c                 C   s   | j rtd| | j dS )zaStart the pool of threads.

        :raises RuntimeError: if the pool is already started
        z%Threadpools can only be started once.N)rR   RuntimeErrorgrowrP   r   r   r   r   start  s    zThreadPool.startc                 C   s(   t dd | jD }t|t | j dS )z3Number of worker threads which are idle. Read-only.c                 S   s   g | ]}|j d u r|qS r   r   .0tr   r   r   
<listcomp>#      z#ThreadPool.idle.<locals>.<listcomp>r   )lenrR   rQ   rY   )r	   Zidlesr   r   r   idle   s    zThreadPool.idlec                 C   s   | j j|d| jd dS )zPut request into queue.

        Args:
            obj (:py:class:`~cheroot.server.HTTPConnection`): HTTP connection
                waiting to be processed
        T)blocktimeoutN)rU   putrV   )r	   objr   r   r   rg   &  s    zThreadPool.putc              	   C   sH   dd | j D D ]2}| j | z| j  W q ty@   Y q0 qd S )Nc                 S   s   g | ]}|  s|qS r   )is_aliver^   r   r   r   ra   1  rb   z2ThreadPool._clear_dead_threads.<locals>.<listcomp>)rR   removerY   popleft
IndexError)r	   r`   r   r   r   _clear_dead_threads/  s    zThreadPool._clear_dead_threadsc                    sb   t  j t j d}t||} fddt|D }|D ]}|js:td q>q: j| dS )z.Spawn new worker threads (not above self.max).r   c                    s   g | ]}   qS r   )_spawn_worker)r_   ir   r   r   ra   =  rb   z#ThreadPool.grow.<locals>.<listcomp>g?N)	rQ   rc   rR   rP   ranger$   r   sleepextend)r	   amountZbudgetZn_newworkersworkerr   r   r   r[   8  s    
zThreadPool.growc                 C   s&   t | j}dj|jd|_|  |S )NzCP Server {worker_name!s})Zworker_name)r   r%   formatr.   r\   )r	   ru   r   r   r   rn   C  s    
zThreadPool._spawn_workerc                 C   sl   |t | j8 }|   |dkr"dS tt | j| j d}t||}t|D ]}| jd | j	t
 qJdS )z-Kill off worker threads (not below self.min).r   N)rc   rY   rm   rQ   rR   rP   rp   appendrU   rg   r=   )r	   rs   Zn_extraZn_to_remove_r   r   r   shrinkL  s    
zThreadPool.shrink   c              	   C   s   |dur"|dk r"d}t jddd |dur6t | }| jD ]}| jt q<ttf}| 	 D ]R}|op|t  }z*|
| | r| |j |
  W q^ |y   Y q^0 q^dS )z|Terminate all worker threads.

        Args:
            timeout (int): time to wait for threads to stop gracefully
        Nr   zZIn the future, negative timeouts to Server.stop() will be equivalent to a timeout of zero.   )
stacklevel)warningswarningr   rR   rU   rg   r=   rZ   r0   _clear_threadsjoinri   _force_closer   )r	   rf   endtimeru   Zignored_errorsZremaining_timer   r   r   stopb  s,    

zThreadPool.stopc                 C   sX   | j jrd S z4z| jtj W n ty<   | j  Y n0 W n tyR   Y n0 d S r   )r   closedsocketshutdownSHUT_RDrO   OSErrorr]   r   r   r   r     s    zThreadPool._force_closec                 C   s,   | j dd g  }| j dd< dd |D S )z3Clear self._threads and yield all joinable threads.Nc                 s   s   | ]}|t  ur|V  qd S r   )r'   current_thread)r_   threadr   r   r   	<genexpr>  s   z,ThreadPool._clear_threads.<locals>.<genexpr>)rR   )r	   threadsr   r   r   r     s    zThreadPool._clear_threadsc                 C   s
   | j  S )zReturn the queue size.)rU   qsizer   r   r   r   r     s    zThreadPool.qsizeN)rE   rF   rF   rE   )rz   )r   r   r   r   r)   r\   propertyrd   rg   rm   r[   rn   ry   r   staticmethodr   r   r   r   r   r   r   r   r      s&     
.	
			
+
r   )r   rW   r4   r'   r   r   r}   rS   Zjaraco.functoolsr   __all__r   r   objectr=   r(   r   r   r   r   r   r   <module>   s   
 >