o
    Qœ_õ1  ã                   @   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mZ ddl	m
Z
mZmZ ddlmZ ddlmZ ddlmZ ddlZddlmZmZmZ ejrSdd	lmZ ejZd
efdd„Zddd„Zda	ddee dee d
efdd„Zd
ee fdd„ZG dd„ de ƒZ!dS )z„Utilities for working with multiple processes, including both forking
the server into multiple processes and managing subprocesses.
é    N)Úhexlify)ÚFutureÚ"future_set_result_unless_cancelledÚ%future_set_exception_unless_cancelled)Úioloop)ÚPipeIOStream)Úgen_log)ÚOptionalÚAnyÚCallable)ÚListÚreturnc                	   C   s\   t du rdS zt  ¡ W S  ty   Y nw zt d¡W S  ttfy&   Y nw t d¡ dS )z1Returns the number of processors on this machine.Né   ÚSC_NPROCESSORS_CONFz1Could not detect number of processors; assuming 1)	ÚmultiprocessingÚ	cpu_countÚNotImplementedErrorÚosÚsysconfÚAttributeErrorÚ
ValueErrorr   Úerror© r   r   ú1/usr/lib/python3/dist-packages/tornado/process.pyr   0   s   
ÿÿ
r   c                  C   sh   dt jvrd S dd l} zttt d¡ƒdƒ}W n ty,   tt ¡ d ƒt 	¡ A }Y nw |  
|¡ d S )NÚrandomr   é   iè  )ÚsysÚmodulesr   Úintr   r   Úurandomr   ÚtimeÚgetpidÚseed)r   r"   r   r   r   Ú_reseed_random@   s   
ÿr#   Únum_processesÚmax_restartsc           	         sN  t jdkr	tdƒ‚|du rd}tdu sJ ‚| du s| dkr tƒ } t d| ¡ i ‰ dtdtt f‡ fd	d
„}t	| ƒD ]}||ƒ}|durG|  S q9d}ˆ r t
 ¡ \}}|ˆ vrWqJˆ  |¡}t
 |¡rmt d||t
 |¡¡ nt
 |¡dkr€t d||t
 |¡¡ nt d||¡ qJ|d7 }||kr”tdƒ‚||ƒ}|durž|S ˆ sLt  d¡ dS )aq  Starts multiple worker processes.

    If ``num_processes`` is None or <= 0, we detect the number of cores
    available on this machine and fork that number of child
    processes. If ``num_processes`` is given and > 0, we fork that
    specific number of sub-processes.

    Since we use processes and not threads, there is no shared memory
    between any server code.

    Note that multiple processes are not compatible with the autoreload
    module (or the ``autoreload=True`` option to `tornado.web.Application`
    which defaults to True when ``debug=True``).
    When using multiple processes, no IOLoops can be created or
    referenced until after the call to ``fork_processes``.

    In each child process, ``fork_processes`` returns its *task id*, a
    number between 0 and ``num_processes``.  Processes that exit
    abnormally (due to a signal or non-zero exit status) are restarted
    with the same id (up to ``max_restarts`` times).  In the parent
    process, ``fork_processes`` calls ``sys.exit(0)`` after all child
    processes have exited normally.

    max_restarts defaults to 100.

    Availability: Unix
    Úwin32zfork not available on windowsNéd   r   zStarting %d processesÚir   c                    s*   t  ¡ }|dkrtƒ  | a| S | ˆ |< d S ©Nr   )r   Úforkr#   Ú_task_id)r(   Úpid©Úchildrenr   r   Ústart_child~   s   z#fork_processes.<locals>.start_childz1child %d (pid %d) killed by signal %d, restartingz3child %d (pid %d) exited with status %d, restartingz!child %d (pid %d) exited normallyr   z"Too many child restarts, giving up)r   ÚplatformÚ	Exceptionr+   r   r   Úinfor   r	   Úranger   ÚwaitÚpopÚWIFSIGNALEDÚwarningÚWTERMSIGÚWEXITSTATUSÚRuntimeErrorÚexit)	r$   r%   r/   r(   ÚidÚnum_restartsr,   ÚstatusÚnew_idr   r-   r   Úfork_processesR   sZ   
ÿ

üüå r@   c                   C   s   t S )zpReturns the current task id, if any.

    Returns None if this process was not created by `fork_processes`.
    )r+   r   r   r   r   Útask_id²   s   rA   c                   @   sº   e Zd ZdZeƒ ZdZi ZdZde	de	ddfdd„Z
d	eegdf ddfd
d„Zddeddfdd„Zeddd„ƒZeddd„ƒZeddd„ƒZededdfdd„ƒZdeddfdd„ZdS )Ú
Subprocessa   Wraps ``subprocess.Popen`` with IOStream support.

    The constructor is the same as ``subprocess.Popen`` with the following
    additions:

    * ``stdin``, ``stdout``, and ``stderr`` may have the value
      ``tornado.process.Subprocess.STREAM``, which will make the corresponding
      attribute of the resulting Subprocess a `.PipeIOStream`. If this option
      is used, the caller is responsible for closing the streams when done
      with them.

    The ``Subprocess.STREAM`` option and the ``set_exit_callback`` and
    ``wait_for_exit`` methods do not work on Windows. There is
    therefore no reason to use this class instead of
    ``subprocess.Popen`` on that platform.

    .. versionchanged:: 5.0
       The ``io_loop`` argument (deprecated since version 4.1) has been removed.

    FNÚargsÚkwargsr   c                 O   sp  t j ¡ | _g }g }| d¡tju r-t ¡ \}}||d< | 	||f¡ | 
|¡ t|ƒ| _| d¡tju rPt ¡ \}}||d< | 	||f¡ | 
|¡ t|ƒ| _| d¡tju rst ¡ \}	}
|
|d< | 	|	|
f¡ | 
|
¡ t|	ƒ| _ztj|i |¤Ž| _W n   |D ]}t |¡ q„‚ |D ]}t |¡ q�| jj| _dD ]}t| |ƒs¯t| |t| j|ƒƒ qžd | _d | _d S )NÚstdinÚstdoutÚstderr)rE   rF   rG   )r   ÚIOLoopÚcurrentÚio_loopÚgetrB   ÚSTREAMr   ÚpipeÚextendÚappendr   rE   rF   rG   Ú
subprocessÚPopenÚprocÚcloser,   ÚhasattrÚsetattrÚgetattrÚ_exit_callbackÚ
returncode)ÚselfrC   rD   Úpipe_fdsÚto_closeÚin_rÚin_wÚout_rÚout_wÚerr_rÚerr_wÚfdÚattrr   r   r   Ú__init__×   sH   







€
zSubprocess.__init__Úcallbackc                 C   s*   || _ t ¡  | tj| j< t | j¡ dS )a¦  Runs ``callback`` when this process exits.

        The callback takes one argument, the return code of the process.

        This method uses a ``SIGCHLD`` handler, which is a global setting
        and may conflict if you have other libraries trying to handle the
        same signal.  If you are using more than one ``IOLoop`` it may
        be necessary to call `Subprocess.initialize` first to designate
        one ``IOLoop`` to run the signal handlers.

        In many cases a close callback on the stdout or stderr streams
        can be used as an alternative to an exit callback if the
        signal handler is causing a problem.

        Availability: Unix
        N)rW   rB   Ú
initializeÚ_waitingr,   Ú_try_cleanup_process)rY   re   r   r   r   Úset_exit_callbackþ   s   zSubprocess.set_exit_callbackTÚraise_errorzFuture[int]c                    s,   t ƒ ‰ dtddf‡ ‡fdd„}|  |¡ ˆ S )a2  Returns a `.Future` which resolves when the process exits.

        Usage::

            ret = yield proc.wait_for_exit()

        This is a coroutine-friendly alternative to `set_exit_callback`
        (and a replacement for the blocking `subprocess.Popen.wait`).

        By default, raises `subprocess.CalledProcessError` if the process
        has a non-zero exit status. Use ``wait_for_exit(raise_error=False)``
        to suppress this behavior and return the exit status without raising.

        .. versionadded:: 4.2

        Availability: Unix
        Úretr   Nc                    s.   | dkrˆrt ˆ t| dƒƒ d S tˆ | ƒ d S )Nr   Úunknown)r   ÚCalledProcessErrorr   )rk   ©Úfuturerj   r   r   re   (  s
   
ÿz*Subprocess.wait_for_exit.<locals>.callback)r   r   ri   )rY   rj   re   r   rn   r   Úwait_for_exit  s   
	zSubprocess.wait_for_exitc                    s8   ˆ j rdS tj ¡ ‰t tj‡ ‡fdd„¡ˆ _dˆ _ dS )aá  Initializes the ``SIGCHLD`` handler.

        The signal handler is run on an `.IOLoop` to avoid locking issues.
        Note that the `.IOLoop` used for signal handling need not be the
        same one used by individual Subprocess objects (as long as the
        ``IOLoops`` are each running in separate threads).

        .. versionchanged:: 5.0
           The ``io_loop`` argument (deprecated since version 4.1) has been
           removed.

        Availability: Unix
        Nc                    s   ˆ  ˆ j¡S ©N)Úadd_callback_from_signalÚ_cleanup)ÚsigÚframe©ÚclsrJ   r   r   Ú<lambda>H  s    z'Subprocess.initialize.<locals>.<lambda>T)Ú_initializedr   rH   rI   ÚsignalÚSIGCHLDÚ_old_sigchld©rw   r   rv   r   rf   4  s   
þ
zSubprocess.initializec                 C   s$   | j sdS t tj| j¡ d| _ dS )z Removes the ``SIGCHLD`` handler.NF)ry   rz   r{   r|   r}   r   r   r   ÚuninitializeL  s   
zSubprocess.uninitializec                 C   s"   t | j ¡ ƒD ]}|  |¡ qd S rq   )Úlistrg   Úkeysrh   )rw   r,   r   r   r   rs   T  s   ÿzSubprocess._cleanupr,   c                 C   sd   zt  |t j¡\}}W n
 ty   Y d S w |dkrd S ||ks"J ‚| j |¡}|j |j|¡ d S r)   )	r   ÚwaitpidÚWNOHANGÚChildProcessErrorrg   r5   rJ   rr   Ú_set_returncode)rw   r,   Úret_pidr>   Úsubprocr   r   r   rh   Y  s   ÿzSubprocess._try_cleanup_processr>   c                 C   st   t jdkr	d| _nt |¡rt |¡ | _nt |¡sJ ‚t |¡| _| j| j_| j	r8| j	}d | _	|| jƒ d S d S )Nr&   éÿÿÿÿ)
r   r0   rX   r   r6   r8   Ú	WIFEXITEDr9   rR   rW   )rY   r>   re   r   r   r   r„   e  s   


ýzSubprocess._set_returncode)T©r   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚobjectrL   ry   rg   r|   r
   rd   r   r   ri   Úboolrp   Úclassmethodrf   r~   rs   rh   r„   r   r   r   r   rB   »   s$    ' rB   r‰   rq   )"r�   r   r   rz   rP   r   r    Úbinasciir   Útornado.concurrentr   r   r   Útornador   Útornado.iostreamr   Útornado.logr   Útypingr	   r
   r   ÚTYPE_CHECKINGr   rm   r   r   r#   r+   r@   rA   rŽ   rB   r   r   r   r   Ú<module>   s<   
ÿÿÿ
þ`	