diff options
Diffstat (limited to 'cherrypy/process/wspbus.py')
-rw-r--r-- | cherrypy/process/wspbus.py | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/cherrypy/process/wspbus.py b/cherrypy/process/wspbus.py index 3ef0217c..5409d038 100644 --- a/cherrypy/process/wspbus.py +++ b/cherrypy/process/wspbus.py @@ -78,13 +78,16 @@ from cherrypy._cpcompat import set # sys.executable is a relative-path, and/or cause other problems). _startup_cwd = os.getcwd() + class ChannelFailures(Exception): - """Exception raised when errors occur in a listener during Bus.publish().""" + + """Exception raised when errors occur in a listener during Bus.publish(). + """ delimiter = '\n' def __init__(self, *args, **kwargs): # Don't use 'super' here; Exceptions are old-style in Py2.4 - # See http://www.cherrypy.org/ticket/959 + # See https://bitbucket.org/cherrypy/cherrypy/issue/959 Exception.__init__(self, *args, **kwargs) self._exceptions = list() @@ -107,9 +110,13 @@ class ChannelFailures(Exception): __nonzero__ = __bool__ # Use a flag to indicate the state of the bus. + + class _StateEnum(object): + class State(object): name = None + def __repr__(self): return "states.%s" % self.name @@ -137,6 +144,7 @@ else: class Bus(object): + """Process state-machine and messenger for HTTP site deployment. All listeners for a given channel are guaranteed to be called even @@ -266,14 +274,14 @@ class Bus(object): # signal handler, console handler, or atexit handler), so we # can't just let exceptions propagate out unhandled. # Assume it's been logged and just die. - os._exit(70) # EX_SOFTWARE + os._exit(70) # EX_SOFTWARE if exitstate == states.STARTING: # exit() was called before start() finished, possibly due to # Ctrl-C because a start listener got stuck. In this case, # we could get stuck in a loop where Ctrl-C never exits the # process, so we just call os.exit here. - os._exit(70) # EX_SOFTWARE + os._exit(70) # EX_SOFTWARE def restart(self): """Restart the process (may close connections). @@ -311,13 +319,21 @@ class Bus(object): raise # Waiting for ALL child threads to finish is necessary on OS X. - # See http://www.cherrypy.org/ticket/581. + # See https://bitbucket.org/cherrypy/cherrypy/issue/581. # It's also good to let them all shut down before allowing # the main thread to call atexit handlers. - # See http://www.cherrypy.org/ticket/751. + # See https://bitbucket.org/cherrypy/cherrypy/issue/751. self.log("Waiting for child threads to terminate...") for t in threading.enumerate(): - if t != threading.currentThread() and t.isAlive(): + # Validate the we're not trying to join the MainThread + # that will cause a deadlock and the case exist when + # implemented as a windows service and in any other case + # that another thread executes cherrypy.engine.exit() + if ( + t != threading.currentThread() and + t.isAlive() and + not isinstance(t, threading._MainThread) + ): # Note that any dummy (external) threads are always daemonic. if hasattr(threading.Thread, "daemon"): # Python 2.6+ @@ -389,7 +405,7 @@ class Bus(object): Set self.max_cloexec_files to 0 to disable this behavior. """ - for fd in range(3, self.max_cloexec_files): # skip stdin/out/err + for fd in range(3, self.max_cloexec_files): # skip stdin/out/err try: flags = fcntl.fcntl(fd, fcntl.F_GETFD) except IOError: |