Changeset 38180 in vbox
- Timestamp:
- Jul 26, 2011 12:26:34 PM (13 years ago)
- Location:
- trunk/src/VBox/Additions/common/VBoxService
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
r38157 r38180 521 521 if (RT_SUCCESS(rc)) 522 522 { 523 VBoxServicePipeBufSetStatus(&pData->stdIn, false /* Disabled */); 524 VBoxServicePipeBufSetStatus(&pData->stdOut, false /* Disabled */); 525 VBoxServicePipeBufSetStatus(&pData->stdErr, false /* Disabled */); 526 527 /* Since the process is not alive anymore, destroy its local 528 * stdin pipe buffer - it's not used anymore and can eat up quite 529 * a bit of memory. */ 530 VBoxServicePipeBufDestroy(&pData->stdIn); 523 /* Mark this thread as stopped and do some action required for stopping ... */ 524 VBoxServiceControlExecThreadStop(pThread); 531 525 532 526 uint32_t uStatus = PROC_STS_UNDEFINED; … … 1117 1111 * 1118 1112 * @return IPRT status code. 1113 * @param uClientID Client ID for accessing host service. 1119 1114 * @param uContextID Context ID to associate the process to start with. 1120 1115 * @param pszCmd Full qualified path of process to start (without arguments). … … 1130 1125 * @param uTimeLimitMS Time limit (in ms) of the process' life time. 1131 1126 */ 1132 int VBoxServiceControlExecProcess(uint32_t uContextID, const char *pszCmd, uint32_t uFlags, 1127 int VBoxServiceControlExecProcess(uint32_t uClientID, uint32_t uContextID, 1128 const char *pszCmd, uint32_t uFlags, 1133 1129 const char *pszArgs, uint32_t uNumArgs, 1134 1130 const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars, 1135 1131 const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS) 1136 1132 { 1137 int rc = VBoxServiceControlExecThreadsApplyPolicies(); 1133 bool fAllowed = false; 1134 int rc = VBoxServiceControlExecThreadStartAllowed(&fAllowed); 1138 1135 if (RT_FAILURE(rc)) 1139 return rc; 1140 1141 /* 1142 * Allocate new thread data and assign it to our thread list. 1143 */ 1144 PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD)); 1145 if (pThread) 1146 { 1147 rc = VBoxServiceControlExecThreadAlloc(pThread, 1148 uContextID, 1149 pszCmd, uFlags, 1150 pszArgs, uNumArgs, 1151 pszEnv, cbEnv, uNumEnvVars, 1152 pszUser, pszPassword, 1153 uTimeLimitMS); 1154 if (RT_SUCCESS(rc)) 1155 { 1156 static uint32_t uCtrlExecThread = 0; 1157 char szThreadName[32]; 1158 if (!RTStrPrintf(szThreadName, sizeof(szThreadName), "controlexec%ld", uCtrlExecThread++)) 1159 AssertMsgFailed(("Unable to create unique control exec thread name!\n")); 1160 1161 rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread, 1162 (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0, 1163 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName); 1164 if (RT_FAILURE(rc)) 1136 VBoxServiceError("ControlExec: Error determining whether process can be started or not, rc=%Rrc\n", rc); 1137 1138 if (fAllowed) 1139 { 1140 /* 1141 * Allocate new thread data and assign it to our thread list. 1142 */ 1143 PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD)); 1144 if (pThread) 1145 { 1146 rc = VBoxServiceControlExecThreadAlloc(pThread, 1147 uContextID, 1148 pszCmd, uFlags, 1149 pszArgs, uNumArgs, 1150 pszEnv, cbEnv, uNumEnvVars, 1151 pszUser, pszPassword, 1152 uTimeLimitMS); 1153 if (RT_SUCCESS(rc)) 1165 1154 { 1166 VBoxServiceError("ControlExec: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n", 1167 rc, pThread); 1168 } 1169 else 1170 { 1171 VBoxServiceVerbose(4, "ControlExec: Waiting for thread to initialize ...\n"); 1172 1173 /* Wait for the thread to initialize. */ 1174 RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */); 1175 if (pThread->fShutdown) 1155 static uint32_t uCtrlExecThread = 0; 1156 char szThreadName[32]; 1157 if (!RTStrPrintf(szThreadName, sizeof(szThreadName), "controlexec%ld", uCtrlExecThread++)) 1158 AssertMsgFailed(("Unable to create unique control exec thread name!\n")); 1159 1160 rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread, 1161 (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0, 1162 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName); 1163 if (RT_FAILURE(rc)) 1176 1164 { 1177 VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd);1178 rc = VERR_GENERAL_FAILURE;1165 VBoxServiceError("ControlExec: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n", 1166 rc, pThread); 1179 1167 } 1180 1168 else 1181 1169 { 1182 pThread->fStarted = true; 1183 /*rc =*/ RTListAppend(&g_GuestControlThreads, &pThread->Node); 1170 VBoxServiceVerbose(4, "ControlExec: Waiting for thread to initialize ...\n"); 1171 1172 /* Wait for the thread to initialize. */ 1173 RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */); 1174 if (pThread->fShutdown) 1175 { 1176 VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd); 1177 rc = VERR_GENERAL_FAILURE; 1178 } 1179 else 1180 { 1181 pThread->fStarted = true; 1182 /*rc =*/ RTListAppend(&g_GuestControlThreads, &pThread->Node); 1183 } 1184 1184 } 1185 1186 if (RT_FAILURE(rc)) 1187 VBoxServiceControlExecThreadDataDestroy((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData); 1185 1188 } 1186 1187 1189 if (RT_FAILURE(rc)) 1188 VBoxServiceControlExecThreadDataDestroy((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData); 1189 } 1190 if (RT_FAILURE(rc)) 1191 RTMemFree(pThread); 1192 } 1193 else 1194 rc = VERR_NO_MEMORY; 1190 RTMemFree(pThread); 1191 } 1192 else 1193 rc = VERR_NO_MEMORY; 1194 } 1195 else /* Process start is not allowed due to policy settings. */ 1196 { 1197 VBoxServiceVerbose(3, "ControlExec: Guest process limit is reached!\n"); 1198 1199 /* Tell the host. */ 1200 rc = VbglR3GuestCtrlExecReportStatus(uClientID, uContextID, 0 /* PID */, 1201 PROC_STS_ERROR, VERR_MAX_PROCS_REACHED, 1202 NULL /* pvData */, 0 /* cbData */); 1203 } 1195 1204 return rc; 1196 1205 } … … 1251 1260 if (RT_SUCCESS(rc)) 1252 1261 { 1253 rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs, 1262 /** @todo Put the following params into a struct! */ 1263 rc = VBoxServiceControlExecProcess(u32ClientId, uContextID, 1264 szCmd, uFlags, szArgs, uNumArgs, 1254 1265 szEnv, cbEnv, uNumEnvVars, 1255 1266 szUser, szPassword, uTimeLimitMS); -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.cpp
r38157 r38180 20 20 * Header Files * 21 21 *******************************************************************************/ 22 #include <iprt/asm.h> 22 23 #include <iprt/assert.h> 23 24 #include <iprt/getopt.h> … … 161 162 162 163 /** 163 * Applies the policies to all guest execution threads.164 *165 * @return IPRT status code.166 */167 int VBoxServiceControlExecThreadsApplyPolicies(void)168 {169 int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);170 if (RT_SUCCESS(rc))171 {172 VBoxServiceVerbose(2, "Control: Applying policies ...\n");173 174 /*175 * Check if we're respecting our memory policy by checking176 * how many guest processes are started and served already.177 */178 if (g_GuestControlProcsMaxKept) /* If we allow unlimited processes, take a shortcut. */179 {180 uint32_t uNumProcs = 0;181 PVBOXSERVICECTRLTHREAD pNode;182 RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)183 {184 if (pNode->enmType == kVBoxServiceCtrlThreadDataExec)185 uNumProcs++;186 }187 188 /*189 * Do we serve more guest processes than we should? Kill the oldest n ones (=beginning190 * at the list).191 */192 uint32_t uProcsToKill = 0;193 if (uNumProcs > g_GuestControlProcsMaxKept)194 uProcsToKill = uNumProcs - g_GuestControlProcsMaxKept;195 if (uProcsToKill)196 {197 VBoxServiceVerbose(2, "Control: Maximum guest processes set to %u, running %u, killing %u oldest one(s) ...\n",198 g_GuestControlProcsMaxKept, uNumProcs, uProcsToKill);199 200 RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)201 {202 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node);203 204 rc = VBoxServiceControlExecThreadShutdown(pNode);205 if (RT_FAILURE(rc))206 {207 VBoxServiceError("Control: Unable to shut down thread due to policy, rc=%Rrc", rc);208 /* Keep going. */209 }210 211 RTListNodeRemove(&pNode->Node);212 RTMemFree(pNode);213 pNode = pNext;214 215 /* Did we fullfill our rate? Then stop killing innocent guest processes. */216 if (--uProcsToKill == 0)217 break;218 }219 }220 }221 222 int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect);223 if (RT_SUCCESS(rc))224 rc = rc2;225 }226 227 return rc;228 }229 230 231 /**232 164 * Assigns a valid PID to a guest control thread and also checks if there already was 233 165 * another (stale) guest process which was using that PID before and destroys it. … … 327 259 RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node) 328 260 { 329 if ( pNode->fStarted 330 && pNode->enmType == kVBoxServiceCtrlThreadDataExec) 261 if (pNode->enmType == kVBoxServiceCtrlThreadDataExec) 331 262 { 332 263 PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData; … … 429 360 break; 430 361 } 431 if (!pPipeBuf) 432 return VERR_INVALID_PARAMETER; 362 AssertPtr(pPipeBuf); 433 363 434 364 #ifdef DEBUG_andy … … 475 405 } 476 406 407 477 408 int VBoxServiceControlExecThreadShutdown(const PVBOXSERVICECTRLTHREAD pThread) 478 409 { … … 482 413 { 483 414 PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData; 484 if (!pData) 415 if (!pData) /* Already destroyed execution data. */ 485 416 return VINF_SUCCESS; 486 VBoxServiceVerbose(2, "Control: [PID %u]: Will not be served anymore\n", 417 if (pThread->fStarted) 418 { 419 VBoxServiceVerbose(2, "ControlExec: [PID %u]: Shutting down a still running thread without stopping is not possible!\n", 420 pData->uPID); 421 return VERR_INVALID_PARAMETER; 422 } 423 424 VBoxServiceVerbose(2, "ControlExec: [PID %u]: Shutting down, will not be served anymore\n", 487 425 pData->uPID); 488 426 VBoxServiceControlExecThreadDataDestroy(pData); … … 492 430 return VBoxServiceControlThreadWaitForShutdown(pThread); 493 431 } 432 433 434 int VBoxServiceControlExecThreadStartAllowed(bool *pbAllowed) 435 { 436 int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect); 437 if (RT_SUCCESS(rc)) 438 { 439 /* 440 * Check if we're respecting our memory policy by checking 441 * how many guest processes are started and served already. 442 */ 443 bool fLimitReached = false; 444 if (g_GuestControlProcsMaxKept) /* If we allow unlimited processes, take a shortcut. */ 445 { 446 /** @todo Put running/stopped (+ memory alloc) stats into global struct! */ 447 uint32_t uProcsRunning = 0; 448 uint32_t uProcsStopped = 0; 449 PVBOXSERVICECTRLTHREAD pNode; 450 RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node) 451 { 452 if (pNode->enmType == kVBoxServiceCtrlThreadDataExec) 453 { 454 Assert(pNode->fStarted != pNode->fStopped); 455 if (pNode->fStarted) 456 uProcsRunning++; 457 else if (pNode->fStopped) 458 uProcsStopped++; 459 else 460 AssertMsgFailed(("Process neither started nor stopped!?\n")); 461 } 462 } 463 464 VBoxServiceVerbose(2, "ControlExec: Maximum served guest processes set to %u, running=%u, stopped=%u\n", 465 g_GuestControlProcsMaxKept, uProcsRunning, uProcsStopped); 466 467 int32_t iProcsLeft = (g_GuestControlProcsMaxKept - uProcsRunning - 1); 468 if (iProcsLeft < 0) 469 { 470 VBoxServiceVerbose(3, "ControlExec: Maximum running guest processes reached\n"); 471 fLimitReached = true; 472 } 473 else if (uProcsStopped > iProcsLeft) 474 { 475 uint32_t uProcsToKill = uProcsStopped - iProcsLeft; 476 Assert(uProcsToKill); 477 VBoxServiceVerbose(3, "ControlExec: Shutting down %ld stopped guest processes\n", uProcsToKill); 478 479 RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node) 480 { 481 if ( pNode->enmType == kVBoxServiceCtrlThreadDataExec 482 && pNode->fStopped) 483 { 484 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node); 485 486 int rc2 = VBoxServiceControlExecThreadShutdown(pNode); 487 if (RT_FAILURE(rc2)) 488 { 489 VBoxServiceError("ControlExec: Unable to shut down thread due to policy, rc=%Rrc", rc2); 490 if (RT_SUCCESS(rc)) 491 rc = rc2; 492 /* Keep going. */ 493 } 494 495 RTListNodeRemove(&pNode->Node); 496 RTMemFree(pNode); 497 pNode = pNext; 498 499 uProcsToKill--; 500 if (!uProcsToKill) 501 break; 502 503 } 504 } 505 Assert(uProcsToKill == 0); 506 } 507 } 508 509 *pbAllowed = !fLimitReached; 510 511 int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect); 512 if (RT_SUCCESS(rc)) 513 rc = rc2; 514 } 515 516 return rc; 517 } 518 519 520 /** 521 * Marks an guest execution thread as stopped and cleans up its internal pipe buffers. 522 * 523 * @param pThread Pointer to guest execution thread. 524 */ 525 void VBoxServiceControlExecThreadStop(const PVBOXSERVICECTRLTHREAD pThread) 526 { 527 AssertPtr(pThread); 528 529 int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect); 530 if (RT_SUCCESS(rc)) 531 { 532 if (pThread->fStarted) 533 { 534 const PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData; 535 if (pData) 536 { 537 VBoxServiceVerbose(3, "ControlExec: [PID %u]: Marking as stopped\n", pData->uPID); 538 539 VBoxServicePipeBufSetStatus(&pData->stdIn, false /* Disabled */); 540 VBoxServicePipeBufSetStatus(&pData->stdOut, false /* Disabled */); 541 VBoxServicePipeBufSetStatus(&pData->stdErr, false /* Disabled */); 542 543 /* Since the process is not alive anymore, destroy its local 544 * stdin pipe buffer - it's not used anymore and can eat up quite 545 * a bit of memory. */ 546 VBoxServicePipeBufDestroy(&pData->stdIn); 547 } 548 549 /* Mark as stopped. */ 550 ASMAtomicXchgBool(&pThread->fStarted, false); 551 ASMAtomicXchgBool(&pThread->fStopped, true); 552 } 553 554 RTCritSectLeave(&g_GuestControlThreadsCritSect); 555 } 556 } 557 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.h
r38157 r38180 27 27 const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars, 28 28 const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS); 29 int VBoxServiceControlExecThreadsApplyPolicies();30 29 int VBoxServiceControlExecThreadAssignPID(PVBOXSERVICECTRLTHREADDATAEXEC pData, uint32_t uPID); 31 30 void VBoxServiceControlExecThreadDataDestroy(PVBOXSERVICECTRLTHREADDATAEXEC pData); … … 34 33 int VBoxServiceControlExecThreadSetInput(uint32_t uPID, bool fPendingClose, uint8_t *pBuf, 35 34 uint32_t cbSize, uint32_t *pcbWritten); 35 int VBoxServiceControlExecThreadStartAllowed(bool *pbAllowed); 36 void VBoxServiceControlExecThreadStop(const PVBOXSERVICECTRLTHREAD pThread); 36 37 #endif /* !___VBoxServiceControlExecThread_h */ 37 38 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
r38157 r38180 311 311 extern int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms, size_t cbMaxBufSize); 312 312 extern int VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms); 313 extern int VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags, 313 extern int VBoxServiceControlExecProcess(uint32_t uClientID, uint32_t uContext, 314 const char *pszCmd, uint32_t uFlags, 314 315 const char *pszArgs, uint32_t uNumArgs, 315 316 const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
Note:
See TracChangeset
for help on using the changeset viewer.