| Index: mozilla/nsprpub/pr/src/md/windows/ntmisc.c
|
| ===================================================================
|
| --- mozilla/nsprpub/pr/src/md/windows/ntmisc.c (revision 191424)
|
| +++ mozilla/nsprpub/pr/src/md/windows/ntmisc.c (working copy)
|
| @@ -1,1183 +0,0 @@
|
| -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -/*
|
| - * ntmisc.c
|
| - *
|
| - */
|
| -
|
| -#include "primpl.h"
|
| -#include <math.h> /* for fabs() */
|
| -#include <windows.h>
|
| -
|
| -char *_PR_MD_GET_ENV(const char *name)
|
| -{
|
| - return getenv(name);
|
| -}
|
| -
|
| -/*
|
| -** _PR_MD_PUT_ENV() -- add or change environment variable
|
| -**
|
| -**
|
| -*/
|
| -PRIntn _PR_MD_PUT_ENV(const char *name)
|
| -{
|
| - return(putenv(name));
|
| -}
|
| -
|
| -
|
| -/*
|
| - **************************************************************************
|
| - **************************************************************************
|
| - **
|
| - ** Date and time routines
|
| - **
|
| - **************************************************************************
|
| - **************************************************************************
|
| - */
|
| -
|
| -/*
|
| - * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
|
| - * We store the value in a PRTime variable for convenience.
|
| - */
|
| -#ifdef __GNUC__
|
| -const PRTime _pr_filetime_offset = 116444736000000000LL;
|
| -const PRTime _pr_filetime_divisor = 10LL;
|
| -#else
|
| -const PRTime _pr_filetime_offset = 116444736000000000i64;
|
| -const PRTime _pr_filetime_divisor = 10i64;
|
| -#endif
|
| -
|
| -#ifdef WINCE
|
| -
|
| -#define FILETIME_TO_INT64(ft) \
|
| - (((PRInt64)ft.dwHighDateTime) << 32 | (PRInt64)ft.dwLowDateTime)
|
| -
|
| -static void
|
| -LowResTime(LPFILETIME lpft)
|
| -{
|
| - GetCurrentFT(lpft);
|
| -}
|
| -
|
| -typedef struct CalibrationData {
|
| - long double freq; /* The performance counter frequency */
|
| - long double offset; /* The low res 'epoch' */
|
| - long double timer_offset; /* The high res 'epoch' */
|
| -
|
| - /* The last high res time that we returned since recalibrating */
|
| - PRInt64 last;
|
| -
|
| - PRBool calibrated;
|
| -
|
| - CRITICAL_SECTION data_lock;
|
| - CRITICAL_SECTION calibration_lock;
|
| - PRInt64 granularity;
|
| -} CalibrationData;
|
| -
|
| -static CalibrationData calibration;
|
| -
|
| -typedef void (*GetSystemTimeAsFileTimeFcn)(LPFILETIME);
|
| -static GetSystemTimeAsFileTimeFcn ce6_GetSystemTimeAsFileTime = NULL;
|
| -
|
| -static void
|
| -NowCalibrate(void)
|
| -{
|
| - FILETIME ft, ftStart;
|
| - LARGE_INTEGER liFreq, now;
|
| -
|
| - if (calibration.freq == 0.0) {
|
| - if(!QueryPerformanceFrequency(&liFreq)) {
|
| - /* High-performance timer is unavailable */
|
| - calibration.freq = -1.0;
|
| - } else {
|
| - calibration.freq = (long double) liFreq.QuadPart;
|
| - }
|
| - }
|
| - if (calibration.freq > 0.0) {
|
| - PRInt64 calibrationDelta = 0;
|
| - /*
|
| - * By wrapping a timeBegin/EndPeriod pair of calls around this loop,
|
| - * the loop seems to take much less time (1 ms vs 15ms) on Vista.
|
| - */
|
| - timeBeginPeriod(1);
|
| - LowResTime(&ftStart);
|
| - do {
|
| - LowResTime(&ft);
|
| - } while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
|
| - timeEndPeriod(1);
|
| -
|
| - calibration.granularity =
|
| - (FILETIME_TO_INT64(ft) - FILETIME_TO_INT64(ftStart))/10;
|
| -
|
| - QueryPerformanceCounter(&now);
|
| -
|
| - calibration.offset = (long double) FILETIME_TO_INT64(ft);
|
| - calibration.timer_offset = (long double) now.QuadPart;
|
| - /*
|
| - * The windows epoch is around 1600. The unix epoch is around 1970.
|
| - * _pr_filetime_offset is the difference (in windows time units which
|
| - * are 10 times more highres than the JS time unit)
|
| - */
|
| - calibration.offset -= _pr_filetime_offset;
|
| - calibration.offset *= 0.1;
|
| - calibration.last = 0;
|
| -
|
| - calibration.calibrated = PR_TRUE;
|
| - }
|
| -}
|
| -
|
| -#define CALIBRATIONLOCK_SPINCOUNT 0
|
| -#define DATALOCK_SPINCOUNT 4096
|
| -#define LASTLOCK_SPINCOUNT 4096
|
| -
|
| -void
|
| -_MD_InitTime(void)
|
| -{
|
| - /* try for CE6 GetSystemTimeAsFileTime first */
|
| - HANDLE h = GetModuleHandleW(L"coredll.dll");
|
| - ce6_GetSystemTimeAsFileTime = (GetSystemTimeAsFileTimeFcn)
|
| - GetProcAddressA(h, "GetSystemTimeAsFileTime");
|
| -
|
| - /* otherwise go the slow route */
|
| - if (ce6_GetSystemTimeAsFileTime == NULL) {
|
| - memset(&calibration, 0, sizeof(calibration));
|
| - NowCalibrate();
|
| - InitializeCriticalSection(&calibration.calibration_lock);
|
| - InitializeCriticalSection(&calibration.data_lock);
|
| - }
|
| -}
|
| -
|
| -void
|
| -_MD_CleanupTime(void)
|
| -{
|
| - if (ce6_GetSystemTimeAsFileTime == NULL) {
|
| - DeleteCriticalSection(&calibration.calibration_lock);
|
| - DeleteCriticalSection(&calibration.data_lock);
|
| - }
|
| -}
|
| -
|
| -#define MUTEX_SETSPINCOUNT(m, c)
|
| -
|
| -/*
|
| - *-----------------------------------------------------------------------
|
| - *
|
| - * PR_Now --
|
| - *
|
| - * Returns the current time in microseconds since the epoch.
|
| - * The epoch is midnight January 1, 1970 GMT.
|
| - * The implementation is machine dependent. This is the
|
| - * implementation for Windows.
|
| - * Cf. time_t time(time_t *tp)
|
| - *
|
| - *-----------------------------------------------------------------------
|
| - */
|
| -
|
| -PR_IMPLEMENT(PRTime)
|
| -PR_Now(void)
|
| -{
|
| - long double lowresTime, highresTimerValue;
|
| - FILETIME ft;
|
| - LARGE_INTEGER now;
|
| - PRBool calibrated = PR_FALSE;
|
| - PRBool needsCalibration = PR_FALSE;
|
| - PRInt64 returnedTime;
|
| - long double cachedOffset = 0.0;
|
| -
|
| - if (ce6_GetSystemTimeAsFileTime) {
|
| - union {
|
| - FILETIME ft;
|
| - PRTime prt;
|
| - } currentTime;
|
| -
|
| - PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
|
| -
|
| - ce6_GetSystemTimeAsFileTime(¤tTime.ft);
|
| -
|
| - /* written this way on purpose, since the second term becomes
|
| - * a constant, and the entire expression is faster to execute.
|
| - */
|
| - return currentTime.prt/_pr_filetime_divisor -
|
| - _pr_filetime_offset/_pr_filetime_divisor;
|
| - }
|
| -
|
| - do {
|
| - if (!calibration.calibrated || needsCalibration) {
|
| - EnterCriticalSection(&calibration.calibration_lock);
|
| - EnterCriticalSection(&calibration.data_lock);
|
| -
|
| - /* Recalibrate only if no one else did before us */
|
| - if (calibration.offset == cachedOffset) {
|
| - /*
|
| - * Since calibration can take a while, make any other
|
| - * threads immediately wait
|
| - */
|
| - MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
|
| -
|
| - NowCalibrate();
|
| -
|
| - calibrated = PR_TRUE;
|
| -
|
| - /* Restore spin count */
|
| - MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
|
| - }
|
| - LeaveCriticalSection(&calibration.data_lock);
|
| - LeaveCriticalSection(&calibration.calibration_lock);
|
| - }
|
| -
|
| - /* Calculate a low resolution time */
|
| - LowResTime(&ft);
|
| - lowresTime =
|
| - ((long double)(FILETIME_TO_INT64(ft) - _pr_filetime_offset)) * 0.1;
|
| -
|
| - if (calibration.freq > 0.0) {
|
| - long double highresTime, diff;
|
| - DWORD timeAdjustment, timeIncrement;
|
| - BOOL timeAdjustmentDisabled;
|
| -
|
| - /* Default to 15.625 ms if the syscall fails */
|
| - long double skewThreshold = 15625.25;
|
| -
|
| - /* Grab high resolution time */
|
| - QueryPerformanceCounter(&now);
|
| - highresTimerValue = (long double)now.QuadPart;
|
| -
|
| - EnterCriticalSection(&calibration.data_lock);
|
| - highresTime = calibration.offset + 1000000L *
|
| - (highresTimerValue-calibration.timer_offset)/calibration.freq;
|
| - cachedOffset = calibration.offset;
|
| -
|
| - /*
|
| - * On some dual processor/core systems, we might get an earlier
|
| - * time so we cache the last time that we returned.
|
| - */
|
| - calibration.last = PR_MAX(calibration.last,(PRInt64)highresTime);
|
| - returnedTime = calibration.last;
|
| - LeaveCriticalSection(&calibration.data_lock);
|
| -
|
| - /* Get an estimate of clock ticks per second from our own test */
|
| - skewThreshold = calibration.granularity;
|
| - /* Check for clock skew */
|
| - diff = lowresTime - highresTime;
|
| -
|
| - /*
|
| - * For some reason that I have not determined, the skew can be
|
| - * up to twice a kernel tick. This does not seem to happen by
|
| - * itself, but I have only seen it triggered by another program
|
| - * doing some kind of file I/O. The symptoms are a negative diff
|
| - * followed by an equally large positive diff.
|
| - */
|
| - if (fabs(diff) > 2*skewThreshold) {
|
| - if (calibrated) {
|
| - /*
|
| - * If we already calibrated once this instance, and the
|
| - * clock is still skewed, then either the processor(s) are
|
| - * wildly changing clockspeed or the system is so busy that
|
| - * we get switched out for long periods of time. In either
|
| - * case, it would be infeasible to make use of high
|
| - * resolution results for anything, so let's resort to old
|
| - * behavior for this call. It's possible that in the
|
| - * future, the user will want the high resolution timer, so
|
| - * we don't disable it entirely.
|
| - */
|
| - returnedTime = (PRInt64)lowresTime;
|
| - needsCalibration = PR_FALSE;
|
| - } else {
|
| - /*
|
| - * It is possible that when we recalibrate, we will return
|
| - * a value less than what we have returned before; this is
|
| - * unavoidable. We cannot tell the different between a
|
| - * faulty QueryPerformanceCounter implementation and user
|
| - * changes to the operating system time. Since we must
|
| - * respect user changes to the operating system time, we
|
| - * cannot maintain the invariant that Date.now() never
|
| - * decreases; the old implementation has this behavior as
|
| - * well.
|
| - */
|
| - needsCalibration = PR_TRUE;
|
| - }
|
| - } else {
|
| - /* No detectable clock skew */
|
| - returnedTime = (PRInt64)highresTime;
|
| - needsCalibration = PR_FALSE;
|
| - }
|
| - } else {
|
| - /* No high resolution timer is available, so fall back */
|
| - returnedTime = (PRInt64)lowresTime;
|
| - }
|
| - } while (needsCalibration);
|
| -
|
| - return returnedTime;
|
| -}
|
| -
|
| -#else
|
| -
|
| -PR_IMPLEMENT(PRTime)
|
| -PR_Now(void)
|
| -{
|
| - PRTime prt;
|
| - FILETIME ft;
|
| - SYSTEMTIME st;
|
| -
|
| - GetSystemTime(&st);
|
| - SystemTimeToFileTime(&st, &ft);
|
| - _PR_FileTimeToPRTime(&ft, &prt);
|
| - return prt;
|
| -}
|
| -
|
| -#endif
|
| -
|
| -/*
|
| - ***********************************************************************
|
| - ***********************************************************************
|
| - *
|
| - * Process creation routines
|
| - *
|
| - ***********************************************************************
|
| - ***********************************************************************
|
| - */
|
| -
|
| -/*
|
| - * Assemble the command line by concatenating the argv array.
|
| - * On success, this function returns 0 and the resulting command
|
| - * line is returned in *cmdLine. On failure, it returns -1.
|
| - */
|
| -static int assembleCmdLine(char *const *argv, char **cmdLine)
|
| -{
|
| - char *const *arg;
|
| - char *p, *q;
|
| - size_t cmdLineSize;
|
| - int numBackslashes;
|
| - int i;
|
| - int argNeedQuotes;
|
| -
|
| - /*
|
| - * Find out how large the command line buffer should be.
|
| - */
|
| - cmdLineSize = 0;
|
| - for (arg = argv; *arg; arg++) {
|
| - /*
|
| - * \ and " need to be escaped by a \. In the worst case,
|
| - * every character is a \ or ", so the string of length
|
| - * may double. If we quote an argument, that needs two ".
|
| - * Finally, we need a space between arguments, and
|
| - * a null byte at the end of command line.
|
| - */
|
| - cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
|
| - + 2 /* we quote every argument */
|
| - + 1; /* space in between, or final null */
|
| - }
|
| - p = *cmdLine = PR_MALLOC((PRUint32) cmdLineSize);
|
| - if (p == NULL) {
|
| - return -1;
|
| - }
|
| -
|
| - for (arg = argv; *arg; arg++) {
|
| - /* Add a space to separates the arguments */
|
| - if (arg != argv) {
|
| - *p++ = ' ';
|
| - }
|
| - q = *arg;
|
| - numBackslashes = 0;
|
| - argNeedQuotes = 0;
|
| -
|
| - /*
|
| - * If the argument is empty or contains white space, it needs to
|
| - * be quoted.
|
| - */
|
| - if (**arg == '\0' || strpbrk(*arg, " \f\n\r\t\v")) {
|
| - argNeedQuotes = 1;
|
| - }
|
| -
|
| - if (argNeedQuotes) {
|
| - *p++ = '"';
|
| - }
|
| - while (*q) {
|
| - if (*q == '\\') {
|
| - numBackslashes++;
|
| - q++;
|
| - } else if (*q == '"') {
|
| - if (numBackslashes) {
|
| - /*
|
| - * Double the backslashes since they are followed
|
| - * by a quote
|
| - */
|
| - for (i = 0; i < 2 * numBackslashes; i++) {
|
| - *p++ = '\\';
|
| - }
|
| - numBackslashes = 0;
|
| - }
|
| - /* To escape the quote */
|
| - *p++ = '\\';
|
| - *p++ = *q++;
|
| - } else {
|
| - if (numBackslashes) {
|
| - /*
|
| - * Backslashes are not followed by a quote, so
|
| - * don't need to double the backslashes.
|
| - */
|
| - for (i = 0; i < numBackslashes; i++) {
|
| - *p++ = '\\';
|
| - }
|
| - numBackslashes = 0;
|
| - }
|
| - *p++ = *q++;
|
| - }
|
| - }
|
| -
|
| - /* Now we are at the end of this argument */
|
| - if (numBackslashes) {
|
| - /*
|
| - * Double the backslashes if we have a quote string
|
| - * delimiter at the end.
|
| - */
|
| - if (argNeedQuotes) {
|
| - numBackslashes *= 2;
|
| - }
|
| - for (i = 0; i < numBackslashes; i++) {
|
| - *p++ = '\\';
|
| - }
|
| - }
|
| - if (argNeedQuotes) {
|
| - *p++ = '"';
|
| - }
|
| - }
|
| -
|
| - *p = '\0';
|
| - return 0;
|
| -}
|
| -
|
| -/*
|
| - * Assemble the environment block by concatenating the envp array
|
| - * (preserving the terminating null byte in each array element)
|
| - * and adding a null byte at the end.
|
| - *
|
| - * Returns 0 on success. The resulting environment block is returned
|
| - * in *envBlock. Note that if envp is NULL, a NULL pointer is returned
|
| - * in *envBlock. Returns -1 on failure.
|
| - */
|
| -static int assembleEnvBlock(char **envp, char **envBlock)
|
| -{
|
| - char *p;
|
| - char *q;
|
| - char **env;
|
| - char *curEnv;
|
| - char *cwdStart, *cwdEnd;
|
| - size_t envBlockSize;
|
| -
|
| - if (envp == NULL) {
|
| - *envBlock = NULL;
|
| - return 0;
|
| - }
|
| -
|
| -#ifdef WINCE
|
| - {
|
| - PRUnichar *wideCurEnv = mozce_GetEnvString();
|
| - int len = WideCharToMultiByte(CP_ACP, 0, wideCurEnv, -1,
|
| - NULL, 0, NULL, NULL);
|
| - curEnv = (char *) PR_MALLOC(len * sizeof(char));
|
| - WideCharToMultiByte(CP_ACP, 0, wideCurEnv, -1,
|
| - curEnv, len, NULL, NULL);
|
| - free(wideCurEnv);
|
| - }
|
| -#else
|
| - curEnv = GetEnvironmentStrings();
|
| -#endif
|
| -
|
| - cwdStart = curEnv;
|
| - while (*cwdStart) {
|
| - if (cwdStart[0] == '=' && cwdStart[1] != '\0'
|
| - && cwdStart[2] == ':' && cwdStart[3] == '=') {
|
| - break;
|
| - }
|
| - cwdStart += strlen(cwdStart) + 1;
|
| - }
|
| - cwdEnd = cwdStart;
|
| - if (*cwdEnd) {
|
| - cwdEnd += strlen(cwdEnd) + 1;
|
| - while (*cwdEnd) {
|
| - if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
|
| - || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
|
| - break;
|
| - }
|
| - cwdEnd += strlen(cwdEnd) + 1;
|
| - }
|
| - }
|
| - envBlockSize = cwdEnd - cwdStart;
|
| -
|
| - for (env = envp; *env; env++) {
|
| - envBlockSize += strlen(*env) + 1;
|
| - }
|
| - envBlockSize++;
|
| -
|
| - p = *envBlock = PR_MALLOC((PRUint32) envBlockSize);
|
| - if (p == NULL) {
|
| -#ifdef WINCE
|
| - PR_Free(curEnv);
|
| -#else
|
| - FreeEnvironmentStrings(curEnv);
|
| -#endif
|
| - return -1;
|
| - }
|
| -
|
| - q = cwdStart;
|
| - while (q < cwdEnd) {
|
| - *p++ = *q++;
|
| - }
|
| -#ifdef WINCE
|
| - PR_Free(curEnv);
|
| -#else
|
| - FreeEnvironmentStrings(curEnv);
|
| -#endif
|
| -
|
| - for (env = envp; *env; env++) {
|
| - q = *env;
|
| - while (*q) {
|
| - *p++ = *q++;
|
| - }
|
| - *p++ = '\0';
|
| - }
|
| - *p = '\0';
|
| - return 0;
|
| -}
|
| -
|
| -/*
|
| - * For qsort. We sort (case-insensitive) the environment strings
|
| - * before generating the environment block.
|
| - */
|
| -static int compare(const void *arg1, const void *arg2)
|
| -{
|
| - return _stricmp(* (char**)arg1, * (char**)arg2);
|
| -}
|
| -
|
| -PRProcess * _PR_CreateWindowsProcess(
|
| - const char *path,
|
| - char *const *argv,
|
| - char *const *envp,
|
| - const PRProcessAttr *attr)
|
| -{
|
| -#ifdef WINCE
|
| - STARTUPINFOW startupInfo;
|
| - PRUnichar *wideCmdLine;
|
| - PRUnichar *wideCwd;
|
| - int len = 0;
|
| -#else
|
| - STARTUPINFO startupInfo;
|
| -#endif
|
| - DWORD creationFlags = 0;
|
| - PROCESS_INFORMATION procInfo;
|
| - BOOL retVal;
|
| - char *cmdLine = NULL;
|
| - char *envBlock = NULL;
|
| - char **newEnvp = NULL;
|
| - const char *cwd = NULL; /* current working directory */
|
| - PRProcess *proc = NULL;
|
| - PRBool hasFdInheritBuffer;
|
| -
|
| - proc = PR_NEW(PRProcess);
|
| - if (!proc) {
|
| - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
| - goto errorExit;
|
| - }
|
| -
|
| - if (assembleCmdLine(argv, &cmdLine) == -1) {
|
| - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
| - goto errorExit;
|
| - }
|
| -
|
| -#ifndef WINCE
|
| - /*
|
| - * If attr->fdInheritBuffer is not NULL, we need to insert
|
| - * it into the envp array, so envp cannot be NULL.
|
| - */
|
| - hasFdInheritBuffer = (attr && attr->fdInheritBuffer);
|
| - if ((envp == NULL) && hasFdInheritBuffer) {
|
| - envp = environ;
|
| - }
|
| -
|
| - if (envp != NULL) {
|
| - int idx;
|
| - int numEnv;
|
| - PRBool found = PR_FALSE;
|
| -
|
| - numEnv = 0;
|
| - while (envp[numEnv]) {
|
| - numEnv++;
|
| - }
|
| - newEnvp = (char **) PR_MALLOC((numEnv + 2) * sizeof(char *));
|
| - for (idx = 0; idx < numEnv; idx++) {
|
| - newEnvp[idx] = envp[idx];
|
| - if (hasFdInheritBuffer && !found
|
| - && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
|
| - newEnvp[idx] = attr->fdInheritBuffer;
|
| - found = PR_TRUE;
|
| - }
|
| - }
|
| - if (hasFdInheritBuffer && !found) {
|
| - newEnvp[idx++] = attr->fdInheritBuffer;
|
| - }
|
| - newEnvp[idx] = NULL;
|
| - qsort((void *) newEnvp, (size_t) idx, sizeof(char *), compare);
|
| - }
|
| - if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
|
| - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
| - goto errorExit;
|
| - }
|
| -
|
| - ZeroMemory(&startupInfo, sizeof(startupInfo));
|
| - startupInfo.cb = sizeof(startupInfo);
|
| -
|
| - if (attr) {
|
| - PRBool redirected = PR_FALSE;
|
| -
|
| - /*
|
| - * XXX the default value for stdin, stdout, and stderr
|
| - * should probably be the console input and output, not
|
| - * those of the parent process.
|
| - */
|
| - startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
| - startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
| - startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
| - if (attr->stdinFd) {
|
| - startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd;
|
| - redirected = PR_TRUE;
|
| - }
|
| - if (attr->stdoutFd) {
|
| - startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd;
|
| - redirected = PR_TRUE;
|
| - /*
|
| - * If stdout is redirected, we can assume that the process will
|
| - * not write anything useful to the console windows, and therefore
|
| - * automatically set the CREATE_NO_WINDOW flag.
|
| - */
|
| - creationFlags |= CREATE_NO_WINDOW;
|
| - }
|
| - if (attr->stderrFd) {
|
| - startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd;
|
| - redirected = PR_TRUE;
|
| - }
|
| - if (redirected) {
|
| - startupInfo.dwFlags |= STARTF_USESTDHANDLES;
|
| - }
|
| - cwd = attr->currentDirectory;
|
| - }
|
| -#endif
|
| -
|
| -#ifdef WINCE
|
| - len = MultiByteToWideChar(CP_ACP, 0, cmdLine, -1, NULL, 0);
|
| - wideCmdLine = (PRUnichar *)PR_MALLOC(len * sizeof(PRUnichar));
|
| - MultiByteToWideChar(CP_ACP, 0, cmdLine, -1, wideCmdLine, len);
|
| - len = MultiByteToWideChar(CP_ACP, 0, cwd, -1, NULL, 0);
|
| - wideCwd = PR_MALLOC(len * sizeof(PRUnichar));
|
| - MultiByteToWideChar(CP_ACP, 0, cwd, -1, wideCwd, len);
|
| - retVal = CreateProcessW(NULL,
|
| - wideCmdLine,
|
| - NULL, /* security attributes for the new
|
| - * process */
|
| - NULL, /* security attributes for the primary
|
| - * thread in the new process */
|
| - TRUE, /* inherit handles */
|
| - creationFlags,
|
| - envBlock, /* an environment block, consisting
|
| - * of a null-terminated block of
|
| - * null-terminated strings. Each
|
| - * string is in the form:
|
| - * name=value
|
| - * XXX: usually NULL */
|
| - wideCwd, /* current drive and directory */
|
| - &startupInfo,
|
| - &procInfo
|
| - );
|
| - PR_Free(wideCmdLine);
|
| - PR_Free(wideCwd);
|
| -#else
|
| - retVal = CreateProcess(NULL,
|
| - cmdLine,
|
| - NULL, /* security attributes for the new
|
| - * process */
|
| - NULL, /* security attributes for the primary
|
| - * thread in the new process */
|
| - TRUE, /* inherit handles */
|
| - creationFlags,
|
| - envBlock, /* an environment block, consisting
|
| - * of a null-terminated block of
|
| - * null-terminated strings. Each
|
| - * string is in the form:
|
| - * name=value
|
| - * XXX: usually NULL */
|
| - cwd, /* current drive and directory */
|
| - &startupInfo,
|
| - &procInfo
|
| - );
|
| -#endif
|
| -
|
| - if (retVal == FALSE) {
|
| - /* XXX what error code? */
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - goto errorExit;
|
| - }
|
| -
|
| - CloseHandle(procInfo.hThread);
|
| - proc->md.handle = procInfo.hProcess;
|
| - proc->md.id = procInfo.dwProcessId;
|
| -
|
| - PR_DELETE(cmdLine);
|
| - if (newEnvp) {
|
| - PR_DELETE(newEnvp);
|
| - }
|
| - if (envBlock) {
|
| - PR_DELETE(envBlock);
|
| - }
|
| - return proc;
|
| -
|
| -errorExit:
|
| - if (cmdLine) {
|
| - PR_DELETE(cmdLine);
|
| - }
|
| - if (newEnvp) {
|
| - PR_DELETE(newEnvp);
|
| - }
|
| - if (envBlock) {
|
| - PR_DELETE(envBlock);
|
| - }
|
| - if (proc) {
|
| - PR_DELETE(proc);
|
| - }
|
| - return NULL;
|
| -} /* _PR_CreateWindowsProcess */
|
| -
|
| -PRStatus _PR_DetachWindowsProcess(PRProcess *process)
|
| -{
|
| - CloseHandle(process->md.handle);
|
| - PR_DELETE(process);
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -/*
|
| - * XXX: This implementation is a temporary quick solution.
|
| - * It can be called by native threads only (not by fibers).
|
| - */
|
| -PRStatus _PR_WaitWindowsProcess(PRProcess *process,
|
| - PRInt32 *exitCode)
|
| -{
|
| - DWORD dwRetVal;
|
| -
|
| - dwRetVal = WaitForSingleObject(process->md.handle, INFINITE);
|
| - if (dwRetVal == WAIT_FAILED) {
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| - PR_ASSERT(dwRetVal == WAIT_OBJECT_0);
|
| - if (exitCode != NULL &&
|
| - GetExitCodeProcess(process->md.handle, exitCode) == FALSE) {
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| - CloseHandle(process->md.handle);
|
| - PR_DELETE(process);
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -PRStatus _PR_KillWindowsProcess(PRProcess *process)
|
| -{
|
| - /*
|
| - * On Unix, if a process terminates normally, its exit code is
|
| - * between 0 and 255. So here on Windows, we use the exit code
|
| - * 256 to indicate that the process is killed.
|
| - */
|
| - if (TerminateProcess(process->md.handle, 256)) {
|
| - return PR_SUCCESS;
|
| - }
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - return PR_FAILURE;
|
| -}
|
| -
|
| -PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen)
|
| -{
|
| - PRIntn rv;
|
| - PRInt32 syserror;
|
| -
|
| - rv = gethostname(name, (PRInt32) namelen);
|
| - if (0 == rv) {
|
| - return PR_SUCCESS;
|
| - }
|
| - syserror = WSAGetLastError();
|
| - PR_ASSERT(WSANOTINITIALISED != syserror);
|
| - _PR_MD_MAP_GETHOSTNAME_ERROR(syserror);
|
| - return PR_FAILURE;
|
| -}
|
| -
|
| -PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen)
|
| -{
|
| - OSVERSIONINFO osvi;
|
| -
|
| - PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE));
|
| -
|
| - ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
| - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
| -
|
| - if (! GetVersionEx (&osvi) ) {
|
| - _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| -
|
| - switch (osvi.dwPlatformId) {
|
| - case VER_PLATFORM_WIN32_NT:
|
| - if (PR_SI_SYSNAME == cmd)
|
| - (void)PR_snprintf(name, namelen, "Windows_NT");
|
| - else if (PR_SI_RELEASE == cmd)
|
| - (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
|
| - osvi.dwMinorVersion);
|
| - break;
|
| - case VER_PLATFORM_WIN32_WINDOWS:
|
| - if (PR_SI_SYSNAME == cmd) {
|
| - if ((osvi.dwMajorVersion > 4) ||
|
| - ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0)))
|
| - (void)PR_snprintf(name, namelen, "Windows_98");
|
| - else
|
| - (void)PR_snprintf(name, namelen, "Windows_95");
|
| - } else if (PR_SI_RELEASE == cmd) {
|
| - (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
|
| - osvi.dwMinorVersion);
|
| - }
|
| - break;
|
| -#ifdef VER_PLATFORM_WIN32_CE
|
| - case VER_PLATFORM_WIN32_CE:
|
| - if (PR_SI_SYSNAME == cmd)
|
| - (void)PR_snprintf(name, namelen, "Windows_CE");
|
| - else if (PR_SI_RELEASE == cmd)
|
| - (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
|
| - osvi.dwMinorVersion);
|
| - break;
|
| -#endif
|
| - default:
|
| - if (PR_SI_SYSNAME == cmd)
|
| - (void)PR_snprintf(name, namelen, "Windows_Unknown");
|
| - else if (PR_SI_RELEASE == cmd)
|
| - (void)PR_snprintf(name, namelen, "%d.%d",0,0);
|
| - break;
|
| - }
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -PRStatus _MD_WindowsGetReleaseName(char *name, PRUint32 namelen)
|
| -{
|
| - OSVERSIONINFO osvi;
|
| -
|
| - ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
| - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
| -
|
| - if (! GetVersionEx (&osvi) ) {
|
| - _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| -
|
| - switch (osvi.dwPlatformId) {
|
| - case VER_PLATFORM_WIN32_NT:
|
| - case VER_PLATFORM_WIN32_WINDOWS:
|
| - (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
|
| - osvi.dwMinorVersion);
|
| - break;
|
| - default:
|
| - (void)PR_snprintf(name, namelen, "%d.%d",0,0);
|
| - break;
|
| - }
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -/*
|
| - **********************************************************************
|
| - *
|
| - * Memory-mapped files
|
| - *
|
| - **********************************************************************
|
| - */
|
| -
|
| -PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
|
| -{
|
| - DWORD dwHi, dwLo;
|
| - DWORD flProtect;
|
| - PROsfd osfd;
|
| -
|
| - osfd = ( fmap->fd == (PRFileDesc*)-1 )? -1 : fmap->fd->secret->md.osfd;
|
| -
|
| - dwLo = (DWORD) (size & 0xffffffff);
|
| - dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
|
| -
|
| - if (fmap->prot == PR_PROT_READONLY) {
|
| - flProtect = PAGE_READONLY;
|
| - fmap->md.dwAccess = FILE_MAP_READ;
|
| - } else if (fmap->prot == PR_PROT_READWRITE) {
|
| - flProtect = PAGE_READWRITE;
|
| - fmap->md.dwAccess = FILE_MAP_WRITE;
|
| - } else {
|
| - PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
|
| -#ifdef WINCE
|
| - /* WINCE does not have FILE_MAP_COPY. */
|
| - PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
| - return PR_FAILURE;
|
| -#else
|
| - flProtect = PAGE_WRITECOPY;
|
| - fmap->md.dwAccess = FILE_MAP_COPY;
|
| -#endif
|
| - }
|
| -
|
| - fmap->md.hFileMap = CreateFileMapping(
|
| - (HANDLE) osfd,
|
| - NULL,
|
| - flProtect,
|
| - dwHi,
|
| - dwLo,
|
| - NULL);
|
| -
|
| - if (fmap->md.hFileMap == NULL) {
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -PRInt32 _MD_GetMemMapAlignment(void)
|
| -{
|
| - SYSTEM_INFO info;
|
| - GetSystemInfo(&info);
|
| - return info.dwAllocationGranularity;
|
| -}
|
| -
|
| -extern PRLogModuleInfo *_pr_shma_lm;
|
| -
|
| -void * _MD_MemMap(
|
| - PRFileMap *fmap,
|
| - PROffset64 offset,
|
| - PRUint32 len)
|
| -{
|
| - DWORD dwHi, dwLo;
|
| - void *addr;
|
| -
|
| - dwLo = (DWORD) (offset & 0xffffffff);
|
| - dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff);
|
| - if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess,
|
| - dwHi, dwLo, len)) == NULL) {
|
| - {
|
| - LPVOID lpMsgBuf;
|
| -
|
| - FormatMessage(
|
| - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
| - NULL,
|
| - GetLastError(),
|
| - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
| - (LPTSTR) &lpMsgBuf,
|
| - 0,
|
| - NULL
|
| - );
|
| - PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf ));
|
| - }
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - }
|
| - return addr;
|
| -}
|
| -
|
| -PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
|
| -{
|
| - if (UnmapViewOfFile(addr)) {
|
| - return PR_SUCCESS;
|
| - } else {
|
| - PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| -}
|
| -
|
| -PRStatus _MD_CloseFileMap(PRFileMap *fmap)
|
| -{
|
| - CloseHandle(fmap->md.hFileMap);
|
| - PR_DELETE(fmap);
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -/*
|
| - ***********************************************************************
|
| - *
|
| - * Atomic increment and decrement operations for x86 processors
|
| - *
|
| - * We don't use InterlockedIncrement and InterlockedDecrement
|
| - * because on NT 3.51 and Win95, they return a number with
|
| - * the same sign as the incremented/decremented result, rather
|
| - * than the result itself. On NT 4.0 these functions do return
|
| - * the incremented/decremented result.
|
| - *
|
| - * The result is returned in the eax register by the inline
|
| - * assembly code. We disable the harmless "no return value"
|
| - * warning (4035) for these two functions.
|
| - *
|
| - ***********************************************************************
|
| - */
|
| -
|
| -#if defined(_M_IX86) || defined(_X86_)
|
| -
|
| -#pragma warning(disable: 4035)
|
| -PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
|
| -{
|
| -#if defined(__GNUC__)
|
| - PRInt32 result;
|
| - asm volatile ("lock ; xadd %0, %1"
|
| - : "=r"(result), "=m"(*val)
|
| - : "0"(1), "m"(*val));
|
| - return result + 1;
|
| -#else
|
| - __asm
|
| - {
|
| - mov ecx, val
|
| - mov eax, 1
|
| - lock xadd dword ptr [ecx], eax
|
| - inc eax
|
| - }
|
| -#endif /* __GNUC__ */
|
| -}
|
| -#pragma warning(default: 4035)
|
| -
|
| -#pragma warning(disable: 4035)
|
| -PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
|
| -{
|
| -#if defined(__GNUC__)
|
| - PRInt32 result;
|
| - asm volatile ("lock ; xadd %0, %1"
|
| - : "=r"(result), "=m"(*val)
|
| - : "0"(-1), "m"(*val));
|
| - //asm volatile("lock ; xadd %0, %1" : "=m" (val), "=a" (result) : "-1" (1));
|
| - return result - 1;
|
| -#else
|
| - __asm
|
| - {
|
| - mov ecx, val
|
| - mov eax, 0ffffffffh
|
| - lock xadd dword ptr [ecx], eax
|
| - dec eax
|
| - }
|
| -#endif /* __GNUC__ */
|
| -}
|
| -#pragma warning(default: 4035)
|
| -
|
| -#pragma warning(disable: 4035)
|
| -PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val)
|
| -{
|
| -#if defined(__GNUC__)
|
| - PRInt32 result;
|
| - //asm volatile("lock ; xadd %1, %0" : "=m" (intp), "=a" (result) : "1" (val));
|
| - asm volatile ("lock ; xadd %0, %1"
|
| - : "=r"(result), "=m"(*intp)
|
| - : "0"(val), "m"(*intp));
|
| - return result + val;
|
| -#else
|
| - __asm
|
| - {
|
| - mov ecx, intp
|
| - mov eax, val
|
| - mov edx, eax
|
| - lock xadd dword ptr [ecx], eax
|
| - add eax, edx
|
| - }
|
| -#endif /* __GNUC__ */
|
| -}
|
| -#pragma warning(default: 4035)
|
| -
|
| -#ifdef _PR_HAVE_ATOMIC_CAS
|
| -
|
| -#pragma warning(disable: 4035)
|
| -void
|
| -PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
|
| -{
|
| -#if defined(__GNUC__)
|
| - void **tos = (void **) stack;
|
| - void *tmp;
|
| -
|
| - retry:
|
| - if (*tos == (void *) -1)
|
| - goto retry;
|
| -
|
| - __asm__("xchg %0,%1"
|
| - : "=r" (tmp), "=m"(*tos)
|
| - : "0" (-1), "m"(*tos));
|
| -
|
| - if (tmp == (void *) -1)
|
| - goto retry;
|
| -
|
| - *(void **)stack_elem = tmp;
|
| - __asm__("" : : : "memory");
|
| - *tos = stack_elem;
|
| -#else
|
| - __asm
|
| - {
|
| - mov ebx, stack
|
| - mov ecx, stack_elem
|
| -retry: mov eax,[ebx]
|
| - cmp eax,-1
|
| - je retry
|
| - mov eax,-1
|
| - xchg dword ptr [ebx], eax
|
| - cmp eax,-1
|
| - je retry
|
| - mov [ecx],eax
|
| - mov [ebx],ecx
|
| - }
|
| -#endif /* __GNUC__ */
|
| -}
|
| -#pragma warning(default: 4035)
|
| -
|
| -#pragma warning(disable: 4035)
|
| -PRStackElem *
|
| -PR_StackPop(PRStack *stack)
|
| -{
|
| -#if defined(__GNUC__)
|
| - void **tos = (void **) stack;
|
| - void *tmp;
|
| -
|
| - retry:
|
| - if (*tos == (void *) -1)
|
| - goto retry;
|
| -
|
| - __asm__("xchg %0,%1"
|
| - : "=r" (tmp), "=m"(*tos)
|
| - : "0" (-1), "m"(*tos));
|
| -
|
| - if (tmp == (void *) -1)
|
| - goto retry;
|
| -
|
| - if (tmp != (void *) 0)
|
| - {
|
| - void *next = *(void **)tmp;
|
| - *tos = next;
|
| - *(void **)tmp = 0;
|
| - }
|
| - else
|
| - *tos = tmp;
|
| -
|
| - return tmp;
|
| -#else
|
| - __asm
|
| - {
|
| - mov ebx, stack
|
| -retry: mov eax,[ebx]
|
| - cmp eax,-1
|
| - je retry
|
| - mov eax,-1
|
| - xchg dword ptr [ebx], eax
|
| - cmp eax,-1
|
| - je retry
|
| - cmp eax,0
|
| - je empty
|
| - mov ecx,[eax]
|
| - mov [ebx],ecx
|
| - mov [eax],0
|
| - jmp done
|
| -empty:
|
| - mov [ebx],eax
|
| -done:
|
| - }
|
| -#endif /* __GNUC__ */
|
| -}
|
| -#pragma warning(default: 4035)
|
| -
|
| -#endif /* _PR_HAVE_ATOMIC_CAS */
|
| -
|
| -#endif /* x86 processors */
|
|
|