Changeset 76082 in vbox for trunk/src/VBox/Main/src-global/win
- Timestamp:
- Dec 9, 2018 7:25:00 PM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 127323
- Location:
- trunk/src/VBox/Main/src-global/win
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-global/win/VBoxSDS.cpp
r76067 r76082 486 486 /** Part of the shutdown monitoring logic. */ 487 487 bool volatile m_fActivity; 488 #ifdef WITH_WATCHER 489 /** Part of the shutdown monitoring logic. */ 490 bool volatile m_fHasClients; 491 #endif 488 492 /** Auto reset event for communicating with the shutdown thread. 489 493 * This is created by startMonitor(). */ … … 497 501 * Can be decreased at system shutdown phase. */ 498 502 volatile uint32_t m_cMsShutdownTimeOut; 503 504 /** The service module instance. */ 505 static CComServiceModule * volatile s_pInstance; 499 506 500 507 public: … … 517 524 , m_fComInitialized(false) 518 525 , m_fActivity(false) 526 #ifdef WITH_WATCHER 527 , m_fHasClients(false) 528 #endif 519 529 , m_cMsShutdownTimeOut(cMsShutdownTimeout) 520 530 , m_hEventShutdown(INVALID_HANDLE_VALUE) … … 532 542 if (SUCCEEDED(hrc)) 533 543 { 534 535 544 // copy service name 536 545 int rc = ::RTUtf16Copy(m_wszServiceName, sizeof(m_wszServiceName), p_wszServiceName); … … 556 565 if (cLocks == 0) 557 566 { 558 m_fActivity = true;567 ::ASMAtomicWriteBool(&m_fActivity, true); 559 568 ::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero 560 569 } … … 562 571 } 563 572 573 /** 574 * Overload CAtlModule::Lock to untrigger automatic shutdown. 575 */ 576 virtual LONG Lock() throw() 577 { 578 LONG cLocks = ATL::CComModule::Lock(); 579 LogFunc(("Lock() called. Ref=%d\n", cLocks)); 580 #ifdef WITH_WATCHER 581 ::ASMAtomicWriteBool(&m_fActivity, true); 582 ::SetEvent(m_hEventShutdown); /* reset the timeout interval */ 583 #endif 584 return cLocks; 585 } 586 587 #ifdef WITH_WATCHER 588 589 /** Called to start the automatic shutdown behaviour based on client count 590 * rather than lock count.. */ 591 void notifyZeroClientConnections() 592 { 593 m_fHasClients = false; 594 ::ASMAtomicWriteBool(&m_fActivity, true); 595 ::SetEvent(m_hEventShutdown); 596 } 597 598 /** Called to make sure automatic shutdown is cancelled. */ 599 void notifyHasClientConnections() 600 { 601 m_fHasClients = true; 602 ::ASMAtomicWriteBool(&m_fActivity, true); 603 } 604 605 #endif /* WITH_WATCHER */ 606 564 607 protected: 565 608 566 609 bool hasActiveConnection() 567 610 { 611 #ifdef WITH_WATCHER 612 return m_fActivity || (m_fHasClients && GetLockCount() > 0); 613 #else 568 614 return m_fActivity || GetLockCount() > 0; 615 #endif 569 616 } 570 617 … … 584 631 if (!hasActiveConnection()) /* if no activity let's really bail */ 585 632 { 586 /* 587 * Disable log rotation at this point, worst case a log file 588 * becomes slightly bigger than it should. Avoids quirks with 589 * log rotation: there might be another API service process 590 * running at this point which would rotate the logs concurrently, 591 * creating a mess. 592 */ 633 ::CoSuspendClassObjects(); 634 635 /* Disable log rotation at this point, worst case a log file becomes slightly 636 bigger than it should. Avoids quirks with log rotation: There might be 637 another API service process running at this point which would rotate the 638 logs concurrently, creating a mess. */ 593 639 PRTLOGGER pReleaseLogger = ::RTLogRelGetDefaultInstance(); 594 640 if (pReleaseLogger) … … 606 652 } 607 653 } 608 ::CoSuspendClassObjects(); 654 609 655 if (!hasActiveConnection()) 610 656 break; … … 686 732 } 687 733 }; 734 735 /*static*/ CComServiceModule * volatile CComServiceModule::s_pInstance = NULL; 736 737 738 #ifdef WITH_WATCHER 739 /** 740 * Go-between for CComServiceModule and VirtualBoxSDS. 741 */ 742 void VBoxSDSNotifyClientCount(uint32_t cClients) 743 { 744 CComServiceModule *pInstance = CComServiceModule::s_pInstance; 745 if (pInstance) 746 { 747 if (cClients == 0) 748 pInstance->notifyZeroClientConnections(); 749 else 750 pInstance->notifyHasClientConnections(); 751 } 752 } 753 #endif 688 754 689 755 … … 949 1015 * Run service. 950 1016 */ 1017 CComServiceModule::s_pInstance = pServiceModule; 951 1018 hrcExit = pServiceModule->startService(nShowCmd); 952 1019 LogRelFunc(("VBoxSDS: Calling _ServiceModule.RevokeClassObjects()...\n")); 1020 CComServiceModule::s_pInstance = NULL; 953 1021 pServiceModule->RevokeClassObjects(); 954 1022 } -
trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp
r76072 r76082 29 29 #include <iprt/asm.h> 30 30 #include <iprt/critsect.h> 31 #include <iprt/mem.h> 32 #include <iprt/system.h> 31 33 32 34 #include <rpcasync.h> … … 53 55 * This is NULL if not set. */ 54 56 ComPtr<IVBoxSVCRegistration> m_ptrTheChosenOne; 57 /** The PID of the chosen one. */ 58 RTPROCESS m_pidTheChosenOne; 59 /** The current watcher thread index, UINT32_MAX if not watched. */ 60 uint32_t m_iWatcher; 61 /** The chosen one revision number. 62 * This is used to detect races while waiting for a full watcher queue. */ 63 uint32_t volatile m_iTheChosenOneRevision; 55 64 private: 56 65 /** Reference count to make destruction safe wrt hung callers. … … 63 72 public: 64 73 VBoxSDSPerUserData(com::Utf8Str const &a_rStrUserSid, com::Utf8Str const &a_rStrUsername) 65 : m_strUserSid(a_rStrUserSid), m_strUsername(a_rStrUsername), m_cRefs(1) 74 : m_strUserSid(a_rStrUserSid) 75 , m_strUsername(a_rStrUsername) 76 #ifdef WITH_WATCHER 77 , m_iWatcher(UINT32_MAX) 78 , m_iTheChosenOneRevision(0) 79 #endif 80 , m_pidTheChosenOne(NIL_RTPROCESS) 81 , m_cRefs(1) 66 82 { 67 83 RTCritSectInit(&m_Lock); … … 71 87 { 72 88 RTCritSectDelete(&m_Lock); 89 i_unchooseTheOne(true /*fIrregular*/); 73 90 } 74 91 … … 98 115 RTCritSectLeave(&m_Lock); 99 116 } 117 118 /** Reset the chosen one. */ 119 void i_unchooseTheOne(bool fIrregular) 120 { 121 if (m_ptrTheChosenOne.isNotNull()) 122 { 123 if (!fIrregular) 124 m_ptrTheChosenOne.setNull(); 125 else 126 { 127 LogRel(("i_unchooseTheOne: Irregular release ... (pid=%d (%#x) user=%s sid=%s)\n", 128 m_pidTheChosenOne, m_pidTheChosenOne, m_strUsername.c_str(), m_strUserSid.c_str())); 129 m_ptrTheChosenOne.setNull(); 130 LogRel(("i_unchooseTheOne: ... done.\n")); 131 } 132 } 133 m_pidTheChosenOne = NIL_RTPROCESS; 134 } 135 100 136 }; 101 137 102 138 103 139 104 105 // constructor / destructor 106 ///////////////////////////////////////////////////////////////////////////// 107 108 DEFINE_EMPTY_CTOR_DTOR(VirtualBoxSDS) 140 /********************************************************************************************************************************* 141 * VirtualBoxSDS - constructor / destructor * 142 *********************************************************************************************************************************/ 143 144 VirtualBoxSDS::VirtualBoxSDS() 145 : m_cVBoxSvcProcesses(0) 146 #ifdef WITH_WATCHER 147 , m_cWatchers(0) 148 , m_papWatchers(NULL) 149 #endif 150 { 151 } 152 153 154 VirtualBoxSDS::~VirtualBoxSDS() 155 { 156 #ifdef WITH_WATCHER 157 i_shutdownAllWatchers(); 158 RTMemFree(m_papWatchers); 159 m_papWatchers = NULL; 160 m_cWatchers = 0; 161 #endif 162 } 163 109 164 110 165 HRESULT VirtualBoxSDS::FinalConstruct() … … 115 170 AssertLogRelRCReturn(vrc, E_FAIL); 116 171 172 #ifdef WITH_WATCHER 173 vrc = RTCritSectInit(&m_WatcherCritSect); 174 AssertLogRelRCReturn(vrc, E_FAIL); 175 #endif 176 117 177 LogRelFlowThisFuncLeave(); 118 178 return S_OK; … … 124 184 LogRelFlowThisFuncEnter(); 125 185 186 #ifdef WITH_WATCHER 187 i_shutdownAllWatchers(); 188 RTCritSectDelete(&m_WatcherCritSect); 189 #endif 190 126 191 RTCritSectRwDelete(&m_MapCritSect); 127 192 … … 141 206 142 207 143 / / IVirtualBoxSDS methods144 ///////////////////////////////////////////////////////////////////////////// 145 208 /********************************************************************************************************************************* 209 * VirtualBoxSDS - IVirtualBoxSDS methods * 210 *********************************************************************************************************************************/ 146 211 147 212 /* SDS plan B interfaces: */ 148 213 STDMETHODIMP VirtualBoxSDS::RegisterVBoxSVC(IVBoxSVCRegistration *aVBoxSVC, LONG aPid, IUnknown **aExistingVirtualBox) 149 214 { 150 LogRel(("VirtualBoxSDS::registerVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid)); 151 #ifdef DEBUG_bird 152 RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL}; 153 RPC_STATUS rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs); 154 LogRel(("RpcServerInqCallAttributesW -> %#x ClientPID=%#x IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid\n", 155 rcRpc, CallAttribs.ClientPID, CallAttribs.IsClientLocal, CallAttribs.ProtocolSequence, CallAttribs.CallStatus, 156 CallAttribs.CallType, CallAttribs.OpNum, &CallAttribs.InterfaceUuid)); 157 #endif 215 LogRel(("registerVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid)); 216 217 /* 218 * Get the caller PID so we can validate the aPid parameter with the other two. 219 * The V2 structure requires Vista or later, so fake it if older. 220 */ 221 RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL }; 222 RPC_STATUS rcRpc; 223 if (RTSystemGetNtVersion() >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0)) 224 rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs); 225 else 226 { 227 CallAttribs.ClientPID = (HANDLE)(intptr_t)aPid; 228 rcRpc = RPC_S_OK; 229 } 158 230 159 231 HRESULT hrc; 160 232 if ( RT_VALID_PTR(aVBoxSVC) 161 && RT_VALID_PTR(aExistingVirtualBox)) 233 && RT_VALID_PTR(aExistingVirtualBox) 234 && rcRpc == RPC_S_OK 235 && (intptr_t)CallAttribs.ClientPID == aPid) 162 236 { 163 237 *aExistingVirtualBox = NULL; 164 238 165 /* Get the client user SID and name. */ 239 /* 240 * Get the client user SID and name. 241 */ 166 242 com::Utf8Str strSid; 167 243 com::Utf8Str strUsername; 168 244 if (i_getClientUserSid(&strSid, &strUsername)) 169 245 { 170 VBoxSDSPerUserData *pUserData = i_lookupOrCreatePerUserData(strSid, strUsername); 246 VBoxSDSPerUserData *pUserData = i_lookupOrCreatePerUserData(strSid, strUsername); /* (returns holding the lock) */ 171 247 if (pUserData) 172 248 { … … 184 260 catch (...) 185 261 { 186 LogRel((" VirtualBoxSDS::registerVBoxSVC: unexpected exception calling GetVirtualBox.\n"));262 LogRel(("registerVBoxSVC: Unexpected exception calling GetVirtualBox!!\n")); 187 263 hrc = E_FAIL; 188 264 } 189 265 if (FAILED_DEAD_INTERFACE(hrc)) 190 266 { 191 LogRel(("VirtualBoxSDS::registerVBoxSVC: Seems VBoxSVC instance died. Dropping it and letting caller take over. (hrc=%Rhrc)\n", hrc)); 192 pUserData->m_ptrTheChosenOne.setNull(); 267 LogRel(("registerVBoxSVC: Seems VBoxSVC instance died. Dropping it and letting caller take over. (hrc=%Rhrc)\n", hrc)); 268 #ifdef WITH_WATCHER 269 i_stopWatching(pUserData, pUserData->m_pidTheChosenOne); 270 #endif 271 pUserData->i_unchooseTheOne(true /*fIrregular*/); 193 272 } 194 273 } … … 197 276 198 277 /* 199 * Is the caller the chosen one?278 * No chosen one? Make the caller the new chosen one! 200 279 */ 201 280 if (pUserData->m_ptrTheChosenOne.isNull()) 202 281 { 203 LogRel((" VirtualBoxSDS::registerVBoxSVC: Making aPid=%u (%#x) the chosen one for user %s (%s)!\n",282 LogRel(("registerVBoxSVC: Making aPid=%u (%#x) the chosen one for user %s (%s)!\n", 204 283 aPid, aPid, pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str())); 205 pUserData->m_ptrTheChosenOne = aVBoxSVC; 284 #ifdef WITH_WATCHER 285 /* Open the process so we can watch it. */ 286 HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE /*fInherit*/, aPid); 287 if (hProcess == NULL) 288 hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE /*fInherit*/, aPid); 289 if (hProcess == NULL) 290 hProcess = OpenProcess(SYNCHRONIZE, FALSE /*fInherit*/, aPid); 291 if (hProcess != NULL) 292 { 293 if (i_watchIt(pUserData, hProcess, aPid)) 294 #endif 295 { 296 /* Make it official... */ 297 pUserData->m_ptrTheChosenOne = aVBoxSVC; 298 pUserData->m_pidTheChosenOne = aPid; 299 hrc = S_OK; 300 } 301 #ifdef WITH_WATCHER 302 else 303 { 304 305 LogRel(("registerVBoxSVC: i_watchIt failed!\n")); 306 hrc = RPC_E_OUT_OF_RESOURCES; 307 } 308 } 309 else 310 { 311 LogRel(("registerVBoxSVC: OpenProcess failed: %u\n", GetLastError())); 312 hrc = E_ACCESSDENIED; 313 } 314 #endif 206 315 } 207 316 … … 215 324 hrc = E_FAIL; 216 325 } 326 else if ( !RT_VALID_PTR(aVBoxSVC) 327 || !RT_VALID_PTR(aExistingVirtualBox)) 328 hrc = E_INVALIDARG; 329 else if (rcRpc != RPC_S_OK) 330 { 331 LogRel(("registerVBoxSVC: rcRpc=%d (%#x)!\n", rcRpc, rcRpc)); 332 hrc = E_UNEXPECTED; 333 } 217 334 else 335 { 336 LogRel(("registerVBoxSVC: Client PID mismatch: aPid=%d (%#x), RPC ClientPID=%zd (%#zx)\n", 337 aPid, aPid, CallAttribs.ClientPID, CallAttribs.ClientPID)); 218 338 hrc = E_INVALIDARG; 339 } 219 340 LogRel2(("VirtualBoxSDS::registerVBoxSVC: returns %Rhrc aExistingVirtualBox=%p\n", hrc, (IUnknown *)aExistingVirtualBox)); 220 341 return hrc; … … 224 345 STDMETHODIMP VirtualBoxSDS::DeregisterVBoxSVC(IVBoxSVCRegistration *aVBoxSVC, LONG aPid) 225 346 { 226 LogRel((" VirtualBoxSDS::deregisterVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid));347 LogRel(("deregisterVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid)); 227 348 HRESULT hrc; 228 349 if (RT_VALID_PTR(aVBoxSVC)) … … 238 359 if (aVBoxSVC == (IVBoxSVCRegistration *)pUserData->m_ptrTheChosenOne) 239 360 { 240 LogRel((" VirtualBoxSDS::deregisterVBoxSVC: It's the chosen one for %s (%s)!\n",361 LogRel(("deregisterVBoxSVC: It's the chosen one for %s (%s)!\n", 241 362 pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str())); 242 pUserData->m_ptrTheChosenOne.setNull(); 363 #ifdef WITH_WATCHER 364 i_stopWatching(pUserData, pUserData->m_pidTheChosenOne); 365 #endif 366 pUserData->i_unchooseTheOne(false /*fIrregular*/); 243 367 } 244 368 else 245 LogRel((" VirtualBoxSDS::deregisterVBoxSVC: not the choosen one (%p != %p)\n",369 LogRel(("deregisterVBoxSVC: not the choosen one (%p != %p)\n", 246 370 (IVBoxSVCRegistration *)aVBoxSVC, (IVBoxSVCRegistration *)pUserData->m_ptrTheChosenOne)); 247 371 pUserData->i_unlock(); … … 252 376 else 253 377 { 254 LogRel((" VirtualBoxSDS::deregisterVBoxSVC: Found no user data for %s (%s) (pid %u)\n",378 LogRel(("deregisterVBoxSVC: Found no user data for %s (%s) (pid %u)\n", 255 379 strSid.c_str(), strUsername.c_str(), aPid)); 256 380 hrc = S_OK; … … 268 392 269 393 /********************************************************************************************************************************* 270 * Internal Methods*394 * VirtualBoxSDS - Internal Methods * 271 395 *********************************************************************************************************************************/ 272 396 … … 307 431 catch (std::bad_alloc &) 308 432 { 309 LogRel((" VirtualBoxSDS::i_GetClientUserSID: std::bad_alloc setting rstrSid.\n"));433 LogRel(("i_GetClientUserSID: std::bad_alloc setting rstrSid.\n")); 310 434 } 311 435 LocalFree((HLOCAL)pwszString); … … 334 458 catch (std::bad_alloc &) 335 459 { 336 LogRel((" VirtualBoxSDS::i_GetClientUserSID: std::bad_alloc setting rStrUsername.\n"));460 LogRel(("i_GetClientUserSID: std::bad_alloc setting rStrUsername.\n")); 337 461 a_pStrUsername->setNull(); 338 462 } 339 463 } 340 464 else 341 LogRel((" VirtualBoxSDS::i_GetClientUserSID: LookupAccountSidW failed: %u/%x (cwcUsername=%u, cwcDomain=%u)\n",465 LogRel(("i_GetClientUserSID: LookupAccountSidW failed: %u/%x (cwcUsername=%u, cwcDomain=%u)\n", 342 466 GetLastError(), cwcUsername, cwcDomain)); 343 467 } 344 468 } 345 469 else 346 LogRel((" VirtualBoxSDS::i_GetClientUserSID: ConvertSidToStringSidW failed: %u\n", GetLastError()));470 LogRel(("i_GetClientUserSID: ConvertSidToStringSidW failed: %u\n", GetLastError())); 347 471 } 348 472 else 349 LogRel((" VirtualBoxSDS::i_GetClientUserSID: GetTokenInformation/TokenUser failed: %u\n", GetLastError()));473 LogRel(("i_GetClientUserSID: GetTokenInformation/TokenUser failed: %u\n", GetLastError())); 350 474 CloseHandle(hToken); 351 475 } … … 353 477 { 354 478 CoRevertToSelf(); 355 LogRel((" VirtualBoxSDS::i_GetClientUserSID: OpenThreadToken failed: %u\n", GetLastError()));479 LogRel(("i_GetClientUserSID: OpenThreadToken failed: %u\n", GetLastError())); 356 480 } 357 481 } 358 482 else 359 LogRel((" VirtualBoxSDS::i_GetClientUserSID: CoImpersonateClient failed: %Rhrc\n", hrc));483 LogRel(("i_GetClientUserSID: CoImpersonateClient failed: %Rhrc\n", hrc)); 360 484 CoUninitialize(); 361 485 return fRet; … … 453 577 454 578 if (pUserData) 455 LogRel((" VirtualBoxSDS::i_lookupOrCreatePerUserData: Created new entry for %s (%s)\n",579 LogRel(("i_lookupOrCreatePerUserData: Created new entry for %s (%s)\n", 456 580 pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str() )); 457 581 else … … 467 591 } 468 592 593 #ifdef WITH_WATCHER 594 /** 595 * Data about what's being watched. 596 */ 597 typedef struct VBoxSDSWatcherData 598 { 599 /** The per-user data (referenced). */ 600 VBoxSDSPerUserData *pUserData; 601 /** The chosen one revision number (for handling an almost impossible race 602 * where a client terminates while making a deregistration call). */ 603 uint32_t iRevision; 604 /** The PID we're watching. */ 605 RTPROCESS pid; 606 607 /** Sets the members to NULL values. */ 608 void setNull() 609 { 610 pUserData = NULL; 611 iRevision = UINT32_MAX; 612 pid = NIL_RTPROCESS; 613 } 614 } VBoxSDSWatcherData; 615 616 /** 617 * Per watcher data. 618 */ 619 typedef struct VBoxSDSWatcher 620 { 621 /** Pointer to the VBoxSDS instance. */ 622 VirtualBoxSDS *pVBoxSDS; 623 /** The thread handle. */ 624 RTTHREAD hThread; 625 /** Number of references to this structure. */ 626 uint32_t volatile cRefs; 627 /** Set if the thread should shut down. */ 628 bool volatile fShutdown; 629 /** Number of pending items in the todo array. */ 630 uint32_t cTodos; 631 /** The watcher number. */ 632 uint32_t iWatcher; 633 /** The number of handles once TODOs have been taken into account. */ 634 uint32_t cHandlesEffective; 635 /** Number of handles / user data items being monitored. */ 636 uint32_t cHandles; 637 /** Array of handles. 638 * The zero'th entry is the event semaphore use to signal the thread. */ 639 HANDLE aHandles[MAXIMUM_WAIT_OBJECTS]; 640 /** Array the runs parallel to aHandles with the VBoxSVC data. */ 641 VBoxSDSWatcherData aData[MAXIMUM_WAIT_OBJECTS]; 642 /** Todo items. */ 643 struct 644 { 645 /** If NULL the data is being removed, otherwise it's being added and 646 * this is the process handle to watch for termination. */ 647 HANDLE hProcess; 648 /** The data about what's being watched. */ 649 VBoxSDSWatcherData Data; 650 } aTodos[MAXIMUM_WAIT_OBJECTS * 4]; 651 652 653 /** Helper for removing a handle & data table entry. */ 654 uint32_t removeHandle(uint32_t iEntry, uint32_t cHandles) 655 { 656 uint32_t cToShift = cHandles - iEntry - 1; 657 if (cToShift > 0) 658 { 659 memmove(&aData[iEntry], &aData[iEntry + 1], sizeof(aData[0]) * cToShift); 660 memmove(&aHandles[iEntry], &aHandles[iEntry + 1], sizeof(aHandles[0]) * cToShift); 661 } 662 cHandles--; 663 aHandles[cHandles] = NULL; 664 aData[cHandles].setNull(); 665 666 return cHandles; 667 } 668 } VBoxSDSWatcher; 669 670 671 672 /** 673 * Watcher thread. 674 */ 675 /*static*/ DECLCALLBACK(int) VirtualBoxSDS::i_watcherThreadProc(RTTHREAD hSelf, void *pvUser) 676 { 677 VBoxSDSWatcher *pThis = (VBoxSDSWatcher *)pvUser; 678 VirtualBoxSDS *pVBoxSDS = pThis->pVBoxSDS; 679 RT_NOREF(hSelf); 680 681 /* 682 * This thread may release references to IVBoxSVCRegistration objects. 683 */ 684 CoInitializeEx(NULL, COINIT_MULTITHREADED); 685 686 /* 687 * The loop. 688 */ 689 RTCritSectEnter(&pVBoxSDS->m_WatcherCritSect); 690 while (!pThis->fShutdown) 691 { 692 /* 693 * Deal with the todo list. 694 */ 695 uint32_t cHandles = pThis->cHandles; 696 uint32_t cTodos = pThis->cTodos; 697 698 for (uint32_t i = 0; i < cTodos; i++) 699 { 700 VBoxSDSPerUserData *pUserData = pThis->aTodos[i].Data.pUserData; 701 AssertContinue(pUserData); 702 if (pThis->aTodos[i].hProcess != NULL) 703 { 704 /* Add: */ 705 AssertLogRelMsgBreakStmt(cHandles < RT_ELEMENTS(pThis->aHandles), 706 ("cHandles=%u cTodos=%u i=%u iWatcher=%u\n", cHandles, cTodos, i, pThis->iWatcher), 707 pThis->fShutdown = true); 708 pThis->aHandles[cHandles] = pThis->aTodos[i].hProcess; 709 pThis->aData[cHandles] = pThis->aTodos[i].Data; 710 cHandles++; 711 } 712 else 713 { 714 /* Remove: */ 715 uint32_t cRemoved = 0; 716 uint32_t j = cHandles; 717 while (j-- > 1) 718 if (pThis->aData[j].pUserData == pUserData) 719 { 720 cHandles = pThis->removeHandle(j, cHandles); 721 pUserData->i_release(); 722 cRemoved++; 723 } 724 if (cRemoved != 1) 725 LogRel(("i_watcherThreadProc/#%u: Warning! cRemoved=%u pUserData=%p\n", pThis->iWatcher, cRemoved, pUserData)); 726 } 727 /* Zap the entry in case we assert and leave further up. */ 728 pThis->aTodos[i].Data.setNull(); 729 pThis->aTodos[i].hProcess = NULL; 730 } 731 732 Assert(cHandles > 0 && cHandles <= RT_ELEMENTS(pThis->aHandles)); 733 pThis->cHandles = cHandles; 734 pThis->cHandlesEffective = cHandles; 735 pThis->cTodos = 0; 736 737 if (pThis->fShutdown) 738 break; 739 740 /* 741 * Wait. 742 */ 743 RTCritSectLeave(&pVBoxSDS->m_WatcherCritSect); 744 745 LogRel(("i_watcherThreadProc/#%u: Waiting on %u handles...\n", pThis->iWatcher, cHandles)); 746 DWORD const dwWait = WaitForMultipleObjects(cHandles, pThis->aHandles, FALSE /*fWaitAll*/, INFINITE); 747 LogRel(("i_watcherThreadProc/#%u: ... wait returned: %#x (%d)\n", pThis->iWatcher, dwWait, dwWait)); 748 749 uint32_t const iHandle = dwWait - WAIT_OBJECT_0; 750 if (iHandle < cHandles && iHandle > 0) 751 { 752 /* 753 * A VBoxSVC process has terminated. 754 * 755 * Note! We need to take the user data lock before the watcher one here. 756 */ 757 VBoxSDSPerUserData * const pUserData = pThis->aData[iHandle].pUserData; 758 uint32_t const iRevision = pThis->aData[iHandle].iRevision; 759 RTPROCESS const pid = pThis->aData[iHandle].pid; 760 761 pUserData->i_lock(); 762 RTCritSectEnter(&pVBoxSDS->m_WatcherCritSect); 763 764 DWORD dwExit = 0; 765 GetExitCodeProcess(pThis->aHandles[iHandle], &dwExit); 766 LogRel(("i_watcherThreadProc/#%u: %p/%s: PID %u/%#x termination detected: %d (%#x) [iRev=%u, cur %u]\n", 767 pThis->iWatcher, pUserData, pUserData->m_strUsername.c_str(), pid, pid, dwExit, dwExit, 768 iRevision, pUserData->m_iTheChosenOneRevision)); 769 770 /* Remove it from the handle array. */ 771 CloseHandle(pThis->aHandles[iHandle]); 772 pThis->cHandles = cHandles = pThis->removeHandle(iHandle, cHandles); 773 pThis->cHandlesEffective -= 1; 774 775 /* If the process we were watching is still the current chosen one, 776 unchoose it and decrement the client count. Otherwise we were subject 777 to a deregistration/termination race (unlikely). */ 778 if (pUserData->m_iTheChosenOneRevision == iRevision) 779 { 780 pUserData->i_unchooseTheOne(true /*fIrregular*/); 781 pUserData->i_unlock(); 782 pVBoxSDS->i_decrementClientCount(); 783 } 784 else 785 pUserData->i_unlock(); 786 pUserData->i_release(); 787 } 788 else 789 { 790 RTCritSectEnter(&pThis->pVBoxSDS->m_WatcherCritSect); 791 AssertLogRelMsgBreak(iHandle == 0 || dwWait == WAIT_TIMEOUT, 792 ("dwWait=%u (%#x) cHandles=%u\n", dwWait, dwWait, cHandles)); 793 } 794 } 795 796 RTCritSectLeave(&pThis->pVBoxSDS->m_WatcherCritSect); 797 798 /* 799 * In case we quit w/o being told, signal i_watchIt that we're out of action. 800 */ 801 pThis->fShutdown = true; 802 803 /* 804 * Release all our data on the way out. 805 */ 806 uint32_t i = pThis->cHandles; 807 while (i-- > 1) 808 { 809 if (pThis->aData[i].pUserData) 810 { 811 pThis->aData[i].pUserData->i_release(); 812 pThis->aData[i].pUserData = NULL; 813 } 814 if (pThis->aHandles[i]) 815 { 816 CloseHandle(pThis->aHandles[i]); 817 pThis->aHandles[i] = NULL; 818 } 819 } 820 if (pThis->aHandles[0]) 821 { 822 CloseHandle(pThis->aHandles[0]); 823 pThis->aHandles[0] = NULL; 824 } 825 826 i = pThis->cTodos; 827 pThis->cTodos = 0; 828 while (i-- > 0) 829 { 830 if (pThis->aTodos[i].Data.pUserData) 831 { 832 pThis->aTodos[i].Data.pUserData->i_release(); 833 pThis->aTodos[i].Data.pUserData = NULL; 834 } 835 if (pThis->aTodos[i].hProcess) 836 { 837 CloseHandle(pThis->aTodos[i].hProcess); 838 pThis->aTodos[i].hProcess = NULL; 839 } 840 } 841 842 if (ASMAtomicDecU32(&pThis->cRefs) == 0) 843 RTMemFree(pThis); 844 845 return VINF_SUCCESS; 846 } 847 848 849 /** 850 * Starts monitoring a VBoxSVC process. 851 * 852 * @param pUserData The user which chosen VBoxSVC should be watched. 853 * @param hProcess Handle to the VBoxSVC process. Consumed. 854 * @param pid The VBoxSVC PID. 855 * @returns Success indicator. 856 */ 857 bool VirtualBoxSDS::i_watchIt(VBoxSDSPerUserData *pUserData, HANDLE hProcess, RTPROCESS pid) 858 { 859 RTCritSectEnter(&m_WatcherCritSect); 860 861 /* 862 * Find a watcher with capacity left over (we save 8 entries for removals). 863 */ 864 for (uint32_t i = 0; i < m_cWatchers; i++) 865 { 866 VBoxSDSWatcher *pWatcher = m_papWatchers[i]; 867 if ( pWatcher->cHandlesEffective < RT_ELEMENTS(pWatcher->aHandles) 868 && !pWatcher->fShutdown) 869 { 870 uint32_t iTodo = pWatcher->cTodos; 871 if (iTodo + 8 < RT_ELEMENTS(pWatcher->aTodos)) 872 { 873 pWatcher->aTodos[iTodo].hProcess = hProcess; 874 pWatcher->aTodos[iTodo].Data.pUserData = pUserData; 875 pWatcher->aTodos[iTodo].Data.iRevision = ++pUserData->m_iTheChosenOneRevision; 876 pWatcher->aTodos[iTodo].Data.pid = pid; 877 pWatcher->cTodos = iTodo + 1; 878 879 pUserData->m_iWatcher = pWatcher->iWatcher; 880 pUserData->i_retain(); 881 882 BOOL fRc = SetEvent(pWatcher->aHandles[0]); 883 AssertLogRelMsg(fRc, ("SetEvent(%p) failed: %u\n", pWatcher->aHandles[0], GetLastError())); 884 LogRel(("i_watchIt: Added %p/%p to watcher #%u: %RTbool\n", pUserData, hProcess, pWatcher->iWatcher, fRc)); 885 886 i_incrementClientCount(); 887 RTCritSectLeave(&m_WatcherCritSect); 888 RTThreadYield(); 889 return true; 890 } 891 } 892 } 893 894 /* 895 * No watcher with capacity was found, so create a new one with 896 * the user/handle prequeued. 897 */ 898 void *pvNew = RTMemRealloc(m_papWatchers, sizeof(m_papWatchers[0]) * (m_cWatchers + 1)); 899 if (pvNew) 900 { 901 m_papWatchers = (VBoxSDSWatcher **)pvNew; 902 VBoxSDSWatcher *pWatcher = (VBoxSDSWatcher *)RTMemAllocZ(sizeof(*pWatcher)); 903 if (pWatcher) 904 { 905 for (uint32_t i = 0; i < RT_ELEMENTS(pWatcher->aData); i++) 906 pWatcher->aData[i].setNull(); 907 for (uint32_t i = 0; i < RT_ELEMENTS(pWatcher->aTodos); i++) 908 pWatcher->aTodos[i].Data.setNull(); 909 910 pWatcher->pVBoxSDS = this; 911 pWatcher->iWatcher = m_cWatchers; 912 pWatcher->cRefs = 2; 913 pWatcher->cHandlesEffective = 2; 914 pWatcher->cHandles = 2; 915 pWatcher->aHandles[0] = CreateEventW(NULL, FALSE /*fManualReset*/, FALSE /*fInitialState*/, NULL); 916 if (pWatcher->aHandles[0]) 917 { 918 /* Add incoming VBoxSVC process in slot #1: */ 919 pWatcher->aHandles[1] = hProcess; 920 pWatcher->aData[1].pid = pid; 921 pWatcher->aData[1].pUserData = pUserData; 922 pWatcher->aData[1].iRevision = ++pUserData->m_iTheChosenOneRevision; 923 pUserData->i_retain(); 924 pUserData->m_iWatcher = pWatcher->iWatcher; 925 926 /* Start the thread and we're good. */ 927 m_papWatchers[m_cWatchers++] = pWatcher; 928 int rc = RTThreadCreateF(&pWatcher->hThread, i_watcherThreadProc, pWatcher, 0, RTTHREADTYPE_MAIN_WORKER, 929 RTTHREADFLAGS_WAITABLE, "watcher%u", pWatcher->iWatcher); 930 if (RT_SUCCESS(rc)) 931 { 932 LogRel(("i_watchIt: Created new watcher #%u for %p/%p\n", m_cWatchers, pUserData, hProcess)); 933 934 i_incrementClientCount(); 935 RTCritSectLeave(&m_WatcherCritSect); 936 return true; 937 } 938 939 LogRel(("i_watchIt: Error starting watcher thread: %Rrc\n", rc)); 940 m_papWatchers[--m_cWatchers] = NULL; 941 942 pUserData->m_iWatcher = UINT32_MAX; 943 pUserData->i_release(); 944 CloseHandle(pWatcher->aHandles[0]); 945 } 946 else 947 LogRel(("i_watchIt: CreateEventW failed: %u\n", GetLastError())); 948 RTMemFree(pWatcher); 949 } 950 else 951 LogRel(("i_watchIt: failed to allocate watcher structure!\n")); 952 } 953 else 954 LogRel(("i_watchIt: Failed to grow watcher array to %u entries!\n", m_cWatchers + 1)); 955 956 RTCritSectLeave(&m_WatcherCritSect); 957 CloseHandle(hProcess); 958 return false; 959 } 960 961 962 /** 963 * Stops monitoring a VBoxSVC process. 964 * 965 * @param pUserData The user which chosen VBoxSVC should be watched. 966 * @param pid The VBoxSVC PID. 967 */ 968 void VirtualBoxSDS::i_stopWatching(VBoxSDSPerUserData *pUserData, RTPROCESS pid) 969 { 970 /* 971 * Add a remove order in the watcher's todo queue. 972 */ 973 RTCritSectEnter(&m_WatcherCritSect); 974 for (uint32_t iRound = 0; ; iRound++) 975 { 976 uint32_t const iWatcher = pUserData->m_iWatcher; 977 if (iWatcher < m_cWatchers) 978 { 979 VBoxSDSWatcher *pWatcher = m_papWatchers[pUserData->m_iWatcher]; 980 if (!pWatcher->fShutdown) 981 { 982 /* 983 * Remove duplicate todo entries. 984 */ 985 bool fAddIt = true; 986 uint32_t iTodo = pWatcher->cTodos; 987 while (iTodo-- > 0) 988 if (pWatcher->aTodos[iTodo].Data.pUserData == pUserData) 989 { 990 if (pWatcher->aTodos[iTodo].hProcess == NULL) 991 fAddIt = true; 992 else 993 { 994 fAddIt = false; 995 CloseHandle(pWatcher->aTodos[iTodo].hProcess); 996 } 997 uint32_t const cTodos = --pWatcher->cTodos; 998 uint32_t const cToShift = cTodos - iTodo; 999 if (cToShift > 0) 1000 memmove(&pWatcher->aTodos[iTodo], &pWatcher->aTodos[iTodo + 1], sizeof(pWatcher->aTodos[0]) * cToShift); 1001 pWatcher->aTodos[cTodos].hProcess = NULL; 1002 pWatcher->aTodos[cTodos].Data.setNull(); 1003 } 1004 1005 /* 1006 * Did we just eliminated the add and cancel out this operation? 1007 */ 1008 if (!fAddIt) 1009 { 1010 pUserData->m_iWatcher = UINT32_MAX; 1011 pUserData->m_iTheChosenOneRevision++; 1012 i_decrementClientCount(); 1013 1014 RTCritSectLeave(&m_WatcherCritSect); 1015 RTThreadYield(); 1016 return; 1017 } 1018 1019 /* 1020 * No we didn't. So, try append a removal item. 1021 */ 1022 iTodo = pWatcher->cTodos; 1023 if (iTodo < RT_ELEMENTS(pWatcher->aTodos)) 1024 { 1025 pWatcher->aTodos[iTodo].hProcess = NULL; 1026 pWatcher->aTodos[iTodo].Data.pUserData = pUserData; 1027 pWatcher->aTodos[iTodo].Data.pid = pid; 1028 pWatcher->aTodos[iTodo].Data.iRevision = pUserData->m_iTheChosenOneRevision++; 1029 pWatcher->cTodos = iTodo + 1; 1030 SetEvent(pWatcher->aHandles[0]); 1031 1032 pUserData->m_iWatcher = UINT32_MAX; 1033 i_decrementClientCount(); 1034 1035 RTCritSectLeave(&m_WatcherCritSect); 1036 RTThreadYield(); 1037 return; 1038 } 1039 } 1040 else 1041 { 1042 LogRel(("i_stopWatching: Watcher #%u has shut down.\n", iWatcher)); 1043 break; 1044 } 1045 1046 /* 1047 * Todo queue is full. Sleep a little and let the watcher process it. 1048 */ 1049 LogRel(("i_stopWatching: Watcher #%u todo queue is full! (round #%u)\n", iWatcher, iRound)); 1050 1051 uint32_t const iTheChosenOneRevision = pUserData->m_iTheChosenOneRevision; 1052 SetEvent(pWatcher->aHandles[0]); 1053 1054 RTCritSectLeave(&m_WatcherCritSect); 1055 RTThreadSleep(1 + (iRound & 127)); 1056 RTCritSectEnter(&m_WatcherCritSect); 1057 1058 AssertLogRelMsgBreak(pUserData->m_iTheChosenOneRevision == iTheChosenOneRevision, 1059 ("Impossible! m_iTheChosenOneRevision changed %#x -> %#x!\n", 1060 iTheChosenOneRevision, pUserData->m_iTheChosenOneRevision)); 1061 } 1062 else 1063 { 1064 AssertLogRelMsg(pUserData->m_iWatcher == UINT32_MAX, 1065 ("Impossible! iWatcher=%d m_cWatcher=%u\n", iWatcher, m_cWatchers)); 1066 break; 1067 } 1068 } 1069 RTCritSectLeave(&m_WatcherCritSect); 1070 } 1071 1072 1073 /** 1074 * Shutdowns all the watchers. 1075 */ 1076 void VirtualBoxSDS::i_shutdownAllWatchers(void) 1077 { 1078 LogRel(("i_shutdownAllWatchers: %u watchers\n", m_cWatchers)); 1079 1080 /* Notify them all. */ 1081 uint32_t i = m_cWatchers; 1082 while (i-- > 0) 1083 { 1084 ASMAtomicWriteBool(&m_papWatchers[i]->fShutdown, true); 1085 SetEvent(m_papWatchers[i]->aHandles[0]); 1086 } 1087 1088 /* Wait for them to complete and destroy their data. */ 1089 i = m_cWatchers; 1090 m_cWatchers = 0; 1091 while (i-- > 0) 1092 { 1093 VBoxSDSWatcher *pWatcher = m_papWatchers[i]; 1094 if (pWatcher) 1095 { 1096 m_papWatchers[i] = NULL; 1097 1098 int rc = RTThreadWait(pWatcher->hThread, RT_MS_1MIN / 2, NULL); 1099 if (RT_SUCCESS(rc)) 1100 pWatcher->hThread = NIL_RTTHREAD; 1101 else 1102 LogRel(("i_shutdownAllWatchers: RTThreadWait failed on #%u: %Rrc\n", i, rc)); 1103 1104 if (ASMAtomicDecU32(&pWatcher->cRefs) == 0) 1105 RTMemFree(pWatcher); 1106 } 1107 } 1108 } 1109 1110 1111 /** 1112 * Increments the VBoxSVC client count. 1113 */ 1114 void VirtualBoxSDS::i_incrementClientCount() 1115 { 1116 Assert(RTCritSectIsOwner(&m_WatcherCritSect)); 1117 uint32_t cClients = ++m_cVBoxSvcProcesses; 1118 Assert(cClients < 4096); 1119 VBoxSDSNotifyClientCount(cClients); 1120 } 1121 1122 1123 /** 1124 * Decrements the VBoxSVC client count. 1125 */ 1126 void VirtualBoxSDS::i_decrementClientCount() 1127 { 1128 Assert(RTCritSectIsOwner(&m_WatcherCritSect)); 1129 uint32_t cClients = --m_cVBoxSvcProcesses; 1130 Assert(cClients < 4096); 1131 VBoxSDSNotifyClientCount(cClients); 1132 } 1133 1134 1135 #endif /* WITH_WATCHER */ 1136 1137 469 1138 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note:
See TracChangeset
for help on using the changeset viewer.