σ
¨[c           @` s΅  d  Z  d d l m Z m Z m 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 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 m Z m Z y d d l Z Wn e k
 rd Z n Xe r/e Z  n  y e j! Z! Wn& e" k
 rdd e j# k re  qen Xd   Z$ d   Z% d   Z& d a' d d  Z( d   Z) d e* f d     YZ+ d S(   s   Utilities for working with multiple processes, including both forking
the server into multiple processes and managing subprocesses.
i    (   t   absolute_importt   divisiont   print_functionN(   t   hexlify(   t   Futuret"   future_set_result_unless_cancelled(   t   ioloop(   t   PipeIOStream(   t   gen_log(   t   set_close_exec(   t   stack_context(   t   errno_from_exceptiont   PY3t   APPENGINE_RUNTIMEc           C` sn   t  d k r d Sy t  j   SWn t k
 r1 n Xy t j d  SWn t t f k
 r\ n Xt j	 d  d S(   s1   Returns the number of processors on this machine.i   t   SC_NPROCESSORS_CONFs1   Could not detect number of processors; assuming 1N(
   t   multiprocessingt   Nonet	   cpu_countt   NotImplementedErrort   ost   sysconft   AttributeErrort
   ValueErrorR   t   error(    (    (    s.   lib/python2.7/site-packages/tornado/process.pyR   ;   s    c          C` s   d t  j k r d  Sd d  l }  y" t t t j d   d  } Wn1 t k
 rt t t	 j	   d  t j
   A} n X|  j |  d  S(   Nt   randomi    i   iθ  (   t   syst   modulesR   t   longR   R   t   urandomR   t   intt   timet   getpidt   seed(   R   R    (    (    s.   lib/python2.7/site-packages/tornado/process.pyt   _reseed_randomK   s    "$c          C` s0   t  j   \ }  } t |   t |  |  | f S(   N(   R   t   pipeR	   (   t   rt   w(    (    s.   lib/python2.7/site-packages/tornado/process.pyt   _pipe_cloexecY   s    

id   c   
      ` sά  t  d	 k s t  |  d	 k s* |  d k r6 t   }  n  t j d |   i      f d   } x0 t |   D]" } | |  } | d	 k	 rh | Sqh Wd } x4  rΚy t j   \ } } Wn1 t	 k
 rζ } t
 |  t j k rΰ q n    n X|   k rω q n    j |  } t j |  r9t j d | | t j |   nM t j |  d k rpt j d | | t j |   n t j d | |  q | d 7} | | k r«t d   n  | |  }	 |	 d	 k	 r |	 Sq Wt j d  d	 S(
   se  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.
    i    s   Starting %d processesc         ` s;   t  j   } | d k r) t   |  a |  S|    | <d  Sd  S(   Ni    (   R   t   forkR!   t   _task_idR   (   t   it   pid(   t   children(    s.   lib/python2.7/site-packages/tornado/process.pyt   start_child   s    
s1   child %d (pid %d) killed by signal %d, restartings3   child %d (pid %d) exited with status %d, restartings!   child %d (pid %d) exited normallyi   s"   Too many child restarts, giving upN(   R'   R   t   AssertionErrorR   R   t   infot   rangeR   t   waitt   OSErrorR   t   errnot   EINTRt   popt   WIFSIGNALEDt   warningt   WTERMSIGt   WEXITSTATUSt   RuntimeErrorR   t   exit(
   t   num_processest   max_restartsR+   R(   t   idt   num_restartsR)   t   statust   et   new_id(    (   R*   s.   lib/python2.7/site-packages/tornado/process.pyt   fork_processesc   sH    			
c           C` s   t  S(   sp   Returns the current task id, if any.

    Returns None if this process was not created by `fork_processes`.
    (   R'   (    (    (    s.   lib/python2.7/site-packages/tornado/process.pyt   task_id΄   s    t
   Subprocessc           B` s   e  Z d  Z e   Z e Z i  Z d   Z d   Z	 e
 d  Z e d    Z e d    Z e d    Z e d    Z d   Z RS(	   s   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.

    c         O` s
  t  j j   |  _ g  } g  } | j d  t j k r t   \ } } | | d <| j | | f  | j	 |  t
 |  |  _ n  | j d  t j k rδ t   \ } } | | d <| j | | f  | j	 |  t
 |  |  _ n  | j d  t j k rGt   \ }	 }
 |
 | d <| j |	 |
 f  | j	 |
  t
 |	  |  _ n  y t j | |   |  _ Wn( x | D] } t j |  qmW  n Xx | D] } t j |  qWxH d d d d g D]4 } t |  |  sΌt |  | t |  j |   qΌqΌWd  |  _ d  |  _ d  S(   Nt   stdint   stdoutt   stderrR)   (   R   t   IOLoopt   currentt   io_loopt   getRC   t   STREAMR%   t   extendt   appendR   RD   RE   RF   t
   subprocesst   Popent   procR   t   closet   hasattrt   setattrt   getattrR   t   _exit_callbackt
   returncode(   t   selft   argst   kwargst   pipe_fdst   to_closet   in_rt   in_wt   out_rt   out_wt   err_rt   err_wt   fdt   attr(    (    s.   lib/python2.7/site-packages/tornado/process.pyt   __init__Χ   sD    


#	c         C` s@   t  j |  |  _ t j   |  t j |  j <t j |  j  d S(   s  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(   R
   t   wrapRU   RC   t
   initializet   _waitingR)   t   _try_cleanup_process(   RW   t   callback(    (    s.   lib/python2.7/site-packages/tornado/process.pyt   set_exit_callbackύ   s    
c         ` s,   t         f d   } |  j |    S(   s  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
        c         ` s<   |  d k r+  r+   j  t |  d    n t   |   d  S(   Ni    (   t   set_exceptiont   CalledProcessErrorR   R   (   t   ret(   t   futuret   raise_error(    s.   lib/python2.7/site-packages/tornado/process.pyRi   #  s    (   R   Rj   (   RW   Ro   Ri   (    (   Rn   Ro   s.   lib/python2.7/site-packages/tornado/process.pyt   wait_for_exit  s    	c         ` sM     j  r d St j j    t j t j    f d      _ t   _  d S(   sΕ  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    j  S(   N(   t   add_callback_from_signalt   _cleanup(   t   sigt   frame(   t   clsRI   (    s.   lib/python2.7/site-packages/tornado/process.pyt   <lambda>>  s    (   t   _initializedR   RG   RH   t   signalt   SIGCHLDt   _old_sigchldt   True(   Ru   (    (   Ru   RI   s.   lib/python2.7/site-packages/tornado/process.pyRf   ,  s    	c         C` s0   |  j  s d St j t j |  j  t |  _  d S(   s    Removes the ``SIGCHLD`` handler.N(   Rw   Rx   Ry   Rz   t   False(   Ru   (    (    s.   lib/python2.7/site-packages/tornado/process.pyt   uninitializeA  s    	c         C` s1   x* t  |  j j    D] } |  j |  q Wd  S(   N(   t   listRg   t   keysRh   (   Ru   R)   (    (    s.   lib/python2.7/site-packages/tornado/process.pyRr   I  s    c         C` s   y t  j | t  j  \ } } Wn, t k
 rM } t |  t j k rN d  Sn X| d k r^ d  S| | k sp t  |  j j	 |  } | j
 j | j |  d  S(   Ni    (   R   t   waitpidt   WNOHANGR0   R   R1   t   ECHILDR,   Rg   R3   RI   Rq   t   _set_returncode(   Ru   R)   t   ret_pidR>   R?   t   subproc(    (    s.   lib/python2.7/site-packages/tornado/process.pyRh   N  s    	c         C` s   t  j |  r% t  j |  |  _ n' t  j |  s: t  t  j |  |  _ |  j |  j _ |  j r |  j } d  |  _ | |  j  n  d  S(   N(
   R   R4   R6   RV   t	   WIFEXITEDR,   R7   RP   RU   R   (   RW   R>   Ri   (    (    s.   lib/python2.7/site-packages/tornado/process.pyR   \  s    			(   t   __name__t
   __module__t   __doc__t   objectRK   R|   Rw   Rg   Rd   Rj   R{   Rp   t   classmethodRf   R}   Rr   Rh   R   (    (    (    s.   lib/python2.7/site-packages/tornado/process.pyRC   ½   s   		&	(,   R   t
   __future__R    R   R   R1   R   Rx   RN   R   R   t   binasciiR   t   tornado.concurrentR   R   t   tornadoR   t   tornado.iostreamR   t   tornado.logR   t   tornado.platform.autoR	   R
   t   tornado.utilR   R   R   t   ImportErrorR   R   R   Rl   R   t   environR   R!   R%   R'   RA   RB   R   RC   (    (    (    s.   lib/python2.7/site-packages/tornado/process.pyt   <module>   sB   
	
			Q		