Changeset 2331 in vbox
- Timestamp:
- Apr 24, 2007 4:21:52 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/linux/server.cpp
r2057 r2331 202 202 static PRBool volatile gKeepRunning = PR_TRUE; 203 203 204 ///////////////////////////////////////////////////////////////////////////// 205 206 /** 207 * Simple but smart PLEvent wrapper. 208 * 209 * @note Instances must be always created with <tt>operator new</tt>! 210 */ 211 class MyEvent 212 { 213 public: 214 215 MyEvent() 216 { 217 mEv.that = NULL; 218 }; 219 220 /** 221 * Posts this event to the given message queue. This method may only be 222 * called once. @note On success, the event will be deleted automatically 223 * after it is delivered and handled. On failure, the event will delete 224 * itself before this method returns! The caller must not delete it in 225 * either case. 226 */ 227 nsresult postTo (nsIEventQueue *aEventQ) 228 { 229 AssertReturn (mEv.that == NULL, NS_ERROR_FAILURE); 230 AssertReturn (aEventQ, NS_ERROR_FAILURE); 231 nsresult rv = aEventQ->InitEvent (&mEv.e, NULL, 232 eventHandler, eventDestructor); 233 if (NS_SUCCEEDED (rv)) 234 { 235 mEv.that = this; 236 rv = aEventQ->PostEvent (&mEv.e); 237 if (NS_SUCCEEDED (rv)) 238 return rv; 239 } 240 delete this; 241 return rv; 242 } 243 244 virtual void *handler() = 0; 245 246 private: 247 248 struct Ev 249 { 250 PLEvent e; 251 MyEvent *that; 252 } mEv; 253 254 static void *PR_CALLBACK eventHandler (PLEvent *self) 255 { 256 return reinterpret_cast <Ev *> (self)->that->handler(); 257 } 258 259 static void PR_CALLBACK eventDestructor (PLEvent *self) 260 { 261 delete reinterpret_cast <Ev *> (self)->that; 262 } 263 }; 264 204 265 //////////////////////////////////////////////////////////////////////////////// 205 266 … … 222 283 LogFlowFunc (("VirtualBox object deleted.\n")); 223 284 printf ("Informational: VirtualBox object deleted.\n"); 224 225 /* Instruct the main event loop to terminate. Note that it's enough226 * to set gKeepRunning to false because we are on the main thread227 * already (i.e. no need to post events there). */228 if (gAutoShutdown)229 gKeepRunning = PR_FALSE;230 285 } 231 286 … … 252 307 if (sTimer != NULL) 253 308 { 254 LogFlowFunc (("Last VirtualBox instance was released , "255 "scheduling server shutdown in %d ms...\n",309 LogFlowFunc (("Last VirtualBox instance was released.\n")); 310 LogFlowFunc (("Scheduling server shutdown in %d ms...\n", 256 311 VBoxSVC_ShutdownDelay)); 312 313 /* make sure the previous timer (if any) is stopped; 314 * otherwise RTTimerStart() will definitely fail. */ 315 RTTimerStop (sTimer); 257 316 258 317 int vrc = RTTimerStart (sTimer, uint64_t (VBoxSVC_ShutdownDelay) * 1000000); … … 303 362 } 304 363 305 /* Returns the current value of the reference counter. */ 306 nsrefcnt GetRefCount() 307 { 308 /* we don't use our own Release() to avoid its "side effect" */ 309 nsrefcnt count = VirtualBox::AddRef(); 310 count = VirtualBox::Release(); 311 return count; 312 } 313 314 /* called on the main thread */ 315 static void *PR_CALLBACK DestructEventHandler (PLEvent* self) 316 { 317 Assert (RTCritSectIsInitialized (&sLock)); 318 319 /* stop accepting GetInstance() requests during possible destruction */ 320 RTCritSectEnter (&sLock); 321 322 Assert (sInstance); 323 324 nsrefcnt count = sInstance->GetRefCount(); 325 AssertMsg (count >= 1, ("count=%d\n", count)); 326 327 if (count > 1) 328 { 329 /* This case is very unlikely because we stop the timer when a new 330 * client connects after the instance was scheduled for 331 * destruction, but it's still possible. This is the only reason 332 * for the above GetRefCount() btw. */ 333 LogFlowFunc (("Destruction is canceled (refcnt=%d).\n", count)); 334 } 335 else 336 { 337 /* release the last (first) reference we added in GetInstance() 338 * (this must call the destructor) */ 339 nsrefcnt count = sInstance->Release(); 340 AssertMsg (count == 0, ("count=%d\n", count)); 341 NOREF(count); 342 } 343 344 RTCritSectLeave (&sLock); 345 346 return 0; 347 } 348 349 static void PR_CALLBACK DestructEventDestructor (PLEvent* self) 350 { 351 delete self; 352 } 364 class MaybeQuitEvent : public MyEvent 365 { 366 /* called on the main thread */ 367 void *handler() 368 { 369 LogFlowFunc (("\n")); 370 371 Assert (RTCritSectIsInitialized (&sLock)); 372 373 /* stop accepting GetInstance() requests on other threads during 374 * possible destruction */ 375 RTCritSectEnter (&sLock); 376 377 nsrefcnt count = 0; 378 379 /* sInstance is NULL here if it was deleted immediately after 380 * creation due to initialization error. See GetInstance(). */ 381 if (sInstance != NULL) 382 { 383 /* Release the guard reference added in GetInstance() */ 384 count = sInstance->Release(); 385 } 386 387 if (count == 0) 388 { 389 if (gAutoShutdown) 390 { 391 Assert (sInstance == NULL); 392 LogFlowFunc (("Terminating the server process...\n")); 393 /* make it leave the event loop */ 394 gKeepRunning = PR_FALSE; 395 } 396 } 397 else 398 { 399 /* This condition is quite rare: a new client will have to 400 * connect after this event has been posted to the main queue 401 * but before it started to process it. */ 402 LogFlowFunc (("Destruction is canceled (refcnt=%d).\n", count)); 403 } 404 405 RTCritSectLeave (&sLock); 406 407 return NULL; 408 } 409 }; 353 410 354 411 static void ShutdownTimer (PRTTIMER pTimer, void *pvUser) … … 363 420 AssertReturnVoid (gEventQ); 364 421 365 /* post a destruction event to the main thread to safely release the 366 * extra reference added in VirtualBoxClassFactory::GetInstance() */ 367 368 LogFlowFunc (("Posting VirtualBox destruction & shtutdown event...\n")); 369 370 PLEvent *ev = new PLEvent; 371 gEventQ->InitEvent (ev, NULL, DestructEventHandler, 372 DestructEventDestructor); 373 nsresult rv = gEventQ->PostEvent (ev); 374 if (NS_FAILED (rv)) 375 { 376 /* this means we've been already stopped (for example 377 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM()) 378 * will do the job. */ 379 PL_DestroyEvent (ev); 380 } 422 /* post a quit event to the main queue */ 423 MaybeQuitEvent *ev = new MaybeQuitEvent(); 424 nsresult rv = ev->postTo (gEventQ); 425 NOREF (rv); 426 427 /* A failure above means we've been already stopped (for example 428 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM()) 429 * will do the job. Nothing to do. */ 381 430 } 382 431 … … 414 463 * or the client has terminated abnormally w/o releasing its 415 464 * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup). 416 * Release the extrareference we added in GetInstance(). */465 * Release the guard reference we added in GetInstance(). */ 417 466 sInstance->Release(); 418 467 } … … 444 493 if (NS_FAILED (rv)) 445 494 { 446 /* on failure diring VirtualBox initialization, delete it 447 * immediately on the current thread, ignoring the reference 448 * count (VirtualBox should be aware of that meaning that it 449 * has already completely unintialized itself in this 450 * case) */ 451 LogFlowFunc (("VirtualBox creation failed " 452 "(rc=%08X), deleting immediately...\n", rv)); 453 delete sInstance; 454 sInstance = 0; 495 /* On failure diring VirtualBox initialization, delete it 496 * immediately on the current thread by releasing all 497 * references in order to properly schedule the server 498 * shutdown. Since the object is fully deleted here, there 499 * is a chance to fix the error and request a new 500 * instantiation before the server terminates. However, 501 * the main reason to maintain the shoutdown delay on 502 * failure is to let the front-end completely fetch error 503 * info from a server-side IVirtualBoxErrorInfo object. */ 504 sInstance->Release(); 505 sInstance->Release(); 506 Assert (sInstance == 0); 507 } 508 else 509 { 510 /* On success, make sure the previous timer is stopped to 511 * cancel a scheduled server termination (if any). */ 512 RTTimerStop (sTimer); 455 513 } 456 514 } … … 468 526 if (count == 2) 469 527 { 470 LogFlowFunc (("Another client has requested " 471 "a reference of VirtualBox scheduled for destruction, " 528 LogFlowFunc (("Another client has requested a reference to VirtualBox, " 472 529 "canceling detruction...\n")); 473 530 … … 821 878 static char *pszPidFile = NULL; 822 879 823 void* PR_CALLBACK quitEventHandler (PLEvent* self) { gKeepRunning = PR_FALSE; return 0; } 824 void PR_CALLBACK quitEventDestructor (PLEvent* self) { delete self; } 880 class ForceQuitEvent : public MyEvent 881 { 882 void *handler() 883 { 884 LogFlowFunc (("\n")); 885 886 gKeepRunning = PR_FALSE; 887 888 if (pszPidFile) 889 RTFileDelete(pszPidFile); 890 891 return NULL; 892 } 893 }; 825 894 826 895 static void signal_handler (int sig) … … 829 898 { 830 899 /* post a quit event to the queue */ 831 PLEvent *ev = new PLEvent; 832 gEventQ->InitEvent (ev, NULL, quitEventHandler, quitEventDestructor); 833 gEventQ->PostEvent (ev); 834 } 835 if (pszPidFile) 836 { 837 RTFileDelete(pszPidFile); 838 } 839 }; 900 ForceQuitEvent *ev = new ForceQuitEvent(); 901 ev->postTo (gEventQ); 902 } 903 } 840 904 841 905 #if defined(USE_BACKTRACE)
Note:
See TracChangeset
for help on using the changeset viewer.