Changeset 39300 in vbox
- Timestamp:
- Nov 15, 2011 9:57:05 AM (13 years ago)
- Location:
- trunk/src/VBox/Additions/common/VBoxService
- Files:
-
- 1 deleted
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r39279 r39300 30 30 #include "VBoxServiceInternal.h" 31 31 #include "VBoxServiceUtils.h" 32 #include "VBoxServiceControlExecThread.h"33 32 34 33 using namespace guestControl; … … 210 209 break; 211 210 } 212 213 if (RT_FAILURE(rc))214 VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc);215 211 } 216 212 … … 227 223 } 228 224 229 RTSemEventMultiDestroy(g_hControlEvent);230 g_hControlEvent = NIL_RTSEMEVENTMULTI;231 225 return rc; 232 226 } … … 371 365 372 366 if (RT_SUCCESS(rc)) 373 rc = VBoxServiceControl ExecThreadPerform(uPID, &ctrlRequest);367 rc = VBoxServiceControlThreadPerform(uPID, &ctrlRequest); 374 368 375 369 if (RT_SUCCESS(rc)) … … 378 372 *pcbRead = ctrlRequest.cbData; 379 373 } 374 else /* Something went wrong, nothing read. */ 375 *pcbRead = 0; 380 376 381 377 return rc; … … 409 405 ? VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF : VBOXSERVICECTRLREQUEST_STDIN_WRITE; 410 406 if (RT_SUCCESS(rc)) 411 rc = VBoxServiceControl ExecThreadPerform(uPID, &ctrlRequest);407 rc = VBoxServiceControlThreadPerform(uPID, &ctrlRequest); 412 408 413 409 if (RT_SUCCESS(rc)) … … 583 579 /** @todo Later, figure what to do if we're in RTProcWait(). It's a very 584 580 * annoying call since doesn't support timeouts in the posix world. */ 585 RTSemEventMultiSignal(g_hControlEvent); 581 if (g_hControlEvent != NIL_RTSEMEVENTMULTI) 582 RTSemEventMultiSignal(g_hControlEvent); 586 583 587 584 /* … … 591 588 if (g_GuestControlSvcClientID) 592 589 { 590 VBoxServiceVerbose(3, "Control: Cancelling pending waits ...\n"); 591 593 592 int rc = VbglR3GuestCtrlCancelPendingWaits(g_GuestControlSvcClientID); 594 593 if (RT_FAILURE(rc)) … … 602 601 VBoxServiceVerbose(3, "Control: Destroying threads ...\n"); 603 602 604 int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect); 605 if (RT_SUCCESS(rc)) 606 { 607 /* Signal all threads that we want to shutdown. */ 608 PVBOXSERVICECTRLTHREAD pThread; 609 RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node) 610 VBoxServiceControlThreadSignalShutdown(pThread); 611 612 /* Wait for threads to shutdown. */ 613 RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node) 614 { 615 int rc2 = VBoxServiceControlExecThreadShutdown(pThread); 616 if (RT_FAILURE(rc2)) 617 VBoxServiceError("Control: Guest process thread failed to stop; rc2=%Rrc\n", rc2); 618 } 619 620 /* Finally destroy thread list. */ 621 pThread = RTListGetFirst(&g_GuestControlThreads, VBOXSERVICECTRLTHREAD, Node); 622 while (pThread) 623 { 624 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node); 625 bool fLast = RTListNodeIsLast(&g_GuestControlThreads, &pThread->Node); 626 627 VBoxServiceControlRemoveThread(pThread); 628 VBoxServiceControlExecThreadDestroy(pThread); 629 630 if (fLast) 631 break; 632 633 pThread = pNext; 634 } 635 636 int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect); 637 if (RT_SUCCESS(rc)) 638 rc = rc2; 639 } 640 603 /* Signal all threads that we want to shutdown. */ 604 PVBOXSERVICECTRLTHREAD pThread; 605 RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node) 606 VBoxServiceControlThreadSignalShutdown(pThread); 607 608 /* Wait for threads to shutdown and destroy thread list. */ 609 pThread = RTListGetFirst(&g_GuestControlThreads, VBOXSERVICECTRLTHREAD, Node); 610 while (pThread) 611 { 612 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node); 613 bool fLast = RTListNodeIsLast(&g_GuestControlThreads, &pThread->Node); 614 615 int rc2 = VBoxServiceControlThreadWaitForShutdown(pThread, 616 30 * 1000 /* Wait 30 seconds max. */); 617 if (RT_FAILURE(rc2)) 618 VBoxServiceError("Control: Guest process thread failed to stop; rc=%Rrc\n", rc2); 619 620 if (fLast) 621 break; 622 623 pThread = pNext; 624 } 625 626 AssertMsg(RTListIsEmpty(&g_GuestControlThreads), 627 ("Guest process thread list still contains children when it should not\n")); 628 629 /* Destroy critical section. */ 641 630 RTCritSectDelete(&g_GuestControlThreadsCritSect); 642 631 } … … 661 650 662 651 652 /** 653 * Determines whether starting a new guest process according to the 654 * maximum number of concurrent guest processes defined is allowed or not. 655 * 656 * @return IPRT status code. 657 * @param pbAllowed True if starting (another) guest process 658 * is allowed, false if not. 659 */ 663 660 static int VBoxServiceControlStartAllowed(bool *pbAllowed) 664 661 { … … 721 718 const PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadByPID(uint32_t uPID) 722 719 { 723 PVBOXSERVICECTRLTHREAD p Node= NULL;720 PVBOXSERVICECTRLTHREAD pThread = NULL; 724 721 int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect); 725 722 if (RT_SUCCESS(rc)) 726 723 { 727 PVBOXSERVICECTRLTHREAD p NodeCur;728 RTListForEach(&g_GuestControlThreads, p NodeCur, VBOXSERVICECTRLTHREAD, Node)729 { 730 if (p NodeCur->uPID == uPID)724 PVBOXSERVICECTRLTHREAD pThreadCur; 725 RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node) 726 { 727 if (pThreadCur->uPID == uPID) 731 728 { 732 p Node = pNodeCur;729 pThread = pThreadCur; 733 730 break; 734 731 } … … 740 737 } 741 738 742 return pNode; 743 } 744 745 739 return pThread; 740 } 741 742 743 /** 744 * Removes the specified guest process thread from the global thread 745 * list. 746 * 747 * @return IPRT status code. 748 * @param pThread Thread to remove. 749 */ 746 750 void VBoxServiceControlRemoveThread(PVBOXSERVICECTRLTHREAD pThread) 747 751 { … … 752 756 if (RT_SUCCESS(rc)) 753 757 { 758 VBoxServiceVerbose(4, "ControlExec: Removing thread (PID: %u) from thread list\n", 759 pThread->uPID); 754 760 RTListNodeRemove(&pThread->Node); 755 761 756 762 int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect); 757 if (RT_SUCCESS(rc)) 758 rc = rc2; 763 AssertRC(rc2); 759 764 } 760 765 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.cpp
r39281 r39300 38 38 39 39 #include "VBoxServiceInternal.h" 40 #include "VBoxServiceControlExecThread.h"41 40 42 41 using namespace guestControl; 43 42 44 43 /* Internal functions. */ 45 static int vboxServiceControl ExecThreadAssignPID(PVBOXSERVICECTRLTHREAD pData, uint32_t uPID);46 static void vboxServiceControl ExecThreadFree(PVBOXSERVICECTRLTHREAD pData);47 static int vboxServiceControlThread WaitForShutdown(constPVBOXSERVICECTRLTHREAD pThread);44 static int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pData, uint32_t uPID); 45 static void vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pData); 46 static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread); 48 47 49 48 /** … … 84 83 85 84 pThread->uContextID = u32ContextID; 86 /* ClientID will be assigned when thread is started! */ 85 /* ClientID will be assigned when thread is started; every guest 86 * process has its own client ID to detect crashes on a per-guest-process 87 * level. */ 87 88 88 89 int rc = RTCritSectInit(&pThread->CritSect); … … 141 142 /* User management. */ 142 143 pThread->pszUser = RTStrDup(pszUser); 144 AssertPtr(pThread->pszUser); 143 145 pThread->pszPassword = RTStrDup(pszPassword); 146 AssertPtr(pThread->pszPassword); 144 147 } 145 148 146 149 if (RT_FAILURE(rc)) /* Clean up on failure. */ 147 vboxServiceControlExecThreadFree(pThread); 148 return rc; 149 } 150 151 152 /** 153 * TODO 154 * 155 * @param pThread 156 */ 157 void VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread) 158 { 159 AssertPtrReturnVoid(pThread); 150 vboxServiceControlThreadFree(pThread); 151 return rc; 152 } 153 154 155 /** 156 * Signals a guest process thread that we want it to shut down in 157 * a gentle way. 158 * 159 * @return IPRT status code. 160 * @param pThread Thread to shut down. 161 */ 162 int VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread) 163 { 164 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 160 165 161 166 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Signalling shutdown ...\n", 162 167 pThread->uPID); 163 168 164 /* First, set the shutdown flag. */165 ASMAtomicXchgBool(&pThread->fShutdown, true);169 /* Do *not* set pThread->fShutdown or other stuff here! 170 * The guest thread loop will do that as soon as it processes the quit message. */ 166 171 167 172 VBOXSERVICECTRLREQUEST ctrlRequest; … … 169 174 ctrlRequest.enmType = VBOXSERVICECTRLREQUEST_QUIT; 170 175 171 int rc = VBoxServiceControl ExecThreadPerform(pThread->uPID, &ctrlRequest);176 int rc = VBoxServiceControlThreadPerform(pThread->uPID, &ctrlRequest); 172 177 if (RT_FAILURE(rc)) 173 178 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Sending quit request failed with rc=%Rrc\n", 174 179 pThread->uPID, rc); 175 } 176 177 178 static int vboxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread) 180 return rc; 181 } 182 183 184 /** 185 * Wait for a guest process thread to shut down. 186 * 187 * @return IPRT status code. 188 * @param pThread Thread to wait shutting down for. 189 * @param RTMSINTERVAL Timeout in ms to wait for shutdown. 190 */ 191 int VBoxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread, 192 RTMSINTERVAL msTimeout) 179 193 { 180 194 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 181 195 int rc = VINF_SUCCESS; 182 196 if ( pThread->Thread != NIL_RTTHREAD 183 && !pThread->fShutdown) /* Only shutdown threads which aren't yet. */ 184 { 197 && !ASMAtomicReadBool(&pThread->fStopped)) /* Only shutdown threads which aren't yet. */ 198 { 199 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Waiting for shutdown ...\n", 200 pThread->uPID); 201 185 202 /* Wait a bit ... */ 186 rc = RTThreadWait(pThread->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL); 203 int rcThread; 204 rc = RTThreadWait(pThread->Thread, msTimeout, &rcThread); 205 if (RT_FAILURE(rcThread)) 206 { 207 VBoxServiceError("ControlExec: [PID %u]: Shutdown returned error rc=%Rrc\n", 208 pThread->uPID, rcThread); 209 if (RT_SUCCESS(rc)) 210 rc = rcThread; 211 } 187 212 } 188 213 return rc; … … 193 218 * Frees an allocated thread data structure along with all its allocated parameters. 194 219 * 195 * @param pThread Pointer to thread data to free. 196 */ 197 static void vboxServiceControlExecThreadFree(const PVBOXSERVICECTRLTHREAD pThread) 198 { 199 if (pThread) 200 { 201 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Freeing thread data ...\n", 202 pThread->uPID); 203 204 RTStrFree(pThread->pszCmd); 205 if (pThread->uNumEnvVars) 206 { 207 for (uint32_t i = 0; i < pThread->uNumEnvVars; i++) 208 RTStrFree(pThread->papszEnv[i]); 209 RTMemFree(pThread->papszEnv); 210 } 211 RTGetOptArgvFree(pThread->papszArgs); 212 RTStrFree(pThread->pszUser); 213 RTStrFree(pThread->pszPassword); 220 * @param pThread Pointer to thread data to free. 221 */ 222 static void vboxServiceControlThreadFree(const PVBOXSERVICECTRLTHREAD pThread) 223 { 224 if (!pThread) 225 return; 226 227 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Freeing thread data ...\n", 228 pThread->uPID); 229 230 RTStrFree(pThread->pszCmd); 231 if (pThread->uNumEnvVars) 232 { 233 for (uint32_t i = 0; i < pThread->uNumEnvVars; i++) 234 RTStrFree(pThread->papszEnv[i]); 235 RTMemFree(pThread->papszEnv); 236 } 237 RTGetOptArgvFree(pThread->papszArgs); 238 RTStrFree(pThread->pszUser); 239 RTStrFree(pThread->pszPassword); 240 241 if (pThread->RequestEvent != NIL_RTSEMEVENTMULTI) 242 { 243 int rc2 = RTSemEventMultiDestroy(pThread->RequestEvent); 244 AssertRC(rc2); 214 245 } 215 246 } … … 223 254 * @param phStdInW The standard input pipe handle. 224 255 */ 225 static int VBoxServiceControl ExecProcCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW)256 static int VBoxServiceControlThreadCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW) 226 257 { 227 258 int rc = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN); … … 245 276 * @param phStdInW The standard input pipe handle. 246 277 */ 247 static int VBoxServiceControl ExecProcHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW)278 static int VBoxServiceControlThreadHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW) 248 279 { 249 280 NOREF(fPollEvt); 250 281 251 return VBoxServiceControl ExecProcCloseStdIn(hPollSet, phStdInW);282 return VBoxServiceControlThreadCloseStdIn(hPollSet, phStdInW); 252 283 } 253 284 … … 263 294 * 264 295 */ 265 static int VBoxServiceControl ExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt,266 296 static int VBoxServiceControlThreadHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, 297 PRTPIPE phPipeR, uint32_t idPollHnd) 267 298 { 268 299 int rc = VINF_SUCCESS; … … 306 337 307 338 308 int VBoxServiceControlExecProcHandleIPCNotify(RTPOLLSET hPollSet, uint32_t fPollEvt, 309 PRTPIPE phNotificationPipeR) 310 { 311 #ifdef DEBUG_andy 312 VBoxServiceVerbose(4, "ControlExec: HandleIPCNotify\n"); 313 #endif 314 /* Drain the notification pipe. */ 315 uint8_t abBuf[8]; 316 size_t cbIgnore; 317 int rc = RTPipeRead(*phNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore); 318 if (RT_FAILURE(rc)) 319 VBoxServiceError("ControlExec: Draining IPC notification pipe failed with rc=%Rrc\n", rc); 320 return rc; 321 } 322 323 324 static int VBoxServiceControlExecHandleIPCRequest(RTPOLLSET hPollSet, uint32_t fPollEvt, 325 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR, 326 PVBOXSERVICECTRLREQUEST pRequest) 339 static int VBoxServiceControlThreadHandleIPCRequest(RTPOLLSET hPollSet, uint32_t fPollEvt, 340 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR, 341 PVBOXSERVICECTRLTHREAD pThread) 327 342 { 328 343 #ifdef DEBUG_andy … … 330 345 #endif 331 346 347 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 332 348 AssertPtrReturn(phStdInW, VERR_INVALID_POINTER); 333 349 AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER); 334 350 AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER); 335 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); 336 337 int rc = VINF_SUCCESS; 338 int rcReq = VINF_SUCCESS; /* Actual request result. */ 339 340 switch (pRequest->enmType) 341 { 342 case VBOXSERVICECTRLREQUEST_QUIT: /* Main control asked us to quit. */ 343 /** @todo Check for some conditions to check to 344 * veto quitting. */ 345 pRequest->rc = VINF_SUCCESS; 346 break; 347 348 case VBOXSERVICECTRLREQUEST_STDIN_WRITE: 349 /* Fall through is intentional. */ 350 case VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF: 351 { 352 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER); 353 AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER); 354 355 size_t cbWritten = 0; 356 if (*phStdInW != NIL_RTPIPE) 351 352 int rc = RTCritSectEnter(&pThread->CritSect); 353 if (RT_SUCCESS(rc)) 354 { 355 /* Drain the notification pipe. */ 356 uint8_t abBuf[8]; 357 size_t cbIgnore; 358 int rc = RTPipeRead(pThread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore); 359 if (RT_FAILURE(rc)) 360 VBoxServiceError("ControlExec: Draining IPC notification pipe failed with rc=%Rrc\n", rc); 361 362 int rcReq = VINF_SUCCESS; /* Actual request result. */ 363 364 PVBOXSERVICECTRLREQUEST pRequest = pThread->pRequest; 365 AssertPtr(pRequest); 366 367 switch (pRequest->enmType) 368 { 369 case VBOXSERVICECTRLREQUEST_QUIT: /* Main control asked us to quit. */ 357 370 { 358 rcReq = RTPipeWrite(*phStdInW, 359 pRequest->pvData, pRequest->cbData, &cbWritten); 371 /** @todo Check for some conditions to check to 372 * veto quitting. */ 373 pThread->fShutdown = true; 374 rcReq = VINF_SUCCESS; 375 break; 360 376 } 361 else 362 rcReq = VINF_EOF; 363 364 /* If this is the last write we need to close the stdin pipe on our 365 * end and remove it from the poll set. */ 366 if (VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF == pRequest->enmType) 367 rc = VBoxServiceControlExecProcCloseStdIn(hPollSet, phStdInW); 368 369 /* Reqport back actual data written (if any). */ 370 pRequest->cbData = cbWritten; 371 break; 372 } 373 374 case VBOXSERVICECTRLREQUEST_STDOUT_READ: 375 /* Fall through is intentional. */ 376 case VBOXSERVICECTRLREQUEST_STDERR_READ: 377 { 378 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER); 379 AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER); 380 381 PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ 382 ? phStdErrR : phStdOutR; 383 AssertPtr(pPipeR); 384 385 size_t cbRead = 0; 386 if (*pPipeR != NIL_RTPIPE) 377 378 case VBOXSERVICECTRLREQUEST_STDIN_WRITE: 379 /* Fall through is intentional. */ 380 case VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF: 387 381 { 388 rcReq = RTPipeRead(*pPipeR, 389 pRequest->pvData, pRequest->cbData, &cbRead); 390 if (rcReq == VERR_BROKEN_PIPE) 382 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER); 383 AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER); 384 385 size_t cbWritten = 0; 386 if (*phStdInW != NIL_RTPIPE) 387 { 388 rcReq = RTPipeWrite(*phStdInW, 389 pRequest->pvData, pRequest->cbData, &cbWritten); 390 } 391 else 391 392 rcReq = VINF_EOF; 393 394 /* If this is the last write we need to close the stdin pipe on our 395 * end and remove it from the poll set. */ 396 if (VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF == pRequest->enmType) 397 rc = VBoxServiceControlThreadCloseStdIn(hPollSet, phStdInW); 398 399 /* Reqport back actual data written (if any). */ 400 pRequest->cbData = cbWritten; 401 break; 392 402 } 393 else 394 rcReq = VINF_EOF; 395 396 /* Report back actual data read (if any). */ 397 pRequest->cbData = cbRead; 398 break; 399 } 400 401 default: 402 rcReq = VERR_INVALID_PARAMETER; 403 break; 404 } 405 406 pRequest->rc = RT_SUCCESS(rc) 407 ? rcReq : rc; 408 409 VBoxServiceVerbose(4, "ControlExec: Handled IPC request with rcReq=%Rrc, enmType=%u, cbData=%u\n", 410 rcReq, pRequest->enmType, pRequest->cbData); 403 404 case VBOXSERVICECTRLREQUEST_STDOUT_READ: 405 /* Fall through is intentional. */ 406 case VBOXSERVICECTRLREQUEST_STDERR_READ: 407 { 408 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER); 409 AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER); 410 411 PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ 412 ? phStdErrR : phStdOutR; 413 AssertPtr(pPipeR); 414 415 size_t cbRead = 0; 416 if (*pPipeR != NIL_RTPIPE) 417 { 418 rcReq = RTPipeRead(*pPipeR, 419 pRequest->pvData, pRequest->cbData, &cbRead); 420 if (rcReq == VERR_BROKEN_PIPE) 421 rcReq = VINF_EOF; 422 } 423 else 424 rcReq = VINF_EOF; 425 426 /* Report back actual data read (if any). */ 427 pRequest->cbData = cbRead; 428 break; 429 } 430 431 default: 432 rcReq = VERR_NOT_IMPLEMENTED; 433 break; 434 } 435 436 /* Assign overall result. */ 437 pRequest->rc = RT_SUCCESS(rc) 438 ? rcReq : rc; 439 440 VBoxServiceVerbose(4, "ControlExec: Handled IPC request with rcReq=%Rrc, enmType=%u, cbData=%u\n", 441 rcReq, pRequest->enmType, pRequest->cbData); 442 443 /* In any case, regardless of the result, we notify 444 * the main guest control to unblock it. */ 445 int rc2 = RTSemEventMultiSignal(pThread->RequestEvent); 446 AssertRC(rc2); 447 /* No access to pRequest here anymore -- could be out of scope 448 * or modified already! */ 449 450 rc2 = RTCritSectLeave(&pThread->CritSect); 451 AssertRC(rc2); 452 } 453 411 454 return rc; 412 455 } … … 426 469 * @param hStdErrR Handle to the process' stderr read end. 427 470 */ 428 static int VBoxServiceControl ExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,429 RTPROCESS hProcess, RTMSINTERVAL cMsTimeout, RTPOLLSET hPollSet,430 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)471 static int VBoxServiceControlThreadProcLoop(PVBOXSERVICECTRLTHREAD pThread, 472 RTPROCESS hProcess, RTMSINTERVAL cMsTimeout, RTPOLLSET hPollSet, 473 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR) 431 474 { 432 475 AssertPtrReturn(pThread, VERR_INVALID_POINTER); … … 452 495 * the first (stale) entry will be found and we get really weird results! 453 496 */ 454 rc = vboxServiceControl ExecThreadAssignPID(pThread, hProcess);497 rc = vboxServiceControlThreadAssignPID(pThread, hProcess); 455 498 if (RT_FAILURE(rc)) 456 499 { … … 493 536 { 494 537 case VBOXSERVICECTRLPIPEID_STDIN: 495 rc = VBoxServiceControl ExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW);538 rc = VBoxServiceControlThreadHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW); 496 539 break; 497 540 498 541 case VBOXSERVICECTRLPIPEID_STDOUT: 499 rc = VBoxServiceControl ExecProcHandleOutputEvent(hPollSet, fPollEvt,500 542 rc = VBoxServiceControlThreadHandleOutputEvent(hPollSet, fPollEvt, 543 phStdOutR, idPollHnd); 501 544 break; 502 545 503 546 case VBOXSERVICECTRLPIPEID_STDERR: 504 rc = VBoxServiceControl ExecProcHandleOutputEvent(hPollSet, fPollEvt,505 547 rc = VBoxServiceControlThreadHandleOutputEvent(hPollSet, fPollEvt, 548 phStdErrR, idPollHnd); 506 549 break; 507 550 508 551 case VBOXSERVICECTRLPIPEID_IPC_NOTIFY: 509 rc = VBoxServiceControlExecProcHandleIPCNotify(hPollSet, fPollEvt, 510 &pThread->hNotificationPipeR); 511 /* Fall through is intentional. */ 512 default: 513 /* Handle IPC requests. */ 514 if (RT_SUCCESS(rc)) 515 { 516 rc = VBoxServiceControlExecHandleIPCRequest(hPollSet, fPollEvt, 517 phStdInW, phStdOutR, phStdErrR, 518 pThread->pRequest); 519 } 520 521 /* If we were asked to terminate do so ... */ 522 if (pThread->pRequest->enmType == VBOXSERVICECTRLREQUEST_QUIT) 523 rc = VINF_EOF; 524 525 /* In any case, regardless of the result, we notify 526 * the main guest control to unblock it. */ 527 rc2 = RTSemEventMultiSignal(pThread->RequestEvent); 528 AssertRC(rc2); 529 /* No access to pRequest here anymore -- could be out of scope 530 * or modified already! */ 552 rc = VBoxServiceControlThreadHandleIPCRequest(hPollSet, fPollEvt, 553 phStdInW,phStdOutR,phStdErrR, pThread); 531 554 break; 532 555 } 556 533 557 if (RT_FAILURE(rc) || rc == VINF_EOF) 534 558 break; /* Abort command, or client dead or something. */ 535 559 536 /* Only notification pipe left? Then there's nothing to poll for anymore really. 537 * Bail out .. */ 560 if (RT_UNLIKELY(pThread->fShutdown)) 561 break; /* We were asked to shutdown. */ 562 563 /* Do we have more to poll for (e.g. is there (still) something in our pollset 564 * like stdout, stderr or stdin)? If we only have our notification pipe left we 565 * need to bail out. */ 538 566 if (RTPollSetGetCount(hPollSet) > 1) 539 567 continue; … … 655 683 if (RT_SUCCESS(rc)) 656 684 { 657 /* Mark this thread as stopped and do some action required for stopping ... */658 //VBoxServiceControlExecThreadCleanup(pThread);659 660 685 uint32_t uStatus = PROC_STS_UNDEFINED; 661 686 uint32_t uFlags = 0; … … 718 743 pThread->uPID, ProcessStatus.enmReason); 719 744 745 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Sending final status, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n", 746 pThread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags); 720 747 rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, 721 748 pThread->uPID, uStatus, uFlags, … … 724 751 VBoxServiceError("ControlExec: [PID %u]: Error reporting final status to host; rc=%Rrc\n", 725 752 pThread->uPID, rc); 726 727 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Ended, CID=%u, Status=%u, Flags=%u\n",728 pThread->uPID, pThread->uContextID, uStatus, uFlags);729 753 730 754 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Process loop ended with rc=%Rrc\n", … … 751 775 * should service. Always set. 752 776 */ 753 static int VBoxServiceControl ExecSetupPipe(int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)777 static int VBoxServiceControlThreadSetupPipe(int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe) 754 778 { 755 779 AssertPtrReturn(ph, VERR_INVALID_PARAMETER); … … 798 822 * @param cbExpanded Size (in bytes) of string to store the resolved path. 799 823 */ 800 static int VBoxServiceControl ExecMakeFullPath(const char *pszPath, char *pszExpanded, size_t cbExpanded)824 static int VBoxServiceControlThreadMakeFullPath(const char *pszPath, char *pszExpanded, size_t cbExpanded) 801 825 { 802 826 int rc = VINF_SUCCESS; … … 825 849 * @param cbResolved Size (in bytes) of resolved file name string. 826 850 */ 827 static int VBoxServiceControl ExecResolveExecutable(const char *pszFileName, char *pszResolved, size_t cbResolved)851 static int VBoxServiceControlThreadResolveExecutable(const char *pszFileName, char *pszResolved, size_t cbResolved) 828 852 { 829 853 int rc = VINF_SUCCESS; … … 844 868 AssertPtr(pszExecResolved); 845 869 846 rc = VBoxServiceControl ExecMakeFullPath(pszExecResolved, pszResolved, cbResolved);870 rc = VBoxServiceControlThreadMakeFullPath(pszExecResolved, pszResolved, cbResolved); 847 871 #ifdef DEBUG 848 872 VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecResolveExecutable: %s -> %s\n", … … 865 889 * Needs to be freed with RTGetOptArgvFree. 866 890 */ 867 static int VBoxServiceControl ExecPrepareArgv(const char *pszArgv0,868 const char * const *papszArgs, char ***ppapszArgv)891 static int VBoxServiceControlThreadPrepareArgv(const char *pszArgv0, 892 const char * const *papszArgs, char ***ppapszArgv) 869 893 { 870 894 /** @todo RTGetOptArgvToString converts to MSC quoted string, while … … 920 944 * successful process start. 921 945 */ 922 static int VBoxServiceControl ExecCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,923 PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,924 const char *pszPassword, PRTPROCESS phProcess)946 static int VBoxServiceControlThreadCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, 947 PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser, 948 const char *pszPassword, PRTPROCESS phProcess) 925 949 { 926 950 AssertPtrReturn(pszExec, VERR_INVALID_PARAMETER); … … 960 984 { 961 985 char **papszArgsExp; 962 rc = VBoxServiceControl ExecPrepareArgv(szSysprepCmd /* argv0 */, papszArgs, &papszArgsExp);986 rc = VBoxServiceControlThreadPrepareArgv(szSysprepCmd /* argv0 */, papszArgs, &papszArgsExp); 963 987 if (RT_SUCCESS(rc)) 964 988 { … … 978 1002 /* We want to use the internal toolbox (all internal 979 1003 * tools are starting with "vbox_" (e.g. "vbox_cat"). */ 980 rc = VBoxServiceControl ExecResolveExecutable(VBOXSERVICE_NAME, szExecExp, sizeof(szExecExp));1004 rc = VBoxServiceControlThreadResolveExecutable(VBOXSERVICE_NAME, szExecExp, sizeof(szExecExp)); 981 1005 } 982 1006 else … … 986 1010 * Do the environment variables expansion on executable and arguments. 987 1011 */ 988 rc = VBoxServiceControl ExecResolveExecutable(pszExec, szExecExp, sizeof(szExecExp));1012 rc = VBoxServiceControlThreadResolveExecutable(pszExec, szExecExp, sizeof(szExecExp)); 989 1013 #ifdef VBOXSERVICE_TOOLBOX 990 1014 } … … 993 1017 { 994 1018 char **papszArgsExp; 995 rc = VBoxServiceControl ExecPrepareArgv(pszExec /* Always use the unmodified executable name as argv0. */,996 papszArgs /* Append the rest of the argument vector (if any). */, &papszArgsExp);1019 rc = VBoxServiceControlThreadPrepareArgv(pszExec /* Always use the unmodified executable name as argv0. */, 1020 papszArgs /* Append the rest of the argument vector (if any). */, &papszArgsExp); 997 1021 if (RT_SUCCESS(rc)) 998 1022 { … … 1039 1063 * @param PVBOXSERVICECTRLTHREAD Thread data associated with a started process. 1040 1064 */ 1041 static DECLCALLBACK(int) VBoxServiceControl ExecProcessWorker(PVBOXSERVICECTRLTHREAD pThread)1065 static DECLCALLBACK(int) VBoxServiceControlThreadProcessWorker(PVBOXSERVICECTRLTHREAD pThread) 1042 1066 { 1043 1067 AssertPtrReturn(pThread, VERR_INVALID_POINTER); … … 1051 1075 return rc; 1052 1076 } 1077 VBoxServiceVerbose(3, "ControlExec: Guest process \"%s\" got client ID=%u\n", 1078 pThread->pszCmd, pThread->uClientID); 1053 1079 1054 1080 bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */ … … 1076 1102 RTHANDLE hStdIn; 1077 1103 PRTHANDLE phStdIn; 1078 rc = VBoxServiceControl ExecSetupPipe(0 /*STDIN_FILENO*/, &hStdIn, &phStdIn, &pThread->pipeStdInW);1104 rc = VBoxServiceControlThreadSetupPipe(0 /*STDIN_FILENO*/, &hStdIn, &phStdIn, &pThread->pipeStdInW); 1079 1105 if (RT_SUCCESS(rc)) 1080 1106 { … … 1082 1108 PRTHANDLE phStdOut; 1083 1109 RTPIPE hStdOutR; 1084 rc = VBoxServiceControl ExecSetupPipe(1 /*STDOUT_FILENO*/, &hStdOut, &phStdOut, &hStdOutR);1110 rc = VBoxServiceControlThreadSetupPipe(1 /*STDOUT_FILENO*/, &hStdOut, &phStdOut, &hStdOutR); 1085 1111 if (RT_SUCCESS(rc)) 1086 1112 { … … 1088 1114 PRTHANDLE phStdErr; 1089 1115 RTPIPE hStdErrR; 1090 rc = VBoxServiceControl ExecSetupPipe(2 /*STDERR_FILENO*/, &hStdErr, &phStdErr, &hStdErrR);1116 rc = VBoxServiceControlThreadSetupPipe(2 /*STDERR_FILENO*/, &hStdErr, &phStdErr, &hStdErrR); 1091 1117 if (RT_SUCCESS(rc)) 1092 1118 { … … 1117 1143 { 1118 1144 RTPROCESS hProcess; 1119 rc = VBoxServiceControl ExecCreateProcess(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,1120 phStdIn, phStdOut, phStdErr,1121 pThread->pszUser, pThread->pszPassword,1122 &hProcess);1145 rc = VBoxServiceControlThreadCreateProcess(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags, 1146 phStdIn, phStdOut, phStdErr, 1147 pThread->pszUser, pThread->pszPassword, 1148 &hProcess); 1123 1149 if (RT_FAILURE(rc)) 1124 1150 VBoxServiceError("ControlExec: Error starting process, rc=%Rrc\n", rc); … … 1147 1173 1148 1174 /* Enter the process loop. */ 1149 rc = VBoxServiceControlExecProcLoop(pThread, 1150 hProcess, pThread->uTimeLimitMS, hPollSet, 1151 &pThread->pipeStdInW, &hStdOutR, &hStdErrR); 1152 1153 /* Before cleaning up everything else, remove the thread from our thread list. */ 1175 rc = VBoxServiceControlThreadProcLoop(pThread, 1176 hProcess, pThread->uTimeLimitMS, hPollSet, 1177 &pThread->pipeStdInW, &hStdOutR, &hStdErrR); 1178 1179 /* 1180 * Remove thread from global thread list. After this it's safe to shutdown 1181 * and deallocate this thread. 1182 */ 1154 1183 VBoxServiceControlRemoveThread(pThread); 1155 1184 … … 1207 1236 } 1208 1237 1238 if (pThread->uClientID) 1239 { 1240 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Cancelling pending waits (client ID=%u)\n", 1241 pThread->uPID, pThread->uClientID); 1242 int rc2 = VbglR3GuestCtrlCancelPendingWaits(pThread->uClientID); 1243 if (RT_FAILURE(rc2)) 1244 { 1245 VBoxServiceError("ControlExec: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n", 1246 pThread->uPID, rc2); 1247 if (RT_SUCCESS(rc)) 1248 rc = rc2; 1249 } 1250 1251 /* Disconnect from guest control service. */ 1252 VbglR3GuestCtrlDisconnect(pThread->uClientID); 1253 pThread->uClientID = 0; 1254 } 1255 1209 1256 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n", 1210 1257 pThread->uPID, pThread->pszCmd, rc); 1211 1258 1212 /* Disconnect from guest control service. */1213 VbglR3GuestCtrlDisconnect(pThread->uClientID);1214 pThread->uClientID = 0;1215 1216 1259 ASMAtomicXchgBool(&pThread->fStarted, false); 1217 ASMAtomicXchgBool(&pThread->fStopped, true);1218 1219 int rc2 = VBoxServiceControlExecThreadShutdown(pThread);1220 if (RT_SUCCESS(rc2))1221 VBoxServiceControlExecThreadDestroy(pThread);1222 1260 1223 1261 /* … … 1228 1266 RTThreadUserSignal(RTThreadSelf()); 1229 1267 1268 int rc2 = vboxServiceControlThreadShutdown(pThread); 1269 if (RT_SUCCESS(rc)) 1270 rc = rc2; 1271 1230 1272 return rc; 1231 1273 } … … 1240 1282 * 1241 1283 */ 1242 static DECLCALLBACK(int) VBoxServiceControl ExecThread(RTTHREAD ThreadSelf, void *pvUser)1284 static DECLCALLBACK(int) VBoxServiceControlThread(RTTHREAD ThreadSelf, void *pvUser) 1243 1285 { 1244 1286 PVBOXSERVICECTRLTHREAD pThread = (VBOXSERVICECTRLTHREAD*)pvUser; 1245 1287 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1246 return VBoxServiceControl ExecProcessWorker(pThread);1288 return VBoxServiceControlThreadProcessWorker(pThread); 1247 1289 } 1248 1290 … … 1299 1341 AssertMsgFailed(("Unable to create unique control exec thread name!\n")); 1300 1342 1301 rc = RTThreadCreate(&pThread->Thread, VBoxServiceControl ExecThread,1343 rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlThread, 1302 1344 (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0, 1303 1345 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName); … … 1313 1355 /* Wait for the thread to initialize. */ 1314 1356 RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */); 1315 if ( pThread->fShutdown)1357 if (ASMAtomicReadBool(&pThread->fShutdown)) 1316 1358 { 1317 1359 VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd); … … 1343 1385 * @param uPID PID to assign to the specified guest control execution thread. 1344 1386 */ 1345 int vboxServiceControl ExecThreadAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)1387 int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID) 1346 1388 { 1347 1389 AssertPtrReturn(pThread, VERR_INVALID_POINTER); … … 1360 1402 VBoxServiceVerbose(3, "ControlExec: PID %u was used before, shutting down stale exec thread ...\n", 1361 1403 uPID); 1362 rc = VBoxServiceControlExecThreadShutdown(pOldThread);1404 rc = vboxServiceControlThreadShutdown(pOldThread); 1363 1405 if (RT_FAILURE(rc)) 1364 1406 { … … 1376 1418 1377 1419 /** 1378 * TODO 1420 * Performs a request to a specific (formerly started) guest process and waits 1421 * for its response. 1379 1422 * 1380 1423 * @return IPRT status code. 1381 * @return int 1382 * @param uPID 1383 * @param pRequest 1384 */ 1385 int VBoxServiceControlExecThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest) 1424 * @param uPID PID of guest process to perform a request to. 1425 * @param pRequest Pointer to request to perform. 1426 */ 1427 int VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest) 1386 1428 { 1387 1429 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); … … 1389 1431 /* Rest in pRequest is optional (based on the request type). */ 1390 1432 1391 VBoxServiceVerbose(4, "ControlExec: [PID %u]: PerformingenmType=%u, pvData=0x%p, cbData=%u ...\n",1433 VBoxServiceVerbose(4, "ControlExec: Performing PID=%u, enmType=%u, pvData=0x%p, cbData=%u ...\n", 1392 1434 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1393 1435 1394 1436 int rc; 1395 1437 const PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlGetThreadByPID(uPID); 1396 if (pThread) 1438 if ( pThread 1439 && !ASMAtomicReadBool(&pThread->fStopped)) 1397 1440 { 1398 1441 rc = RTCritSectEnter(&pThread->CritSect); … … 1402 1445 pThread->pRequest = pRequest; 1403 1446 1404 /** @todo To speed up simultaneous guest process handling we could add a worker threads in order1405 * to wait for the request to happen. Later. */1447 /** @todo To speed up simultaneous guest process handling we could add a worker threads 1448 * or queue in order to wait for the request to happen. Later. */ 1406 1449 1407 1450 /* Wake up guest thrad by sending a wakeup byte to the notification pipe so … … 1412 1455 if (RT_SUCCESS(rc)) 1413 1456 rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten); 1457 1458 /* Make sure we leave the critical section before doing the wait. */ 1459 int rc2 = RTCritSectLeave(&pThread->CritSect); 1460 AssertRCReturn(rc2, rc2); 1461 1414 1462 if (RT_SUCCESS(rc) && cbWritten) 1415 1463 { 1464 VBoxServiceVerbose(4, "ControlExec: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n", 1465 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1416 1466 /* Wait on the request to get completed (or we are asked to abort/shutdown). */ 1417 1467 rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT); … … 1421 1471 uPID, pRequest->rc, pRequest->cbData); 1422 1472 1423 /* Give back overall request result. */ 1424 rc = pRequest->rc; 1425 1426 /* Reset the semaphore. */ 1427 int rc2 = RTSemEventMultiReset(pThread->RequestEvent); 1428 if (RT_FAILURE(rc2)) 1429 VBoxServiceError("ControlExec: Unable to reset request event, rc=%Rrc\n", rc2); 1473 rc = RTCritSectEnter(&pThread->CritSect); 1474 if (RT_SUCCESS(rc)) 1475 { 1476 /* Give back overall request result. */ 1477 rc = pRequest->rc; 1478 1479 /* Reset the semaphore. */ 1480 rc2 = RTSemEventMultiReset(pThread->RequestEvent); 1481 if (RT_FAILURE(rc2)) 1482 VBoxServiceError("ControlExec: Unable to reset request event, rc=%Rrc\n", rc2); 1483 1484 rc2 = RTCritSectLeave(&pThread->CritSect); 1485 AssertRCReturn(rc2, rc2); 1486 } 1430 1487 } 1431 1488 } 1432 1433 int rc2 = RTCritSectLeave(&pThread->CritSect);1434 AssertRCReturn(rc2, rc2);1435 1489 } 1436 1490 } … … 1438 1492 rc = VERR_NOT_FOUND; 1439 1493 1440 VBoxServiceVerbose(4, "ControlExec: [PID %u]: PerformedenmType=%u, pvData=0x%p, cbData=%u with rc=%Rrc\n",1494 VBoxServiceVerbose(4, "ControlExec: Performed PID=%u, enmType=%u, pvData=0x%p, cbData=%u with rc=%Rrc\n", 1441 1495 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData, rc); 1442 1496 return rc; … … 1445 1499 1446 1500 /** 1447 * Removes the guest thread from the global guest thread list and finally 1448 * destroys it. Does not do locking, must be done by the caller! 1449 * 1450 * @param pThread Thread to destroy. 1451 */ 1452 void VBoxServiceControlExecThreadDestroy(PVBOXSERVICECTRLTHREAD pThread) 1453 { 1454 if (!pThread) 1455 return; 1456 1501 * Shuts down a guest thread. 1502 * 1503 * @return IPRT status code. 1504 * @param pThread Thread to shut down. 1505 */ 1506 static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread) 1507 { 1508 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1509 1510 int rc = RTCritSectEnter(&pThread->CritSect); 1511 if (RT_SUCCESS(rc)) 1512 { 1513 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Shutting down ...\n", 1514 pThread->uPID); 1515 1516 /* 1517 * Destroy thread-specific data. 1518 */ 1519 vboxServiceControlThreadFree(pThread); 1520 1521 /* Set stopped status. */ 1522 ASMAtomicXchgBool(&pThread->fStopped, true); 1523 1524 rc = RTCritSectLeave(&pThread->CritSect); 1525 } 1526 1527 /* 1528 * Destroy other thread data. 1529 */ 1457 1530 if (RTCritSectIsInitialized(&pThread->CritSect)) 1458 1531 RTCritSectDelete(&pThread->CritSect); 1459 1532 1460 /* Destroy thread structure as final step. */ 1533 /* 1534 * Destroy thread structure as final step. 1535 */ 1461 1536 RTMemFree(pThread); 1462 1537 pThread = NULL; 1463 } 1464 1465 1466 /** 1467 * Shuts down a guest thread. 1468 * Does not do locking, must be done by the caller! 1469 * 1470 * @return IPRT status code. 1471 * @param pThread Thread to shut down. 1472 */ 1473 int VBoxServiceControlExecThreadShutdown(PVBOXSERVICECTRLTHREAD pThread) 1474 { 1475 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1476 1477 if (ASMAtomicReadBool(&pThread->fShutdown)) /* Already shut down. */ 1478 return VINF_SUCCESS; 1479 1480 /* First, signal shut down. */ 1481 VBoxServiceControlThreadSignalShutdown(pThread); 1482 1483 /* 1484 * Wait for thread to shutdown. 1485 */ 1486 VBoxServiceVerbose(2, "ControlExec: [PID %u]: Waitng for shutting down ...\n", 1487 pThread->uPID); 1488 int rc; 1489 for (int i = 0; i < 3; i++) 1490 { 1491 rc = vboxServiceControlThreadWaitForShutdown(pThread); 1492 if (RT_SUCCESS(rc)) 1493 break; 1494 1495 VBoxServiceError("ControlExec: [PID %u]: Attempt #%d: Waiting for shutdown failed with rc=%Rrc ...\n", 1496 pThread->uPID, i + 1, rc); 1497 RTThreadSleep(500); /* Wait a bit before next try. */ 1498 } 1499 1500 /* Do not destroy critical section here! */ 1501 1502 /* 1503 * Destroy thread-specific data. 1504 */ 1505 vboxServiceControlExecThreadFree(pThread); 1506 1507 return rc; 1508 } 1509 1538 1539 return rc; 1540 } 1541 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
r39281 r39300 143 143 * marks the end of input. */ 144 144 VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF = 71, 145 /** Kill process.145 /** Kill/terminate process. 146 146 * @todo Implement this! */ 147 147 VBOXSERVICECTRLREQUEST_KILL = 90, 148 148 /** Gently ask process to terminate. 149 149 * @todo Implement this! */ 150 VBOXSERVICECTRLREQUEST_HANGUP = 91 150 VBOXSERVICECTRLREQUEST_HANGUP = 91, 151 /** Ask the process in which status it 152 * currently is. 153 * @todo Implement this! */ 154 VBOXSERVICECTRLREQUEST_STATUS = 100 151 155 } VBOXSERVICECTRLREQUESTTYPE; 152 156 … … 161 165 /** The request type to handle. */ 162 166 VBOXSERVICECTRLREQUESTTYPE enmType; 163 /** On input, this contains the (maximum) amount164 * of buffered data to read or write. On output,167 /** Payload size; on input, this contains the (maximum) amount 168 * of data the caller wants to write or to read. On output, 165 169 * this show the actual amount of data read/written. */ 166 170 size_t cbData; 167 /** The provided,allocated data buffer for input/output. */171 /** Payload data; a pre-allocated data buffer for input/output. */ 168 172 void *pvData; 169 173 /** The overall result of the operation. */ … … 334 338 const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS, 335 339 PRTLISTNODE *ppNode); 336 extern void VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread); 340 int VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest); 341 extern int VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread); 342 extern int VBoxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread, RTMSINTERVAL msTimeout); 337 343 #endif /* VBOX_WITH_GUEST_CONTROL */ 338 344
Note:
See TracChangeset
for help on using the changeset viewer.