B
    h2                 @   sD  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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mZ dd	lmZ ddlZdd
lmZmZmZmZ ejrddlmZ ejZe dddZ!ddddZ"ee e f dddZ#da$dee  e e dddZ%ee  dddZ&G dd de'Z(dS )zUtilities 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)set_close_exec)errno_from_exception)TupleOptionalAnyCallable)List)returnc            	   C   s\   t dkrdS yt  S  tk
r(   Y nX y
tdS  ttfk
rL   Y nX td dS )z1Returns the number of processors on this machine.N   ZSC_NPROCESSORS_CONFz1Could not detect number of processors; assuming 1)	multiprocessing	cpu_countNotImplementedErrorosZsysconfAttributeError
ValueErrorr   error r   r   LC:\Users\sanjo\AppData\Local\Qlobot\Launcher\ext_packages\tornado\process.pyr   3   s    

r   c              C   sj   dt jkrd S dd l} ytttdd}W n, tk
rZ   tt d t	 A }Y nX | 
| d S )Nrandomr      i  )sysmodulesr   intr   r   urandomr   timegetpidseed)r   r#   r   r   r   _reseed_randomC   s    
r$   c              C   s$   t  \} }t|  t| | |fS )N)r   piper	   )rwr   r   r   _pipe_cloexecR   s    r(   )num_processesmax_restartsr   c       
   
      s~  |dkrd}t dkst| dks(| dkr.t } td|  i  ttt d fdd}x$t| D ]}||}|dk	r`|S q`W d}x rnyt	 \}}W n4 t
k
r } zt|tjkrw W dd}~X Y nX | krq |}t|rtd||t| n8t|dkr.td	||t| ntd
|| q|d7 }||krXtd||}	|	dk	r|	S qW td dS )a  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`` returns None if all child processes
    have exited normally, but will otherwise only exit by throwing an
    exception.

    max_restarts defaults to 100.
    Nd   r   zStarting %d processes)ir   c                s.   t  }|dkrt  | a| S |  |< d 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.   AssertionErrorr   r   infor   r   ranger   waitOSErrorr
   errnoEINTRpopWIFSIGNALEDwarningWTERMSIGWEXITSTATUSRuntimeErrorr   exit)
r)   r*   r1   r,   idZnum_restartsr/   statuseZnew_idr   )r0   r   fork_processes\   sX    

rC   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    rD   c               @   s   e Zd ZdZe ZdZi ZdZe	e	ddddZ
eegdf dddd	ZdeddddZeddddZeddddZeddddZeeddddZedd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   s  t j | _g }g }|dtjkrXt \}}||d< |||f |	| t
|| _|dtjkrt \}}||d< |||f |	| t
|| _|dtjkrt \}	}
|
|d< ||	|
f |	|
 t
|	| _ytj||| _W n(   x|D ]}t| q W  Y nX x|D ]}t| q"W | jj| _x.dD ]&}t| |sFt| |t| j| qFW d | _d | _d S )Nstdinstdoutstderr)rH   rI   rJ   )r   IOLoopcurrentio_loopgetrE   STREAMr(   extendappendr   rH   rI   rJ   
subprocessPopenprocr   closer/   hasattrsetattrgetattr_exit_callback
returncode)selfrF   rG   Zpipe_fdsto_closeZin_rZin_wZout_rZout_wZerr_rZerr_wfdattrr   r   r   __init__   sF    












zSubprocess.__init__)callbackr   c             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.
        N)rY   rE   
initialize_waitingr/   _try_cleanup_process)r[   r`   r   r   r   set_exit_callback  s    zSubprocess.set_exit_callbackTzFuture[int])raise_errorr   c                s*   t   tdd fdd}| |  S )a  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
        N)retr   c                s,   | dkrrt  t| d n
t |  d S )Nr   unknown)r   CalledProcessErrorr   )rf   )futurere   r   r   r`   ,  s    z*Subprocess.wait_for_exit.<locals>.callback)r   r   rd   )r[   re   r`   r   )ri   re   r   wait_for_exit  s    	
zSubprocess.wait_for_exit)r   c                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.
        Nc                s     jS )N)add_callback_from_signal_cleanup)sigframe)clsrM   r   r   <lambda>J      z'Subprocess.initialize.<locals>.<lambda>T)_initializedr   rK   rL   signalSIGCHLD_old_sigchld)ro   r   )ro   rM   r   ra   8  s    
zSubprocess.initializec             C   s$   | j s
dS ttj| j d| _ dS )z Removes the ``SIGCHLD`` handler.NF)rr   rs   rt   ru   )ro   r   r   r   uninitializeN  s    zSubprocess.uninitializec             C   s&   x t | j D ]}| | qW d S )N)listrb   keysrc   )ro   r/   r   r   r   rl   V  s    zSubprocess._cleanup)r/   r   c          
   C   s   yt |t j\}}W n4 tk
rJ } zt|tjkr:d S W d d }~X Y nX |dkrXd S ||ksdt| j	|}|j
|j| d S )Nr   )r   waitpidWNOHANGr6   r
   r7   ECHILDr2   rb   r9   rM   rk   _set_returncode)ro   r/   Zret_pidrA   rB   Zsubprocr   r   r   rc   [  s    zSubprocess._try_cleanup_process)rA   r   c             C   s^   t |rt | | _nt |s(tt || _| j| j_| jrZ| j}d | _|| j d S )N)	r   r:   r<   rZ   	WIFEXITEDr2   r=   rT   rY   )r[   rA   r`   r   r   r   r|   h  s    

zSubprocess._set_returncode)T)__name__
__module____qualname____doc__objectrO   rr   rb   ru   r   r_   r   r   rd   boolrj   classmethodra   rv   rl   rc   r|   r   r   r   r   rE      s"   'rE   )N))r   r7   r   r   rs   rR   r   r!   binasciir   tornado.concurrentr   r   r   tornador   tornado.iostreamr   tornado.logr   tornado.platform.autor	   tornado.utilr
   typingr   r   r   r   TYPE_CHECKINGr   rh   r   r   r$   r(   r.   rC   rD   r   rE   r   r   r   r   <module>   s4   ^	