Changeset 27556 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Mar 20, 2010 3:05:06 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 59072
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/process-win.cpp
r27513 r27556 44 44 45 45 #include <iprt/assert.h> 46 #include <iprt/critsect.h> 46 47 #include <iprt/file.h> 47 48 #include <iprt/err.h> 48 49 #include <iprt/env.h> 49 50 #include <iprt/getopt.h> 51 #include <iprt/initterm.h> 50 52 #include <iprt/ldr.h> 53 #include <iprt/mem.h> 54 #include <iprt/once.h> 51 55 #include <iprt/pipe.h> 52 56 #include <iprt/string.h> … … 54 58 55 59 56 /* 57 * This is from Winternl.h. It has been copied here 58 * because the header does not define a calling convention for 59 * its prototypes and just assumes that _stdcall is the standard 60 * calling convention. 61 */ 62 typedef struct _PEB 63 { 64 BYTE Reserved1[2]; 65 BYTE BeingDebugged; 66 BYTE Reserved2[229]; 67 PVOID Reserved3[59]; 68 ULONG SessionId; 69 } PEB, *PPEB; 70 71 typedef struct _PROCESS_BASIC_INFORMATION 72 { 73 PVOID Reserved1; 74 PPEB PebBaseAddress; 75 PVOID Reserved2[2]; 76 ULONG_PTR UniqueProcessId; 77 PVOID Reserved3; 78 } PROCESS_BASIC_INFORMATION; 79 80 typedef enum _PROCESSINFOCLASS 81 { 82 ProcessBasicInformation = 0, 83 ProcessWow64Information = 26 84 } PROCESSINFOCLASS; 85 86 extern "C" LONG WINAPI 87 NtQueryInformationProcess( 88 IN HANDLE ProcessHandle, 89 IN PROCESSINFOCLASS ProcessInformationClass, 90 OUT PVOID ProcessInformation, 91 IN ULONG ProcessInformationLength, 92 OUT PULONG ReturnLength OPTIONAL); 93 60 /******************************************************************************* 61 * Structures and Typedefs * 62 *******************************************************************************/ 94 63 typedef WINADVAPI BOOL WINAPI FNCREATEPROCESSWITHLOGON(LPCWSTR, 95 64 LPCWSTR, … … 106 75 107 76 108 #if 0 /** @todo Andy, could you enable and test this, please? It should work, but I don't have a full windows install to test it on. */ 77 /******************************************************************************* 78 * Global Variables * 79 *******************************************************************************/ 80 /** Init once structure. */ 81 static RTONCE g_rtProcWinInitOnce = RTONCE_INITIALIZER; 82 /** Critical section protecting the process array. */ 83 static RTCRITSECT g_CritSect; 84 /** The number of processes in the array. */ 85 static uint32_t g_cProcesses; 86 /** The current allocation size. */ 87 static uint32_t g_cProcessesAlloc; 88 /** Array containing the live or non-reaped child processes. */ 89 static struct RTPROCWINENTRY 90 { 91 /** The process ID. */ 92 ULONG_PTR pid; 93 /** The process handle. */ 94 HANDLE hProcess; 95 } *g_paProcesses; 96 97 98 /** 99 * Clean up the globals. 100 * 101 * @param enmReason Ignored. 102 * @param iStatus Ignored. 103 * @param pvUser Ignored. 104 */ 105 static DECLCALLBACK(void) rtProcWinTerm(RTTERMREASON enmReason, int32_t iStatus, void *pvUser) 106 { 107 NOREF(pvUser); NOREF(iStatus); NOREF(enmReason); 108 109 RTCritSectDelete(&g_CritSect); 110 111 size_t i = g_cProcesses; 112 while (i-- > 0) 113 { 114 CloseHandle(g_paProcesses[i].hProcess); 115 g_paProcesses[i].hProcess = NULL; 116 } 117 RTMemFree(g_paProcesses); 118 119 g_paProcesses = NULL; 120 g_cProcesses = 0; 121 g_cProcessesAlloc = 0; 122 } 123 124 125 /** 126 * Initialize the globals. 127 * 128 * @returns IPRT status code. 129 * @param pvUser1 Ignored. 130 * @param pvUser2 Ignored. 131 */ 132 static DECLCALLBACK(int32_t) rtProcWinInitOnce(void *pvUser1, void *pvUser2) 133 { 134 NOREF(pvUser1); NOREF(pvUser2); 135 136 g_cProcesses = 0; 137 g_cProcessesAlloc = 0; 138 g_paProcesses = NULL; 139 int rc = RTCritSectInit(&g_CritSect); 140 if (RT_SUCCESS(rc)) 141 { 142 /** @todo init once, terminate once - this is a generic thing which should 143 * have some kind of static and simpler setup! */ 144 rc = RTTermRegisterCallback(rtProcWinTerm, NULL); 145 if (RT_SUCCESS(rc)) 146 return rc; 147 RTCritSectDelete(&g_CritSect); 148 } 149 return rc; 150 } 151 152 153 /** 154 * Gets the process handle for a process from g_paProcesses. 155 * 156 * @returns Process handle if found, NULL if not. 157 * @param pid The process to remove (pid). 158 */ 159 static HANDLE rtProcWinFindPid(RTPROCESS pid) 160 { 161 HANDLE hProcess = NULL; 162 163 RTCritSectEnter(&g_CritSect); 164 uint32_t i = g_cProcesses; 165 while (i-- > 0) 166 if (g_paProcesses[i].pid == pid) 167 { 168 hProcess = g_paProcesses[i].hProcess; 169 break; 170 } 171 RTCritSectLeave(&g_CritSect); 172 173 return hProcess; 174 } 175 176 177 /** 178 * Removes a process from g_paProcesses. 179 * 180 * @param pid The process to remove (pid). 181 */ 182 static void rtProcWinRemovePid(RTPROCESS pid) 183 { 184 RTCritSectEnter(&g_CritSect); 185 uint32_t i = g_cProcesses; 186 while (i-- > 0) 187 if (g_paProcesses[i].pid == pid) 188 { 189 g_cProcesses--; 190 uint32_t cToMove = g_cProcesses - i; 191 if (cToMove) 192 memmove(&g_paProcesses[i], &g_paProcesses[i + 1], cToMove * sizeof(g_paProcesses[0])); 193 break; 194 } 195 RTCritSectLeave(&g_CritSect); 196 } 197 198 199 /** 200 * Adds a process to g_paProcesses. 201 * 202 * @returns IPRT status code. 203 * @param pid The process id. 204 * @param hProcess The process handle. 205 */ 206 static int rtProcWinAddPid(RTPROCESS pid, HANDLE hProcess) 207 { 208 RTCritSectEnter(&g_CritSect); 209 210 uint32_t i = g_cProcesses; 211 if (i >= g_cProcessesAlloc) 212 { 213 void *pvNew = RTMemRealloc(g_paProcesses, (i + 16) * sizeof(g_paProcesses[0])); 214 if (RT_UNLIKELY(!pvNew)) 215 { 216 RTCritSectLeave(&g_CritSect); 217 return VERR_NO_MEMORY; 218 } 219 g_paProcesses = (struct RTPROCWINENTRY *)pvNew; 220 g_cProcessesAlloc = i + 16; 221 } 222 223 g_paProcesses[i].pid = pid; 224 g_paProcesses[i].hProcess = hProcess; 225 g_cProcesses = i + 1; 226 227 RTCritSectLeave(&g_CritSect); 228 return VINF_SUCCESS; 229 } 230 231 109 232 RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess) 110 233 { … … 114 237 pProcess); 115 238 } 116 #else117 /** @todo r=michael This function currently does not work correctly if the arguments118 contain spaces. */119 RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess)120 {121 /*122 * Validate input.123 */124 AssertPtrReturn(pszExec, VERR_INVALID_POINTER);125 AssertReturn(*pszExec, VERR_INVALID_PARAMETER);126 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);127 AssertReturn(Env != NIL_RTENV, VERR_INVALID_PARAMETER);128 const char * const *papszEnv = RTEnvGetExecEnvP(Env);129 AssertPtrReturn(papszEnv, VERR_INVALID_HANDLE);130 AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);131 AssertPtrReturn(*papszArgs, VERR_INVALID_PARAMETER);132 /* later: path searching. */133 134 /*135 * Spawn the child.136 */137 /** @todo utf-8 considerations! */138 HANDLE hProcess = (HANDLE)_spawnve(_P_NOWAITO, pszExec, papszArgs, papszEnv);139 if (hProcess != 0 && hProcess != INVALID_HANDLE_VALUE)140 {141 if (pProcess)142 {143 /*144 * GetProcessId requires XP SP1 or later145 */146 #if defined(RT_ARCH_AMD64)147 *pProcess = GetProcessId(hProcess);148 #else /* !RT_ARCH_AMD64 */149 static bool fInitialized = false;150 static DWORD (WINAPI *pfnGetProcessId)(HANDLE Thread) = NULL;151 if (!fInitialized)152 {153 HMODULE hmodKernel32 = GetModuleHandle("KERNEL32.DLL");154 if (hmodKernel32)155 pfnGetProcessId = (DWORD (WINAPI*)(HANDLE))GetProcAddress(hmodKernel32, "GetProcessId");156 fInitialized = true;157 }158 if (pfnGetProcessId)159 {160 *pProcess = pfnGetProcessId(hProcess);161 if (!*pProcess)162 {163 int rc = RTErrConvertFromWin32(GetLastError());164 AssertMsgFailed(("failed to get pid from hProcess=%#x rc=%Rrc\n", hProcess, rc));165 return rc;166 }167 }168 else169 {170 /*171 * Fall back to the NT api for older versions.172 */173 PROCESS_BASIC_INFORMATION ProcInfo = {0};174 ULONG Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,175 &ProcInfo, sizeof(ProcInfo), NULL);176 if (Status != 0)177 {178 int rc = ERROR_INTERNAL_ERROR; /* (we don't have a valid conversion here, but this shouldn't happen anyway.) */179 AssertMsgFailed(("failed to get pid from hProcess=%#x rc=%Rrc Status=%#x\n", hProcess, rc, Status));180 return rc;181 }182 *pProcess = ProcInfo.UniqueProcessId;183 }184 #endif /* !RT_ARCH_AMD64 */185 }186 return VINF_SUCCESS;187 }188 189 int rc = RTErrConvertFromErrno(errno);190 AssertMsgFailed(("spawn/exec failed rc=%Rrc\n", rc)); /* this migth be annoying... */191 return rc;192 }193 #endif194 239 195 240 … … 235 280 dwErr = GetLastError(); 236 281 237 #ifndef IPRT_TARGET_NT4 /* We could dispense with the tediuos dynamic loading here if we wanted. */282 #ifndef IPRT_TARGET_NT4 238 283 /* 239 284 * If we don't hold enough priviledges to spawn a new process with … … 285 330 const char *pszPassword, PRTPROCESS phProcess) 286 331 { 287 int rc;288 289 332 /* 290 333 * Input validation … … 296 339 AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER); 297 340 /** @todo search the PATH (add flag for this). */ 341 342 /* 343 * Initialize the globals. 344 */ 345 int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL); 346 AssertRCReturn(rc, rc); 298 347 299 348 /* … … 441 490 if (phProcess) 442 491 { 443 /** @todo Remember the process handle and pick it up in RTProcWait. */ 492 /* 493 * Add the process to the child process list so 494 * RTProcWait can reuse and close the process handle. 495 */ 496 rtProcWinAddPid(ProcInfo.dwProcessId, ProcInfo.hProcess); 444 497 *phProcess = ProcInfo.dwProcessId; 445 498 } … … 472 525 { 473 526 AssertReturn(!(fFlags & ~(RTPROCWAIT_FLAGS_BLOCK | RTPROCWAIT_FLAGS_NOBLOCK)), VERR_INVALID_PARAMETER); 474 475 /* 476 * Open the process. 477 */ 478 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Process); 527 int rc = RTOnce(&g_rtProcWinInitOnce, rtProcWinInitOnce, NULL, NULL); 528 AssertRCReturn(rc, rc); 529 530 /* 531 * Try find the process among the ones we've spawned, otherwise, attempt 532 * opening the specified process. 533 */ 534 HANDLE hProcess = rtProcWinFindPid(Process); 535 if (hProcess == NULL) 536 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Process); 479 537 if (hProcess != NULL) 480 538 { … … 502 560 pProcStatus->iStatus = (int)dwExitCode; 503 561 } 562 rtProcWinRemovePid(Process); 504 563 return VINF_SUCCESS; 505 564 } … … 527 586 } 528 587 DWORD dwErr = GetLastError(); 588 if (dwErr == ERROR_INVALID_PARAMETER) 589 return VERR_PROCESS_NOT_FOUND; 529 590 return RTErrConvertFromWin32(dwErr); 530 591 }
Note:
See TracChangeset
for help on using the changeset viewer.