Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/nsprpub/pr/src/md/windows/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 31 kB image not shown  

Quelle  ntmisc.c   Sprache: C

 
/* -*- 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(charconst* argv, char** cmdLine) {
  charconst* 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, charconst* argv,
                                    charconst* 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) ||
            (cmd == PR_SI_RELEASE_BUILD));

  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);
      } else if (PR_SI_RELEASE_BUILD == cmd) {
        (void)PR_snprintf(name, namelen, "%d", osvi.dwBuildNumber);
      }
      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);
      } else if (PR_SI_RELEASE_BUILD == cmd) {
        (void)PR_snprintf(name, namelen, "%d", osvi.dwBuildNumber);
      }
      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);
      } else if (PR_SI_RELEASE_BUILD == cmd) {
        if (namelen) {
          *name = 0;
        }
      }
      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);
      } else if (PR_SI_RELEASE_BUILD == cmd) {
        if (namelen) {
          *name = 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;
  }
  _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
  return PR_FAILURE;
}

PRStatus _MD_CloseFileMap(PRFileMap* fmap) {
  CloseHandle(fmap->md.hFileMap);
  PR_DELETE(fmap);
  return PR_SUCCESS;
}

PRStatus _MD_SyncMemMap(PRFileDesc* fd, void* addr, PRUint32 len) {
  PROsfd osfd = fd->secret->md.osfd;

  /* The FlushViewOfFile page on MSDN says:
   *  To flush all the dirty pages plus the metadata for the file and
   *  ensure that they are physically written to disk, call
   *  FlushViewOfFile and then call the FlushFileBuffers function.
   */

  if (FlushViewOfFile(addr, len) && FlushFileBuffers((HANDLE)osfd)) {
    return PR_SUCCESS;
  }
  _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
  return PR_FAILURE;
}

/*
 ***********************************************************************
 *
 * 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 */

Messung V0.5
C=94 H=82 G=88

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.