Changeset 1830
- Timestamp:
- 11/13/07 20:08:22
- Files:
-
- trunk/cherrypy/_cpmodpy.py (modified) (1 diff)
- trunk/cherrypy/restsrv/servers.py (modified) (2 diffs)
- trunk/cherrypy/restsrv/win32.py (modified) (4 diffs)
- trunk/cherrypy/restsrv/wspbus.py (modified) (6 diffs)
- trunk/cherrypy/test/benchmark.py (modified) (1 diff)
- trunk/cherrypy/test/helper.py (modified) (2 diffs)
- trunk/cherrypy/test/test_states.py (modified) (6 diffs)
- trunk/cherrypy/test/test_states_demo.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cpmodpy.py
r1824 r1830 94 94 95 95 def cherrypy_cleanup(data): 96 cherrypy.engine. stop()96 cherrypy.engine.exit() 97 97 try: 98 98 from mod_python import apache trunk/cherrypy/restsrv/servers.py
r1824 r1830 76 76 self.bus.log("<Ctrl-C> hit: shutting down HTTP server") 77 77 self.interrupt = exc 78 self.bus. stop()78 self.bus.exit() 79 79 except SystemExit, exc: 80 80 self.bus.log("SystemExit raised: shutting down HTTP server") 81 81 self.interrupt = exc 82 self.bus. stop()82 self.bus.exit() 83 83 raise 84 84 except: … … 87 87 self.bus.log("Error in HTTP server: shutting down", 88 88 traceback=True) 89 self.bus. stop()89 self.bus.exit() 90 90 raise 91 91 trunk/cherrypy/restsrv/win32.py
r1824 r1830 43 43 pass 44 44 45 self. stop()45 self.exit() 46 46 # 'First to return True stops the calls' 47 47 return 1 … … 67 67 state = property(_get_state, _set_state) 68 68 69 def block(self, state=wspbus.states.STOPPED, interval=1):69 def wait(self, state, interval=0.1): 70 70 """Wait for the given state, KeyboardInterrupt or SystemExit. 71 71 … … 74 74 """ 75 75 # Don't wait for an event that beat us to the punch ;) 76 if self.state == state: 77 return 78 79 event = self._get_state_event(state) 80 try: 76 if self.state != state: 77 event = self._get_state_event(state) 81 78 win32event.WaitForSingleObject(event, win32event.INFINITE) 82 if self.execv:83 self._do_execv()84 except SystemExit:85 self.log('SystemExit raised: shutting down bus')86 self.stop()87 raise88 79 89 80 … … 138 129 from cherrypy import restsrv 139 130 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 140 restsrv.bus. stop()131 restsrv.bus.exit() 141 132 142 133 def SvcOther(self, control): trunk/cherrypy/restsrv/wspbus.py
r1826 r1830 52 52 | 53 53 V 54 STOPPING --> STOPPED --> X54 STOPPING --> STOPPED --> EXITING -> X 55 55 A A | 56 56 | \___ | … … 88 88 states.STARTED = states.State() 89 89 states.STOPPING = states.State() 90 states.EXITING = states.State() 90 91 91 92 … … 172 173 e_info = sys.exc_info() 173 174 try: 174 self. stop()175 self.exit() 175 176 except: 176 # Any stop errors will be logged inside publish().177 # Any stop/exit errors will be logged inside publish(). 177 178 pass 178 179 self.log("Exception that caused shutdown: %s" % start_trace) 179 180 raise e_info[0], e_info[1], e_info[2] 180 181 181 def exit(self , status=0):182 """Stop all services and exit the process."""182 def exit(self): 183 """Stop all services and prepare to exit the process.""" 183 184 self.stop() 185 186 self.state = states.EXITING 184 187 self.log('Bus exit') 185 188 self.publish('exit') 186 sys.exit(status)187 189 188 190 def restart(self): … … 193 195 """ 194 196 self.execv = True 195 self. stop()197 self.exit() 196 198 197 199 def graceful(self): … … 200 202 self.publish('graceful') 201 203 202 def block(self, state=states.STOPPED,interval=0.1):203 """Wait for the givenstate, KeyboardInterrupt or SystemExit."""204 def block(self, interval=0.1): 205 """Wait for the EXITING state, KeyboardInterrupt or SystemExit.""" 204 206 try: 205 while self.state != state: 206 time.sleep(interval) 207 if self.execv: 208 self._do_execv() 207 self.wait(states.EXITING, interval=interval) 209 208 except (KeyboardInterrupt, IOError): 210 209 # The time.sleep call might raise 211 210 # "IOError: [Errno 4] Interrupted function call" on KBInt. 212 211 self.log('Keyboard Interrupt: shutting down bus') 213 self. stop()212 self.exit() 214 213 except SystemExit: 215 214 self.log('SystemExit raised: shutting down bus') 216 self. stop()215 self.exit() 217 216 raise 218 219 def _do_execv(self): 220 """Re-execute the current process.""" 221 self.execv = False 222 223 self.log('Bus restart') 224 self.publish('exit') 225 226 # Re-execute the current process. We must do this in the 227 # main thread (which is the only thread that should be 228 # calling block) because OS X doesn't allow execv to be 229 # called in a child thread very well. 217 230 218 # Waiting for ALL child threads to finish is necessary on OS X. 231 # See: http://www.cherrypy.org/ticket/581 219 # See http://www.cherrypy.org/ticket/581. 220 # It's also good to let them all shut down before allowing 221 # the main thread to call atexit handlers. 222 # See http://www.cherrypy.org/ticket/751. 232 223 self.log("Waiting for child threads to terminate...") 233 224 for t in threading.enumerate(): 234 if t != threading.currentThread(): 225 if (t != threading.currentThread() and t.isAlive() 226 # Note that any dummy (external) threads are always daemonic. 227 and not t.isDaemon()): 235 228 t.join() 236 229 230 if self.execv: 231 self._do_execv() 232 233 def wait(self, state, interval=0.1): 234 """Wait for the given state.""" 235 while self.state != state: 236 time.sleep(interval) 237 238 def _do_execv(self): 239 """Re-execute the current process. 240 241 This must be called from the main thread, because certain platforms 242 (OS X) don't allow execv to be called in a child thread very well. 243 """ 237 244 args = sys.argv[:] 238 245 self.log('Re-spawning %s' % ' '.join(args)) 239 246 args.insert(0, sys.executable) 240 241 247 if sys.platform == 'win32': 242 248 args = ['"%s"' % arg for arg in args] … … 261 267 262 268 def _callback(func, *a, **kw): 263 self. block(states.STARTED)269 self.wait(states.STARTED) 264 270 func(*a, **kw) 265 271 t = threading.Thread(target=_callback, args=args, kwargs=kwargs) trunk/cherrypy/test/benchmark.py
r1793 r1830 378 378 run_standard_benchmarks() 379 379 finally: 380 cherrypy.engine. stop()380 cherrypy.engine.exit() 381 381 cherrypy.server.stop() 382 382 trunk/cherrypy/test/helper.py
r1824 r1830 150 150 151 151 def _run_test_suite_thread(moduleNames, conf): 152 for testmod in moduleNames: 153 # Must run each module in a separate suite, 154 # because each module uses/overwrites cherrypy globals. 155 cherrypy.tree = cherrypy._cptree.Tree() 156 cherrypy.config.reset() 157 setConfig(conf) 158 159 m = __import__(testmod, globals(), locals()) 160 setup = getattr(m, "setup_server", None) 161 if setup: 162 setup() 163 164 # The setup functions probably mounted new apps. 165 # Tell our server about them. 166 sync_apps(profile=conf.get("profiling.on", False), 167 validate=conf.get("validator.on", False), 168 conquer=conf.get("conquer.on", False), 169 ) 170 171 suite = CPTestLoader.loadTestsFromName(testmod) 172 result = CPTestRunner.run(suite) 173 cherrypy.engine.test_success &= result.wasSuccessful() 174 175 teardown = getattr(m, "teardown_server", None) 176 if teardown: 177 teardown() 178 cherrypy.engine.stop() 152 try: 153 for testmod in moduleNames: 154 # Must run each module in a separate suite, 155 # because each module uses/overwrites cherrypy globals. 156 cherrypy.tree = cherrypy._cptree.Tree() 157 cherrypy.config.reset() 158 setConfig(conf) 159 160 m = __import__(testmod, globals(), locals()) 161 setup = getattr(m, "setup_server", None) 162 if setup: 163 setup() 164 165 # The setup functions probably mounted new apps. 166 # Tell our server about them. 167 sync_apps(profile=conf.get("profiling.on", False), 168 validate=conf.get("validator.on", False), 169 conquer=conf.get("conquer.on", False), 170 ) 171 172 suite = CPTestLoader.loadTestsFromName(testmod) 173 result = CPTestRunner.run(suite) 174 cherrypy.engine.test_success &= result.wasSuccessful() 175 176 teardown = getattr(m, "teardown_server", None) 177 if teardown: 178 teardown() 179 finally: 180 cherrypy.engine.exit() 179 181 180 182 def testmain(conf=None): … … 192 194 webtest.main() 193 195 finally: 194 cherrypy.engine. stop()196 cherrypy.engine.exit() 195 197 trunk/cherrypy/test/test_states.py
r1828 r1830 135 135 self.assertStatus(503) 136 136 137 # Block the main thread now and verify that stop() works.138 def stoptest():137 # Block the main thread now and verify that exit() works. 138 def exittest(): 139 139 self.getPage("/") 140 140 self.assertBody("Hello World") 141 engine. stop()141 engine.exit() 142 142 cherrypy.server.start() 143 engine.start_with_callback( stoptest)143 engine.start_with_callback(exittest) 144 144 engine.block() 145 self.assertEqual(engine.state, engine.states. STOPPED)145 self.assertEqual(engine.state, engine.states.EXITING) 146 146 147 147 def test_1_Restart(self): … … 202 202 self.assertEqual(db_connection.running, False) 203 203 self.assertEqual(len(db_connection.threads), 0) 204 self.assertEqual(engine.state, engine.states. STOPPED)204 self.assertEqual(engine.state, engine.states.EXITING) 205 205 finally: 206 206 self.persistent = False … … 254 254 self.assertInBody("raise cherrypy.TimeoutError()") 255 255 finally: 256 engine. stop()256 engine.exit() 257 257 258 258 def test_4_Autoreload(self): … … 295 295 finally: 296 296 # Shut down the spawned process 297 self.getPage("/ stop")297 self.getPage("/exit") 298 298 299 299 try: … … 368 368 finally: 369 369 # Shut down the spawned process 370 self.getPage("/ stop")370 self.getPage("/exit") 371 371 372 372 try: … … 430 430 tr.out.close() 431 431 finally: 432 engine. stop()432 engine.exit() 433 433 434 434 trunk/cherrypy/test/test_states_demo.py
r1828 r1830 28 28 start.exposed = True 29 29 30 def stop(self):30 def exit(self): 31 31 # This handler might be called before the engine is STARTED if an 32 32 # HTTP worker thread handles it before the HTTP server returns 33 33 # control to engine.start. We avoid that race condition here 34 34 # by waiting for the Bus to be STARTED. 35 cherrypy.engine. block(state=cherrypy.engine.states.STARTED)36 cherrypy.engine. stop()37 stop.exposed = True35 cherrypy.engine.wait(state=cherrypy.engine.states.STARTED) 36 cherrypy.engine.exit() 37 exit.exposed = True 38 38 39 39

