NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

plugins.py (15004B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\process\plugins.py
      2 import os
      3 import re
      4 import signal as _signal
      5 import sys
      6 import time
      7 import threading
      8 from cherrypy._cpcompat import basestring, get_daemon, get_thread_ident, ntob, set
      9 _module__file__base = os.getcwd()
     10 
     11 class SimplePlugin(object):
     12     bus = None
     13 
     14     def __init__(self, bus):
     15         self.bus = bus
     16 
     17     def subscribe(self):
     18         for channel in self.bus.listeners:
     19             method = getattr(self, channel, None)
     20             if method is not None:
     21                 self.bus.subscribe(channel, method)
     22 
     23     def unsubscribe(self):
     24         for channel in self.bus.listeners:
     25             method = getattr(self, channel, None)
     26             if method is not None:
     27                 self.bus.unsubscribe(channel, method)
     28 
     29 
     30 class SignalHandler(object):
     31     handlers = {}
     32     signals = {}
     33     for k, v in vars(_signal).items():
     34         if k.startswith('SIG') and not k.startswith('SIG_'):
     35             signals[v] = k
     36 
     37     del k
     38     del v
     39 
     40     def __init__(self, bus):
     41         self.bus = bus
     42         self.handlers = {'SIGTERM': self.bus.exit,
     43          'SIGHUP': self.handle_SIGHUP,
     44          'SIGUSR1': self.bus.graceful}
     45         if sys.platform[:4] == 'java':
     46             del self.handlers['SIGUSR1']
     47             self.handlers['SIGUSR2'] = self.bus.graceful
     48             self.bus.log('SIGUSR1 cannot be set on the JVM platform. Using SIGUSR2 instead.')
     49             self.handlers['SIGINT'] = self._jython_SIGINT_handler
     50         self._previous_handlers = {}
     51 
     52     def _jython_SIGINT_handler(self, signum = None, frame = None):
     53         self.bus.log('Keyboard Interrupt: shutting down bus')
     54         self.bus.exit()
     55 
     56     def subscribe(self):
     57         for sig, func in self.handlers.items():
     58             try:
     59                 self.set_handler(sig, func)
     60             except ValueError:
     61                 pass
     62 
     63     def unsubscribe(self):
     64         for signum, handler in self._previous_handlers.items():
     65             signame = self.signals[signum]
     66             if handler is None:
     67                 self.bus.log('Restoring %s handler to SIG_DFL.' % signame)
     68                 handler = _signal.SIG_DFL
     69             else:
     70                 self.bus.log('Restoring %s handler %r.' % (signame, handler))
     71             try:
     72                 our_handler = _signal.signal(signum, handler)
     73                 if our_handler is None:
     74                     self.bus.log('Restored old %s handler %r, but our handler was not registered.' % (signame, handler), level=30)
     75             except ValueError:
     76                 self.bus.log('Unable to restore %s handler %r.' % (signame, handler), level=40, traceback=True)
     77 
     78     def set_handler(self, signal, listener = None):
     79         if isinstance(signal, basestring):
     80             signum = getattr(_signal, signal, None)
     81             if signum is None:
     82                 raise ValueError('No such signal: %r' % signal)
     83             signame = signal
     84         else:
     85             try:
     86                 signame = self.signals[signal]
     87             except KeyError:
     88                 raise ValueError('No such signal: %r' % signal)
     89 
     90             signum = signal
     91         prev = _signal.signal(signum, self._handle_signal)
     92         self._previous_handlers[signum] = prev
     93         if listener is not None:
     94             self.bus.log('Listening for %s.' % signame)
     95             self.bus.subscribe(signame, listener)
     96 
     97     def _handle_signal(self, signum = None, frame = None):
     98         signame = self.signals[signum]
     99         self.bus.log('Caught signal %s.' % signame)
    100         self.bus.publish(signame)
    101 
    102     def handle_SIGHUP(self):
    103         if os.isatty(sys.stdin.fileno()):
    104             self.bus.log('SIGHUP caught but not daemonized. Exiting.')
    105             self.bus.exit()
    106         else:
    107             self.bus.log('SIGHUP caught while daemonized. Restarting.')
    108             self.bus.restart()
    109 
    110 
    111 try:
    112     import pwd, grp
    113 except ImportError:
    114     pwd, grp = (None, None)
    115 
    116 class DropPrivileges(SimplePlugin):
    117 
    118     def __init__(self, bus, umask = None, uid = None, gid = None):
    119         SimplePlugin.__init__(self, bus)
    120         self.finalized = False
    121         self.uid = uid
    122         self.gid = gid
    123         self.umask = umask
    124 
    125     def _get_uid(self):
    126         return self._uid
    127 
    128     def _set_uid(self, val):
    129         if val is not None:
    130             if pwd is None:
    131                 self.bus.log('pwd module not available; ignoring uid.', level=30)
    132                 val = None
    133             elif isinstance(val, basestring):
    134                 val = pwd.getpwnam(val)[2]
    135         self._uid = val
    136 
    137     uid = property(_get_uid, _set_uid, doc='The uid under which to run. Availability: Unix.')
    138 
    139     def _get_gid(self):
    140         return self._gid
    141 
    142     def _set_gid(self, val):
    143         if val is not None:
    144             if grp is None:
    145                 self.bus.log('grp module not available; ignoring gid.', level=30)
    146                 val = None
    147             elif isinstance(val, basestring):
    148                 val = grp.getgrnam(val)[2]
    149         self._gid = val
    150 
    151     gid = property(_get_gid, _set_gid, doc='The gid under which to run. Availability: Unix.')
    152 
    153     def _get_umask(self):
    154         return self._umask
    155 
    156     def _set_umask(self, val):
    157         if val is not None:
    158             try:
    159                 os.umask
    160             except AttributeError:
    161                 self.bus.log('umask function not available; ignoring umask.', level=30)
    162                 val = None
    163 
    164         self._umask = val
    165 
    166     umask = property(_get_umask, _set_umask, doc='The default permission mode for newly created files and directories.\n        \n        Usually expressed in octal format, for example, ``0644``.\n        Availability: Unix, Windows.\n        ')
    167 
    168     def start(self):
    169 
    170         def current_ids():
    171             name, group = (None, None)
    172             if pwd:
    173                 name = pwd.getpwuid(os.getuid())[0]
    174             if grp:
    175                 group = grp.getgrgid(os.getgid())[0]
    176             return (name, group)
    177 
    178         if self.finalized:
    179             if not (self.uid is None and self.gid is None):
    180                 self.bus.log('Already running as uid: %r gid: %r' % current_ids())
    181         elif self.uid is None and self.gid is None:
    182             if pwd or grp:
    183                 self.bus.log('uid/gid not set', level=30)
    184         else:
    185             self.bus.log('Started as uid: %r gid: %r' % current_ids())
    186             if self.gid is not None:
    187                 os.setgid(self.gid)
    188                 os.setgroups([])
    189             if self.uid is not None:
    190                 os.setuid(self.uid)
    191             self.bus.log('Running as uid: %r gid: %r' % current_ids())
    192         if self.finalized:
    193             if self.umask is not None:
    194                 self.bus.log('umask already set to: %03o' % self.umask)
    195         elif self.umask is None:
    196             self.bus.log('umask not set', level=30)
    197         else:
    198             old_umask = os.umask(self.umask)
    199             self.bus.log('umask old: %03o, new: %03o' % (old_umask, self.umask))
    200         self.finalized = True
    201 
    202     start.priority = 77
    203 
    204 
    205 class Daemonizer(SimplePlugin):
    206 
    207     def __init__(self, bus, stdin = '/dev/null', stdout = '/dev/null', stderr = '/dev/null'):
    208         SimplePlugin.__init__(self, bus)
    209         self.stdin = stdin
    210         self.stdout = stdout
    211         self.stderr = stderr
    212         self.finalized = False
    213 
    214     def start(self):
    215         if self.finalized:
    216             self.bus.log('Already deamonized.')
    217         if threading.activeCount() != 1:
    218             self.bus.log('There are %r active threads. Daemonizing now may cause strange failures.' % threading.enumerate(), level=30)
    219         sys.stdout.flush()
    220         sys.stderr.flush()
    221         try:
    222             pid = os.fork()
    223             if pid == 0:
    224                 pass
    225             else:
    226                 self.bus.log('Forking once.')
    227                 os._exit(0)
    228         except OSError:
    229             exc = sys.exc_info()[1]
    230             sys.exit('%s: fork #1 failed: (%d) %s\n' % (sys.argv[0], exc.errno, exc.strerror))
    231 
    232         os.setsid()
    233         try:
    234             pid = os.fork()
    235             if pid > 0:
    236                 self.bus.log('Forking twice.')
    237                 os._exit(0)
    238         except OSError:
    239             exc = sys.exc_info()[1]
    240             sys.exit('%s: fork #2 failed: (%d) %s\n' % (sys.argv[0], exc.errno, exc.strerror))
    241 
    242         os.chdir('/')
    243         os.umask(0)
    244         si = open(self.stdin, 'r')
    245         so = open(self.stdout, 'a+')
    246         se = open(self.stderr, 'a+')
    247         os.dup2(si.fileno(), sys.stdin.fileno())
    248         os.dup2(so.fileno(), sys.stdout.fileno())
    249         os.dup2(se.fileno(), sys.stderr.fileno())
    250         self.bus.log('Daemonized to PID: %s' % os.getpid())
    251         self.finalized = True
    252 
    253     start.priority = 65
    254 
    255 
    256 class PIDFile(SimplePlugin):
    257 
    258     def __init__(self, bus, pidfile):
    259         SimplePlugin.__init__(self, bus)
    260         self.pidfile = pidfile
    261         self.finalized = False
    262 
    263     def start(self):
    264         pid = os.getpid()
    265         if self.finalized:
    266             self.bus.log('PID %r already written to %r.' % (pid, self.pidfile))
    267         else:
    268             open(self.pidfile, 'wb').write(ntob('%s' % pid, 'utf8'))
    269             self.bus.log('PID %r written to %r.' % (pid, self.pidfile))
    270             self.finalized = True
    271 
    272     start.priority = 70
    273 
    274     def exit(self):
    275         try:
    276             os.remove(self.pidfile)
    277             self.bus.log('PID file removed: %r.' % self.pidfile)
    278         except (KeyboardInterrupt, SystemExit):
    279             raise
    280         except:
    281             pass
    282 
    283 
    284 class PerpetualTimer(threading._Timer):
    285 
    286     def run(self):
    287         while True:
    288             self.finished.wait(self.interval)
    289             if self.finished.isSet():
    290                 return
    291             try:
    292                 self.function(*self.args, **self.kwargs)
    293             except Exception:
    294                 self.bus.log('Error in perpetual timer thread function %r.' % self.function, level=40, traceback=True)
    295                 raise
    296 
    297 
    298 class BackgroundTask(threading.Thread):
    299 
    300     def __init__(self, interval, function, args = [], kwargs = {}):
    301         threading.Thread.__init__(self)
    302         self.interval = interval
    303         self.function = function
    304         self.args = args
    305         self.kwargs = kwargs
    306         self.running = False
    307 
    308     def cancel(self):
    309         self.running = False
    310 
    311     def run(self):
    312         self.running = True
    313         while self.running:
    314             time.sleep(self.interval)
    315             if not self.running:
    316                 return
    317             try:
    318                 self.function(*self.args, **self.kwargs)
    319             except Exception:
    320                 self.bus.log('Error in background task thread function %r.' % self.function, level=40, traceback=True)
    321                 raise
    322 
    323     def _set_daemon(self):
    324         return True
    325 
    326 
    327 class Monitor(SimplePlugin):
    328     callback = None
    329     frequency = 60
    330     thread = None
    331 
    332     def __init__(self, bus, callback, frequency = 60, name = None):
    333         SimplePlugin.__init__(self, bus)
    334         self.callback = callback
    335         self.frequency = frequency
    336         self.thread = None
    337         self.name = name
    338 
    339     def start(self):
    340         if self.frequency > 0:
    341             threadname = self.name or self.__class__.__name__
    342             if self.thread is None:
    343                 self.thread = BackgroundTask(self.frequency, self.callback)
    344                 self.thread.bus = self.bus
    345                 self.thread.setName(threadname)
    346                 self.thread.start()
    347                 self.bus.log('Started monitor thread %r.' % threadname)
    348             else:
    349                 self.bus.log('Monitor thread %r already started.' % threadname)
    350 
    351     start.priority = 70
    352 
    353     def stop(self):
    354         if self.thread is None:
    355             self.bus.log('No thread running for %s.' % self.name or self.__class__.__name__)
    356         else:
    357             if self.thread is not threading.currentThread():
    358                 name = self.thread.getName()
    359                 self.thread.cancel()
    360                 if not get_daemon(self.thread):
    361                     self.bus.log('Joining %r' % name)
    362                     self.thread.join()
    363                 self.bus.log('Stopped thread %r.' % name)
    364             self.thread = None
    365 
    366     def graceful(self):
    367         self.stop()
    368         self.start()
    369 
    370 
    371 class Autoreloader(Monitor):
    372     files = None
    373     frequency = 1
    374     match = '.*'
    375 
    376     def __init__(self, bus, frequency = 1, match = '.*'):
    377         self.mtimes = {}
    378         self.files = set()
    379         self.match = match
    380         Monitor.__init__(self, bus, self.run, frequency)
    381 
    382     def start(self):
    383         if self.thread is None:
    384             self.mtimes = {}
    385         Monitor.start(self)
    386 
    387     start.priority = 70
    388 
    389     def sysfiles(self):
    390         files = set()
    391         for k, m in sys.modules.items():
    392             if re.match(self.match, k):
    393                 if hasattr(m, '__loader__') and hasattr(m.__loader__, 'archive'):
    394                     f = m.__loader__.archive
    395                 else:
    396                     f = getattr(m, '__file__', None)
    397                     if f is not None and not os.path.isabs(f):
    398                         f = os.path.normpath(os.path.join(_module__file__base, f))
    399                 files.add(f)
    400 
    401         return files
    402 
    403     def run(self):
    404         for filename in self.sysfiles() | self.files:
    405             if filename:
    406                 if filename.endswith('.pyc'):
    407                     filename = filename[:-1]
    408                 oldtime = self.mtimes.get(filename, 0)
    409                 if oldtime is None:
    410                     continue
    411                 try:
    412                     mtime = os.stat(filename).st_mtime
    413                 except OSError:
    414                     mtime = None
    415 
    416                 if filename not in self.mtimes:
    417                     self.mtimes[filename] = mtime
    418                 elif mtime is None or mtime > oldtime:
    419                     self.bus.log('Restarting because %s changed.' % filename)
    420                     self.thread.cancel()
    421                     self.bus.log('Stopped thread %r.' % self.thread.getName())
    422                     self.bus.restart()
    423                     return
    424 
    425 
    426 class ThreadManager(SimplePlugin):
    427     threads = None
    428 
    429     def __init__(self, bus):
    430         self.threads = {}
    431         SimplePlugin.__init__(self, bus)
    432         self.bus.listeners.setdefault('acquire_thread', set())
    433         self.bus.listeners.setdefault('start_thread', set())
    434         self.bus.listeners.setdefault('release_thread', set())
    435         self.bus.listeners.setdefault('stop_thread', set())
    436 
    437     def acquire_thread(self):
    438         thread_ident = get_thread_ident()
    439         if thread_ident not in self.threads:
    440             i = len(self.threads) + 1
    441             self.threads[thread_ident] = i
    442             self.bus.publish('start_thread', i)
    443 
    444     def release_thread(self):
    445         thread_ident = get_thread_ident()
    446         i = self.threads.pop(thread_ident, None)
    447         if i is not None:
    448             self.bus.publish('stop_thread', i)
    449 
    450     def stop(self):
    451         for thread_ident, i in self.threads.items():
    452             self.bus.publish('stop_thread', i)
    453 
    454         self.threads.clear()
    455 
    456     graceful = stop