
    gi                        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  ej                         Z G d de      Z G d de      Z	 ddlZddlZ G d
 de      Z G d de      Z G d de      Z G d dej.                        Z G d dej2                        Z G d de      Z G d de      Z G d de      Zy# e$ r d	\  ZZY yw xY w)z2Site services for use with a Web Site Process Bus.    N)text_or_bytes)ntobc                   (    e Zd ZdZdZ	 d Zd Zd Zy)SimplePluginzCPlugin base class which auto-subscribes methods for known channels.Nc                     || _         y Nbusselfr
   s     -/opt/Tautulli/lib/cherrypy/process/plugins.py__init__zSimplePlugin.__init__(   s	        c                     | j                   j                  D ].  }t        | |d      }|| j                   j                  ||       0 y)z>Register this object as a (multi-channel) listener on the bus.N)r
   	listenersgetattr	subscriber   channelmethods      r   r   zSimplePlugin.subscribe+   sC    xx)) 	4GT7D1F!""7F3		4r   c                     | j                   j                  D ].  }t        | |d      }|| j                   j                  ||       0 y)z0Unregister this object as a listener on the bus.N)r
   r   r   unsubscriber   s      r   r   zSimplePlugin.unsubscribe3   sC    xx)) 	6GT7D1F!$$Wf5		6r   )__name__
__module____qualname____doc__r
   r   r   r    r   r   r   r   !   s    M
C46r   r   c                       e Zd ZdZi Z	 i Z	  ee      j                         D ].  \  Z	Z
e	j                  d      se	j                  d      r*e	ee
<   0 [	[
d ZddZd Zd Zd	 Zdd
ZddZd Zy)SignalHandlera  Register bus channels (and listeners) for system signals.

    You can modify what signals your application listens for, and what it does
    when it receives signals, by modifying :attr:`SignalHandler.handlers`,
    a dict of {signal name: callback} pairs. The default set is::

        handlers = {'SIGTERM': self.bus.exit,
                    'SIGHUP': self.handle_SIGHUP,
                    'SIGUSR1': self.bus.graceful,
                   }

    The :func:`SignalHandler.handle_SIGHUP`` method calls
    :func:`bus.restart()<cherrypy.process.wspbus.Bus.restart>`
    if the process is daemonized, but
    :func:`bus.exit()<cherrypy.process.wspbus.Bus.exit>`
    if the process is attached to a TTY. This is because Unix window
    managers tend to send SIGHUP to terminal windows when the user closes them.

    Feel free to add signals which are not available on every platform.
    The :class:`SignalHandler` will ignore errors raised from attempting
    to register handlers for unknown signals.
    SIGSIG_c                    || _         | j                   j                  | j                  | j                   j                  d| _        t
        j                  d d dk(  rd| j                  d= | j                   j                  | j                  d<   | j                   j                  d       | j                  | j                  d<   i | _	        t        j                         | _        y )N)SIGTERMSIGHUPSIGUSR1   javar%   SIGUSR2zASIGUSR1 cannot be set on the JVM platform. Using SIGUSR2 instead.SIGINT)r
   exithandle_SIGHUPgracefulhandlerssysplatformlog_jython_SIGINT_handler_previous_handlersosgetpid_original_pidr   s     r   r   zSignalHandler.__init___   s    $(HHMM#'#5#5$(HH$5$5
 <<v%i('+xx'8'8DMM)$HHLL 2 3&*&A&ADMM(#"$YY[r   Nc                 n    | j                   j                  d       | j                   j                          y )Nz%Keyboard Interrupt: shutting down bus)r
   r0   r*   )r   signumframes      r   r1   z$SignalHandler._jython_SIGINT_handlerr   s     <=r   c                     | j                   t        j                         k7  xr2 t        j                  t        j
                  j                                S )a  Return boolean indicating if the current process is
        running as a daemon.

        The criteria to determine the `daemon` condition is to verify
        if the current pid is not the same as the one that got used on
        the initial construction of the plugin *and* the stdin is not
        connected to a terminal.

        The sole validation of the tty is not enough when the plugin
        is executing inside other process like in a CI tool
        (Buildbot, Jenkins).
        )r5   r3   r4   isattyr.   stdinfilenor   s    r   _is_daemonizedzSignalHandler._is_daemonizedw   s>     "))+- .		#))**,--	
r   c                     | j                   j                         D ]  \  }}	 | j                  ||        y# t        $ r Y 'w xY w)z#Subscribe self.handlers to signals.N)r-   itemsset_handler
ValueError)r   sigfuncs      r   r   zSignalHandler.subscribe   sK    ,,. 	IC  d+	  s   7	AAc           	         | j                   j                         D ]  \  }}| j                  |   }|/| j                  j	                  d|z         t
        j                  }n"| j                  j	                  d|d|d       	 t        j                  ||      }|$| j                  j	                  d|d|dd	        y# t        $ r( | j                  j	                  d
|d|ddd       Y w xY w)z'Unsubscribe self.handlers from signals.Nz Restoring %s handler to SIG_DFL.z
Restoring z	 handler .zRestored old z%, but our handler was not registered.   levelzUnable to restore (   TrI   	traceback)	r2   r@   signalsr
   r0   _signalSIG_DFLsignalrB   )r   r7   handlersignameour_handlers        r   r   zSignalHandler.unsubscribe   s    #66<<> 	KOFGll6*G?'IJ!//7GLMK%nnVW=&HHLL")7"4;= ! ?	K  K%w079T  KKs   <C.C43C4c                    t        |t              r$t        t        |d      }|t	        d|z        |}n	 | j
                  |   }|}t        j                  || j                        }|| j                  |<   |;| j                  j                  d|z         | j                  j                  ||       yy# t        $ r t	        d|z        w xY w)a=  Subscribe a handler for the given signal (number or name).

        If the optional 'listener' argument is provided, it will be
        subscribed as a listener for the given signal's channel.

        If the given signal name or number is not available on the
        current platform, ValueError is raised.
        NzNo such signal: %rzListening for %s.)
isinstancer   r   rN   rB   rM   KeyErrorrP   _handle_signalr2   r
   r0   r   )r   rP   listenerr7   rR   prevs         r   rA   zSignalHandler.set_handler   s     fm,Wfd3F~ !5!>??G@,,v. F~~fd&9&9:*.'HHLL,w67HHw1    @ !5!>??@s   B4 4Cc                     | j                   |   }| j                  j                  d|z         | j                  j                  |       y)z?Python signal handler (self.set_handler subscribes it for you).zCaught signal %s.N)rM   r
   r0   publish)r   r7   r8   rR   s       r   rW   zSignalHandler._handle_signal   s8    ,,v&(723!r   c                     | j                         r6| j                  j                  d       | j                  j                          y| j                  j                  d       | j                  j	                          y)z!Restart if daemonized, else exit.z+SIGHUP caught while daemonized. Restarting.z*SIGHUP caught but not daemonized. Exiting.N)r>   r
   r0   restartr*   r=   s    r   r+   zSignalHandler.handle_SIGHUP   sO     HHLLFGHH HHLLEFHHMMOr   NNr   )r   r   r   r   r-   rM   varsrN   r@   kv
startswithr   r1   r>   r   r   rA   rW   r+   r   r   r   r   r   <   s    . HOG-W##% 1<<q||F';GAJ 	
1)&

$K*28"r   r   r^   c                       e Zd ZdZddZed        Zej                  d        Zed        Zej                  d        Zed        Z	e	j                  d	        Z	d
 Z
de
_        y)DropPrivilegeszDrop privileges. uid/gid arguments not available on Windows.

    Special thanks to `Gavin Baker
    <http://antonym.org/2005/12/dropping-privileges-in-python.html>`_.
    Nc                 h    t         j                  | |       d| _        || _        || _        || _        y NF)r   r   	finalizeduidgidumask)r   r
   rj   rh   ri   s        r   r   zDropPrivileges.__init__   s.    dC(
r   c                     | j                   S )zAThe uid under which to run.

        Availability: Unix.
        )_uidr=   s    r   rh   zDropPrivileges.uid        yyr   c                     |Ut         '| j                  j                  dd       d }|| _        y t        |t              rt        j
                  |      d   }|| _        y )Nz'pwd module not available; ignoring uid.rG   rH      )pwdr
   r0   rU   r   getpwnamrl   r   vals     r   rh   zDropPrivileges.uid   [    ?{F#%  ' 	 C/ll3'*	r   c                     | j                   S )zAThe gid under which to run.

        Availability: Unix.
        )_gidr=   s    r   ri   zDropPrivileges.gid   rm   r   c                     |Ut         '| j                  j                  dd       d }|| _        y t        |t              rt        j
                  |      d   }|| _        y )Nz'grp module not available; ignoring gid.rG   rH   ro   )grpr
   r0   rU   r   getgrnamrv   rr   s     r   ri   zDropPrivileges.gid  rt   r   c                     | j                   S )zThe default permission mode for newly created files and directories.

        Usually expressed in octal format, for example, ``0644``.
        Availability: Unix, Windows.
        )_umaskr=   s    r   rj   zDropPrivileges.umask  s     {{r   c                     |	 t         j                   || _        y || _        y # t        $ r) | j                  j	                  dd       d }Y || _        y w xY w)Nz-umask function not available; ignoring umask.rG   rH   )r3   rj   AttributeErrorr
   r0   r{   rr   s     r   rj   zDropPrivileges.umask  sZ    ?
 c	 " L#%  '	s   $ (AAc                    d }| j                   r=| j                  | j                  | j                  j	                  d |       z         n| j                  6| j                  *t
        st        r| j                  j	                  dd       n| j                  j	                  d |       z         | j                  4t        j                  | j                         t        j                  g        | j                  t        j                  | j                         | j                  j	                  d |       z         | j                   r<| j                  | j                  j	                  d| j                  z         d| _         y | j                  %| j                  j	                  d	d       d| _         y t        j                  | j                        }| j                  j	                  d
|| j                  fz         d| _         y )Nc                      d\  } }t         r*t        j                  t        j                               d   } t        r*t	        j
                  t        j                               d   }| |fS )z+Return the current (uid, gid) if available.r^   r   )rp   getpwuidr3   getuidrx   getgrgidgetgid)namegroups     r   current_idsz)DropPrivileges.start.<locals>.current_ids$  sM    $KD%||BIIK03RYY[1!4;r   z"Already running as uid: %r gid: %rzuid/gid not setrG   rH   zStarted as uid: %r gid: %rzRunning as uid: %r gid: %rzumask already set to: %03ozumask not setzumask old: %03o, new: %03oT)rg   rh   ri   r
   r0   rp   rx   r3   setgid	setgroupssetuidrj   )r   r   	old_umasks      r   startzDropPrivileges.start"  s   	 >>HH$)9A(]+ , xxDHH$4#HHLL!2"L=9KMIJ88'IIdhh'LL$88'IIdhh'9KMIJ >>zz%9DJJFG  zz!_B7 	 HHTZZ0	9'45 6 r   M   )NNN)r   r   r   r   r   propertyrh   setterri   rj   r   priorityr   r   r   rd   rd      s       	ZZ    	ZZ    \\ (X ENr   rd   c                   L    e Zd ZdZ	 	 d	dZd Zde_        edddd fd       Zy)

Daemonizera  Daemonize the running script.

    Use this with a Web Site Process Bus via::

        Daemonizer(bus).subscribe()

    When this component finishes, the process is completely decoupled from
    the parent environment. Please note that when this component is used,
    the return code from the parent process will still be 0 if a startup
    error occurs in the forked children. Errors in the initial daemonizing
    process still return proper exit codes. Therefore, if you use this
    plugin to daemonize, don't use the return code as an accurate indicator
    of whether the process fully started. In fact, that return code only
    indicates if the process successfully finished the first fork.
    	/dev/nullc                 h    t         j                  | |       || _        || _        || _        d| _        y rf   )r   r   r;   stdoutstderrrg   )r   r
   r;   r   r   s        r   r   zDaemonizer.__init__b  s.    dC(
r   c                 ~   | j                   r| j                  j                  d       t        j                         dk7  r2| j                  j                  dt        j
                         z  d       | j                  | j                  | j                  | j                  | j                  j                         d| _         y )NzAlready deamonized.   zHThere are %r active threads. Daemonizing now may cause strange failures.rG   rH   T)
rg   r
   r0   	threadingactive_count	enumerate	daemonizer;   r   r   r=   s    r   r   zDaemonizer.startj  s    >>HHLL./ !!#q(HHLL G",,./68  : 	tzz4;;TXX\\Jr   A   c                      y r   r   )msgs    r   <lambda>zDaemonizer.<lambda>  s    r   c           
         t         j                  j                          t         j                  j                          d}t	        d      D ]Z  }ddg|   }	 t        j                         }|dkD  r ||       t        j                  d       |dk(  sGt        j                          \ t        j                  d       t        | d      }	t        |d	      }
t        |d	      }t        j                  |	j                         t         j                   j                                t        j                  |
j                         t         j                  j                                t        j                  |j                         t         j                  j                                 |d
t        j"                         z         y # t        $ r9}t        j                  |j                  t         ||dz                Y d }~pd }~ww xY w)Nz>{sys.argv[0]}: fork #{n} failed: ({exc.errno}) {exc.strerror}
ro   zForking once.zForking twice.r   r   )r.   excnrza+zDaemonized to PID: %s)r.   r   flushr   ranger3   fork_exitOSErrorr*   formatsetsidrj   opendup2r<   r;   r4   )r;   r   r   logger
error_tmplr   r   pidr   sisoses               r   r   zDaemonizer.daemonize}  ss    	



 N 	 !H 	D"$45d;CJggi73KHHQK qy			 	%&$&$
 			SYY--/0
		SZZ..01
		SZZ..01&45'  J**stax*HIIJs   6F>>	H .G;;H N)r   r   r   )	r   r   r   r   r   r   r   staticmethodr   r   r   r   r   r   Q  s?      7B#" ENk+#*6 *6r   r   c                   0    e Zd ZdZd Zd Zde_        d Zy)PIDFilez!Maintain a PID file via a WSPBus.c                 L    t         j                  | |       || _        d| _        y rf   )r   r   pidfilerg   )r   r
   r   s      r   r   zPIDFile.__init__  s     dC(r   c                    t        j                         }| j                  r-| j                  j	                  d|d| j
                  d       y t        | j
                  d      5 }|j                  t        d|z  d             d d d        | j                  j	                  d|d| j
                  d       d| _        y # 1 sw Y   =xY w)	NzPID z already written to rF   wbz%s
utf8z written to T)	r3   r4   rg   r
   r0   r   r   writer   )r   r   fs      r   r   zPIDFile.start  s    iik>>HHLLCNOdllD) 4QVc\6234HHLLCFG!DN4 4s   $B??CF   c                     	 t        j                  | j                         | j                  j	                  d| j                  z         y # t
        t        f$ r  t        $ r Y y w xY w)NzPID file removed: %r.)r3   remover   r
   r0   KeyboardInterrupt
SystemExit	Exceptionr=   s    r   r*   zPIDFile.exit  sS    	IIdll#HHLL04<<?@!:. 	 		s   AA
 
A%$A%N)r   r   r   r   r   r   r   r*   r   r   r   r   r     s    +
" ENr   r   c                   (     e Zd ZdZ fdZd Z xZS )PerpetualTimera  A responsive subclass of threading.Timer whose run() method repeats.

    Use this timer only when you really need a very interruptible timer;
    this checks its 'finished' condition up to 20 times a second, which
    can results in pretty high CPU usage
    c                 Z    |j                  dd      | _        t        t        |   |i | y)z:Override parent constructor to allow 'bus' to be provided.r
   N)popr
   superr   r   )r   argskwargs	__class__s      r   r   zPerpetualTimer.__init__  s)    ::eT*nd,d=f=r   c                 ^   	 | j                   j                  | j                         | j                   j                         ry 	  | j                  | j
                  i | j                   h# t        $ r9 | j                  r+| j                  j                  d| j                  z  dd        w xY w)NTz,Error in perpetual timer thread function %r.rJ   rK   )
finishedwaitintervalisSetfunctionr   r   r   r
   r0   r=   s    r   runzPerpetualTimer.run  s    MMt}}-}}""$tyy8DKK8   88HHLLF&-/4 ! A s   &A* *AB,)r   r   r   r   r   r   __classcell__r   s   @r   r   r     s    >
r   r   c                   6     e Zd ZdZg i df fd	Zd Zd Z xZS )BackgroundTaska  A subclass of threading.Thread whose run() method repeats.

    Use this class for most repeating tasks. It uses time.sleep() to
    wait for each interval, which isn't very responsive; that is, even
    if you call self.cancel(), you'll have to wait until the sleep()
    call finishes before the thread stops. To compensate, it defaults to
    being daemonic, which means it won't delay stopping the whole
    process.
    Nc                     t         t        |           || _        || _        || _        || _        d| _        || _        d| _	        y )NFT)
r   r   r   r   r   r   r   runningr
   daemon)r   r   r   r   r   r
   r   s         r   r   zBackgroundTask.__init__  sC    nd,.  	 r   c                     d| _         y rf   )r   r=   s    r   cancelzBackgroundTask.cancel  s	    r   c                 v   d| _         | j                   rat        j                  | j                         | j                   sy 	  | j                  | j
                  i | j                   | j                   r`y y # t        $ r9 | j                  r+| j                  j                  d| j                  z  dd        w xY w)NTz,Error in background task thread function %r.rJ   rK   )
r   timesleepr   r   r   r   r   r
   r0   r=   s    r   r   zBackgroundTask.run  s    llJJt}}%<<tyy8DKK8 ll  88HHLL!O#'=="18:d ! L s   &A6 6AB8)r   r   r   r   r   r   r   r   r   s   @r   r   r     s      1324 
r   r   c                   J    e Zd ZdZdZ	 dZ	 dZ	 d	dZd Zde_	        d Z
d Zy)
MonitorzAWSPBus listener to periodically run a callback in its own thread.N<   c                 h    t         j                  | |       || _        || _        d | _        || _        y r   )r   r   callback	frequencythreadr   )r   r
   r   r   r   s        r   r   zMonitor.__init__  s.    dC( "	r   c                    | j                   dkD  r| j                  xs | j                  j                  }| j                  {t        | j                   | j                  | j                        | _        || j                  _        | j                  j                          | j                  j                  d|z         y| j                  j                  d|z         yy)z0Start our callback in its own background thread.r   Nr	   zStarted monitor thread %r.z"Monitor thread %r already started.)
r   r   r   r   r   r   r   r
   r   r0   )r   
threadnames     r   r   zMonitor.start$  s    >>A=dnn&=&=J{{",T^^T]]15;#- !!#9JFGAJNO r   r   c                 $   | j                   A| j                  j                  d| j                  z  xs | j                  j
                         y| j                   t        j                         ur| j                   j                  }| j                   j                          | j                   j                  s8| j                  j                  d|z         | j                   j                          | j                  j                  d|z         d| _         y)z+Stop our callback's background task thread.NzNo thread running for %s.z
Joining %rStopped thread %r.)r   r
   r0   r   r   r   r   current_threadr   r   join)r   r   s     r   stopzMonitor.stop2  s    ;;HHLL4# >&*nn&=&=? {{)":":"<<{{''""${{))HHLL!45KK$$&1D89DKr   c                 D    | j                          | j                          y)z:Stop the callback's background task thread and restart it.N)r   r   r=   s    r   r,   zMonitor.gracefulA  s    		

r   )r   N)r   r   r   r   r   r   r   r   r   r   r   r,   r   r   r   r   r     s=    KH,I4FP ENr   r   c                       e Zd ZdZdZ	 dZ	 dZ	 ddZd Zde_	        d Z
ed	        Zed
        Zed        Zed        Zd Zy)AutoreloaderaQ  Monitor which re-executes the process when files change.

    This :ref:`plugin<plugins>` restarts the process (via :func:`os.execv`)
    if any of the files it monitors change (or is deleted). By default, the
    autoreloader monitors all imported modules; you can add to the
    set by adding to ``autoreload.files``::

        cherrypy.engine.autoreload.files.add(myFile)

    If there are imported files you do *not* wish to monitor, you can
    adjust the ``match`` attribute, a regular expression. For example,
    to stop monitoring cherrypy itself::

        cherrypy.engine.autoreload.match = r'^(?!cherrypy).+'

    Like all :class:`Monitor<cherrypy.process.plugins.Monitor>` plugins,
    the autoreload plugin takes a ``frequency`` argument. The default is
    1 second; that is, the autoreloader will examine files once each second.
    Nr   .*c                     i | _         t               | _        || _        t        j                  | || j                  |       y r   )mtimessetfilesmatchr   r   r   )r   r
   r   r   s       r   r   zAutoreloader.__init__e  s1    U

sDHHi8r   c                 T    | j                   i | _        t        j                  |        y)z2Start our own background task thread for self.run.N)r   r   r   r   r=   s    r   r   zAutoreloader.startk  s    ;;DKdr   r   c           	      L   t        t        j                  | j                        j                  t	        t
        j                  j                                     }t        t
        j                  j                  |      }t        t        dt        | j                  |                  S )z1Return a Set of sys.modules filenames to monitor.N)filterrecompiler   listr.   moduleskeysmapgetr   _file_for_module)r   search_mod_namesmodss      r   sysfileszAutoreloader.sysfilesr  sn    !JJtzz"((!!#$
 3;;??$456$D$9$94 @ABBr   c                 J    | j                  |      xs | j                  |      S )z(Return the relevant file for the module.)_archive_for_zip_module_file_for_file_moduleclsmodules     r   r   zAutoreloader._file_for_module{  s*     ''/ 1((0	
r   c                 N    	 | j                   j                  S # t        $ r Y yw xY w)z7Return the archive filename for the module if relevant.N)
__loader__archiver}   )r  s    r   r  z$Autoreloader._archive_for_zip_module  s+    	$$,,, 		s    	$$c                 t    	 |j                   xr | j                  |j                         S # t        $ r Y yw xY w)zReturn the file for the module.N)__file___make_absoluter}   r  s     r   r  z"Autoreloader._file_for_file_module  s7    	??Js'9'9&//'JJ 		s   (+ 	77c                     t         j                  j                  |       r| S t         j                  j                  t         j                  j	                  t
        |             S )z8Ensure filename is absolute to avoid effect of os.chdir.)r3   pathisabsnormpathr   _module__file__base)filenames    r   r  zAutoreloader._make_absolute  sB     77==2x 	
GGRWW\\*=xHI	
r   c                 r   | j                         | j                  z  D ]  }|s|j                  d      r|dd }| j                  j	                  |d      }|<	 t        j                  |      j                  }|| j                  vr|| j                  |<   z|||kD  s| j                  j                  d|z         | j                  j                          | j                  j                  d| j                  j                  z         | j                  j                           y y# t        $ r d}Y w xY w)z:Reload the process if registered files have been modified.z.pycNr   zRestarting because %s changed.r   )r  r   endswithr   r   r3   statst_mtimer   r
   r0   r   r   r   r]   )r   r  oldtimemtimes       r   r   zAutoreloader.run  s   $**4 	H$$V,'}H++//(A6?!GGH-66E
 4;;.,1DKK)}%E%-&. /**,%9%)[[%5%5&6 7((*9	  ! E!s   D((D65D6)r   r   )r   r   r   r   r   r   r   r   r   r   r  classmethodr   r   r  r  r  r   r   r   r   r   r   G  s    ( E5IFE;9
 ENC 
 
     
 
r   r   c                   2    e Zd ZdZdZ	 d Zd Zd Zd ZeZ	y)ThreadManagera  Manager for HTTP request threads.

    If you have control over thread creation and destruction, publish to
    the 'acquire_thread' and 'release_thread' channels (for each
    thread). This will register/unregister the current thread and
    publish to 'start_thread' and 'stop_thread' listeners in the bus as
    needed.

    If threads are created and destroyed by code you do not control
    (e.g., Apache), then, at the beginning of every HTTP request,
    publish to 'acquire_thread' only. You should not publish to
    'release_thread' in this case, since you do not know whether the
    thread will be re-used or not. The bus will call 'stop_thread'
    listeners for you when it stops.
    Nc                    i | _         t        j                  | |       | j                  j                  j                  dt                      | j                  j                  j                  dt                      | j                  j                  j                  dt                      | j                  j                  j                  dt                      y )Nacquire_threadstart_threadrelease_threadstop_thread)threadsr   r   r
   r   
setdefaultr   r   s     r   r   zThreadManager.__init__  s    dC(%%&6>%%nce<%%&6>%%mSU;r   c                     t        j                         }|| j                  vrDt        | j                        dz   }|| j                  |<   | j                  j                  d|       yy)zRun 'start_thread' listeners for the current thread.

        If the current thread has already been seen, any 'start_thread'
        listeners will not be run again.
        r   r!  N)_thread	get_identr$  lenr
   r[   r   thread_identis      r   r   zThreadManager.acquire_thread  sZ     ((*t||+ DLL!A%A)*DLL&HH^Q/ ,r   c                     t        j                         }| j                  j                  |d      }|| j                  j                  d|       yy)z;Release the current thread and run 'stop_thread' listeners.Nr#  )r'  r(  r$  r   r
   r[   r*  s      r   r"  zThreadManager.release_thread  sD    ((*LL\40=HH]A. r   c                     | j                   j                         D ]!  \  }}| j                  j                  d|       # | j                   j	                          y)z8Release all threads and run all 'stop_thread' listeners.r#  N)r$  r@   r
   r[   clearr*  s      r   r   zThreadManager.stop  sF    #||113 	/OL!HH]A.	/r   )
r   r   r   r   r$  r   r   r"  r   r,   r   r   r   r  r    s,      G6<0/
 Hr   r  )r   r3   r   rP   rN   r.   r   r   r'  cherrypy._cpcompatr   r   getcwdr  objectr   r   rp   rx   ImportErrorrd   r   r   Timerr   Threadr   r   r   r  r   r   r   <module>r6     s    8 	 	  
    , #$  biik 66 66TF Tn
t\ tnW6 W6tl :Y__ :'Y%% 'T5l 5pq7 qh6L 6K  HCs   C 
CC