1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
* License, v. 2.0. If a copy of the MPL was not distributed with this
4
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
12
#include <math.h> /* for fabs() */
15
char *_PR_MD_GET_ENV(const char *name)
21
** _PR_MD_PUT_ENV() -- add or change environment variable
25
PRIntn _PR_MD_PUT_ENV(const char *name)
32
**************************************************************************
33
**************************************************************************
35
** Date and time routines
37
**************************************************************************
38
**************************************************************************
42
* The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
43
* We store the value in a PRTime variable for convenience.
46
const PRTime _pr_filetime_offset = 116444736000000000LL;
47
const PRTime _pr_filetime_divisor = 10LL;
49
const PRTime _pr_filetime_offset = 116444736000000000i64;
50
const PRTime _pr_filetime_divisor = 10i64;
55
#define FILETIME_TO_INT64(ft) \
56
(((PRInt64)ft.dwHighDateTime) << 32 | (PRInt64)ft.dwLowDateTime)
59
LowResTime(LPFILETIME lpft)
64
typedef struct CalibrationData {
65
long double freq; /* The performance counter frequency */
66
long double offset; /* The low res 'epoch' */
67
long double timer_offset; /* The high res 'epoch' */
69
/* The last high res time that we returned since recalibrating */
74
CRITICAL_SECTION data_lock;
75
CRITICAL_SECTION calibration_lock;
79
static CalibrationData calibration;
81
typedef void (*GetSystemTimeAsFileTimeFcn)(LPFILETIME);
82
static GetSystemTimeAsFileTimeFcn ce6_GetSystemTimeAsFileTime = NULL;
88
LARGE_INTEGER liFreq, now;
90
if (calibration.freq == 0.0) {
91
if(!QueryPerformanceFrequency(&liFreq)) {
92
/* High-performance timer is unavailable */
93
calibration.freq = -1.0;
95
calibration.freq = (long double) liFreq.QuadPart;
98
if (calibration.freq > 0.0) {
99
PRInt64 calibrationDelta = 0;
101
* By wrapping a timeBegin/EndPeriod pair of calls around this loop,
102
* the loop seems to take much less time (1 ms vs 15ms) on Vista.
105
LowResTime(&ftStart);
108
} while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
111
calibration.granularity =
112
(FILETIME_TO_INT64(ft) - FILETIME_TO_INT64(ftStart))/10;
114
QueryPerformanceCounter(&now);
116
calibration.offset = (long double) FILETIME_TO_INT64(ft);
117
calibration.timer_offset = (long double) now.QuadPart;
119
* The windows epoch is around 1600. The unix epoch is around 1970.
120
* _pr_filetime_offset is the difference (in windows time units which
121
* are 10 times more highres than the JS time unit)
123
calibration.offset -= _pr_filetime_offset;
124
calibration.offset *= 0.1;
125
calibration.last = 0;
127
calibration.calibrated = PR_TRUE;
131
#define CALIBRATIONLOCK_SPINCOUNT 0
132
#define DATALOCK_SPINCOUNT 4096
133
#define LASTLOCK_SPINCOUNT 4096
138
/* try for CE6 GetSystemTimeAsFileTime first */
139
HANDLE h = GetModuleHandleW(L"coredll.dll");
140
ce6_GetSystemTimeAsFileTime = (GetSystemTimeAsFileTimeFcn)
141
GetProcAddressA(h, "GetSystemTimeAsFileTime");
143
/* otherwise go the slow route */
144
if (ce6_GetSystemTimeAsFileTime == NULL) {
145
memset(&calibration, 0, sizeof(calibration));
147
InitializeCriticalSection(&calibration.calibration_lock);
148
InitializeCriticalSection(&calibration.data_lock);
153
_MD_CleanupTime(void)
155
if (ce6_GetSystemTimeAsFileTime == NULL) {
156
DeleteCriticalSection(&calibration.calibration_lock);
157
DeleteCriticalSection(&calibration.data_lock);
161
#define MUTEX_SETSPINCOUNT(m, c)
164
*-----------------------------------------------------------------------
168
* Returns the current time in microseconds since the epoch.
169
* The epoch is midnight January 1, 1970 GMT.
170
* The implementation is machine dependent. This is the
171
* implementation for Windows.
172
* Cf. time_t time(time_t *tp)
174
*-----------------------------------------------------------------------
180
long double lowresTime, highresTimerValue;
183
PRBool calibrated = PR_FALSE;
184
PRBool needsCalibration = PR_FALSE;
185
PRInt64 returnedTime;
186
long double cachedOffset = 0.0;
188
if (ce6_GetSystemTimeAsFileTime) {
194
PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
196
ce6_GetSystemTimeAsFileTime(¤tTime.ft);
198
/* written this way on purpose, since the second term becomes
199
* a constant, and the entire expression is faster to execute.
201
return currentTime.prt/_pr_filetime_divisor -
202
_pr_filetime_offset/_pr_filetime_divisor;
206
if (!calibration.calibrated || needsCalibration) {
207
EnterCriticalSection(&calibration.calibration_lock);
208
EnterCriticalSection(&calibration.data_lock);
210
/* Recalibrate only if no one else did before us */
211
if (calibration.offset == cachedOffset) {
213
* Since calibration can take a while, make any other
214
* threads immediately wait
216
MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
220
calibrated = PR_TRUE;
222
/* Restore spin count */
223
MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
225
LeaveCriticalSection(&calibration.data_lock);
226
LeaveCriticalSection(&calibration.calibration_lock);
229
/* Calculate a low resolution time */
232
((long double)(FILETIME_TO_INT64(ft) - _pr_filetime_offset)) * 0.1;
234
if (calibration.freq > 0.0) {
235
long double highresTime, diff;
236
DWORD timeAdjustment, timeIncrement;
237
BOOL timeAdjustmentDisabled;
239
/* Default to 15.625 ms if the syscall fails */
240
long double skewThreshold = 15625.25;
242
/* Grab high resolution time */
243
QueryPerformanceCounter(&now);
244
highresTimerValue = (long double)now.QuadPart;
246
EnterCriticalSection(&calibration.data_lock);
247
highresTime = calibration.offset + 1000000L *
248
(highresTimerValue-calibration.timer_offset)/calibration.freq;
249
cachedOffset = calibration.offset;
252
* On some dual processor/core systems, we might get an earlier
253
* time so we cache the last time that we returned.
255
calibration.last = PR_MAX(calibration.last,(PRInt64)highresTime);
256
returnedTime = calibration.last;
257
LeaveCriticalSection(&calibration.data_lock);
259
/* Get an estimate of clock ticks per second from our own test */
260
skewThreshold = calibration.granularity;
261
/* Check for clock skew */
262
diff = lowresTime - highresTime;
265
* For some reason that I have not determined, the skew can be
266
* up to twice a kernel tick. This does not seem to happen by
267
* itself, but I have only seen it triggered by another program
268
* doing some kind of file I/O. The symptoms are a negative diff
269
* followed by an equally large positive diff.
271
if (fabs(diff) > 2*skewThreshold) {
274
* If we already calibrated once this instance, and the
275
* clock is still skewed, then either the processor(s) are
276
* wildly changing clockspeed or the system is so busy that
277
* we get switched out for long periods of time. In either
278
* case, it would be infeasible to make use of high
279
* resolution results for anything, so let's resort to old
280
* behavior for this call. It's possible that in the
281
* future, the user will want the high resolution timer, so
282
* we don't disable it entirely.
284
returnedTime = (PRInt64)lowresTime;
285
needsCalibration = PR_FALSE;
288
* It is possible that when we recalibrate, we will return
289
* a value less than what we have returned before; this is
290
* unavoidable. We cannot tell the different between a
291
* faulty QueryPerformanceCounter implementation and user
292
* changes to the operating system time. Since we must
293
* respect user changes to the operating system time, we
294
* cannot maintain the invariant that Date.now() never
295
* decreases; the old implementation has this behavior as
298
needsCalibration = PR_TRUE;
301
/* No detectable clock skew */
302
returnedTime = (PRInt64)highresTime;
303
needsCalibration = PR_FALSE;
306
/* No high resolution timer is available, so fall back */
307
returnedTime = (PRInt64)lowresTime;
309
} while (needsCalibration);
324
SystemTimeToFileTime(&st, &ft);
325
_PR_FileTimeToPRTime(&ft, &prt);
332
***********************************************************************
333
***********************************************************************
335
* Process creation routines
337
***********************************************************************
338
***********************************************************************
342
* Assemble the command line by concatenating the argv array.
343
* On success, this function returns 0 and the resulting command
344
* line is returned in *cmdLine. On failure, it returns -1.
346
static int assembleCmdLine(char *const *argv, char **cmdLine)
356
* Find out how large the command line buffer should be.
359
for (arg = argv; *arg; arg++) {
361
* \ and " need to be escaped by a \. In the worst case,
362
* every character is a \ or ", so the string of length
363
* may double. If we quote an argument, that needs two ".
364
* Finally, we need a space between arguments, and
365
* a null byte at the end of command line.
367
cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
368
+ 2 /* we quote every argument */
369
+ 1; /* space in between, or final null */
371
p = *cmdLine = PR_MALLOC((PRUint32) cmdLineSize);
376
for (arg = argv; *arg; arg++) {
377
/* Add a space to separates the arguments */
386
* If the argument is empty or contains white space, it needs to
389
if (**arg == '\0' || strpbrk(*arg, " \f\n\r\t\v")) {
400
} else if (*q == '"') {
401
if (numBackslashes) {
403
* Double the backslashes since they are followed
406
for (i = 0; i < 2 * numBackslashes; i++) {
411
/* To escape the quote */
415
if (numBackslashes) {
417
* Backslashes are not followed by a quote, so
418
* don't need to double the backslashes.
420
for (i = 0; i < numBackslashes; i++) {
429
/* Now we are at the end of this argument */
430
if (numBackslashes) {
432
* Double the backslashes if we have a quote string
433
* delimiter at the end.
438
for (i = 0; i < numBackslashes; i++) {
452
* Assemble the environment block by concatenating the envp array
453
* (preserving the terminating null byte in each array element)
454
* and adding a null byte at the end.
456
* Returns 0 on success. The resulting environment block is returned
457
* in *envBlock. Note that if envp is NULL, a NULL pointer is returned
458
* in *envBlock. Returns -1 on failure.
460
static int assembleEnvBlock(char **envp, char **envBlock)
466
char *cwdStart, *cwdEnd;
476
PRUnichar *wideCurEnv = mozce_GetEnvString();
477
int len = WideCharToMultiByte(CP_ACP, 0, wideCurEnv, -1,
478
NULL, 0, NULL, NULL);
479
curEnv = (char *) PR_MALLOC(len * sizeof(char));
480
WideCharToMultiByte(CP_ACP, 0, wideCurEnv, -1,
481
curEnv, len, NULL, NULL);
485
curEnv = GetEnvironmentStrings();
490
if (cwdStart[0] == '=' && cwdStart[1] != '\0'
491
&& cwdStart[2] == ':' && cwdStart[3] == '=') {
494
cwdStart += strlen(cwdStart) + 1;
498
cwdEnd += strlen(cwdEnd) + 1;
500
if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
501
|| cwdEnd[2] != ':' || cwdEnd[3] != '=') {
504
cwdEnd += strlen(cwdEnd) + 1;
507
envBlockSize = cwdEnd - cwdStart;
509
for (env = envp; *env; env++) {
510
envBlockSize += strlen(*env) + 1;
514
p = *envBlock = PR_MALLOC((PRUint32) envBlockSize);
519
FreeEnvironmentStrings(curEnv);
531
FreeEnvironmentStrings(curEnv);
534
for (env = envp; *env; env++) {
546
* For qsort. We sort (case-insensitive) the environment strings
547
* before generating the environment block.
549
static int compare(const void *arg1, const void *arg2)
551
return _stricmp(* (char**)arg1, * (char**)arg2);
554
PRProcess * _PR_CreateWindowsProcess(
558
const PRProcessAttr *attr)
561
STARTUPINFOW startupInfo;
562
PRUnichar *wideCmdLine;
566
STARTUPINFO startupInfo;
568
DWORD creationFlags = 0;
569
PROCESS_INFORMATION procInfo;
571
char *cmdLine = NULL;
572
char *envBlock = NULL;
573
char **newEnvp = NULL;
574
const char *cwd = NULL; /* current working directory */
575
PRProcess *proc = NULL;
576
PRBool hasFdInheritBuffer;
578
proc = PR_NEW(PRProcess);
580
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
584
if (assembleCmdLine(argv, &cmdLine) == -1) {
585
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
591
* If attr->fdInheritBuffer is not NULL, we need to insert
592
* it into the envp array, so envp cannot be NULL.
594
hasFdInheritBuffer = (attr && attr->fdInheritBuffer);
595
if ((envp == NULL) && hasFdInheritBuffer) {
602
PRBool found = PR_FALSE;
605
while (envp[numEnv]) {
608
newEnvp = (char **) PR_MALLOC((numEnv + 2) * sizeof(char *));
609
for (idx = 0; idx < numEnv; idx++) {
610
newEnvp[idx] = envp[idx];
611
if (hasFdInheritBuffer && !found
612
&& !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
613
newEnvp[idx] = attr->fdInheritBuffer;
617
if (hasFdInheritBuffer && !found) {
618
newEnvp[idx++] = attr->fdInheritBuffer;
621
qsort((void *) newEnvp, (size_t) idx, sizeof(char *), compare);
623
if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
624
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
628
ZeroMemory(&startupInfo, sizeof(startupInfo));
629
startupInfo.cb = sizeof(startupInfo);
632
PRBool redirected = PR_FALSE;
635
* XXX the default value for stdin, stdout, and stderr
636
* should probably be the console input and output, not
637
* those of the parent process.
639
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
640
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
641
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
643
startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd;
644
redirected = PR_TRUE;
646
if (attr->stdoutFd) {
647
startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd;
648
redirected = PR_TRUE;
650
* If stdout is redirected, we can assume that the process will
651
* not write anything useful to the console windows, and therefore
652
* automatically set the CREATE_NO_WINDOW flag.
654
creationFlags |= CREATE_NO_WINDOW;
656
if (attr->stderrFd) {
657
startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd;
658
redirected = PR_TRUE;
661
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
663
cwd = attr->currentDirectory;
668
len = MultiByteToWideChar(CP_ACP, 0, cmdLine, -1, NULL, 0);
669
wideCmdLine = (PRUnichar *)PR_MALLOC(len * sizeof(PRUnichar));
670
MultiByteToWideChar(CP_ACP, 0, cmdLine, -1, wideCmdLine, len);
671
len = MultiByteToWideChar(CP_ACP, 0, cwd, -1, NULL, 0);
672
wideCwd = PR_MALLOC(len * sizeof(PRUnichar));
673
MultiByteToWideChar(CP_ACP, 0, cwd, -1, wideCwd, len);
674
retVal = CreateProcessW(NULL,
676
NULL, /* security attributes for the new
678
NULL, /* security attributes for the primary
679
* thread in the new process */
680
TRUE, /* inherit handles */
682
envBlock, /* an environment block, consisting
683
* of a null-terminated block of
684
* null-terminated strings. Each
685
* string is in the form:
687
* XXX: usually NULL */
688
wideCwd, /* current drive and directory */
692
PR_Free(wideCmdLine);
695
retVal = CreateProcess(NULL,
697
NULL, /* security attributes for the new
699
NULL, /* security attributes for the primary
700
* thread in the new process */
701
TRUE, /* inherit handles */
703
envBlock, /* an environment block, consisting
704
* of a null-terminated block of
705
* null-terminated strings. Each
706
* string is in the form:
708
* XXX: usually NULL */
709
cwd, /* current drive and directory */
715
if (retVal == FALSE) {
716
/* XXX what error code? */
717
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
721
CloseHandle(procInfo.hThread);
722
proc->md.handle = procInfo.hProcess;
723
proc->md.id = procInfo.dwProcessId;
748
} /* _PR_CreateWindowsProcess */
750
PRStatus _PR_DetachWindowsProcess(PRProcess *process)
752
CloseHandle(process->md.handle);
758
* XXX: This implementation is a temporary quick solution.
759
* It can be called by native threads only (not by fibers).
761
PRStatus _PR_WaitWindowsProcess(PRProcess *process,
766
dwRetVal = WaitForSingleObject(process->md.handle, INFINITE);
767
if (dwRetVal == WAIT_FAILED) {
768
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
771
PR_ASSERT(dwRetVal == WAIT_OBJECT_0);
772
if (exitCode != NULL &&
773
GetExitCodeProcess(process->md.handle, exitCode) == FALSE) {
774
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
777
CloseHandle(process->md.handle);
782
PRStatus _PR_KillWindowsProcess(PRProcess *process)
785
* On Unix, if a process terminates normally, its exit code is
786
* between 0 and 255. So here on Windows, we use the exit code
787
* 256 to indicate that the process is killed.
789
if (TerminateProcess(process->md.handle, 256)) {
792
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
796
PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen)
801
rv = gethostname(name, (PRInt32) namelen);
805
syserror = WSAGetLastError();
806
PR_ASSERT(WSANOTINITIALISED != syserror);
807
_PR_MD_MAP_GETHOSTNAME_ERROR(syserror);
811
PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen)
815
PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE));
817
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
818
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
820
if (! GetVersionEx (&osvi) ) {
821
_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
825
switch (osvi.dwPlatformId) {
826
case VER_PLATFORM_WIN32_NT:
827
if (PR_SI_SYSNAME == cmd)
828
(void)PR_snprintf(name, namelen, "Windows_NT");
829
else if (PR_SI_RELEASE == cmd)
830
(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
831
osvi.dwMinorVersion);
833
case VER_PLATFORM_WIN32_WINDOWS:
834
if (PR_SI_SYSNAME == cmd) {
835
if ((osvi.dwMajorVersion > 4) ||
836
((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0)))
837
(void)PR_snprintf(name, namelen, "Windows_98");
839
(void)PR_snprintf(name, namelen, "Windows_95");
840
} else if (PR_SI_RELEASE == cmd) {
841
(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
842
osvi.dwMinorVersion);
845
#ifdef VER_PLATFORM_WIN32_CE
846
case VER_PLATFORM_WIN32_CE:
847
if (PR_SI_SYSNAME == cmd)
848
(void)PR_snprintf(name, namelen, "Windows_CE");
849
else if (PR_SI_RELEASE == cmd)
850
(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
851
osvi.dwMinorVersion);
855
if (PR_SI_SYSNAME == cmd)
856
(void)PR_snprintf(name, namelen, "Windows_Unknown");
857
else if (PR_SI_RELEASE == cmd)
858
(void)PR_snprintf(name, namelen, "%d.%d",0,0);
864
PRStatus _MD_WindowsGetReleaseName(char *name, PRUint32 namelen)
868
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
869
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
871
if (! GetVersionEx (&osvi) ) {
872
_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
876
switch (osvi.dwPlatformId) {
877
case VER_PLATFORM_WIN32_NT:
878
case VER_PLATFORM_WIN32_WINDOWS:
879
(void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion,
880
osvi.dwMinorVersion);
883
(void)PR_snprintf(name, namelen, "%d.%d",0,0);
890
**********************************************************************
892
* Memory-mapped files
894
**********************************************************************
897
PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
903
osfd = ( fmap->fd == (PRFileDesc*)-1 )? -1 : fmap->fd->secret->md.osfd;
905
dwLo = (DWORD) (size & 0xffffffff);
906
dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
908
if (fmap->prot == PR_PROT_READONLY) {
909
flProtect = PAGE_READONLY;
910
fmap->md.dwAccess = FILE_MAP_READ;
911
} else if (fmap->prot == PR_PROT_READWRITE) {
912
flProtect = PAGE_READWRITE;
913
fmap->md.dwAccess = FILE_MAP_WRITE;
915
PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
917
/* WINCE does not have FILE_MAP_COPY. */
918
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
921
flProtect = PAGE_WRITECOPY;
922
fmap->md.dwAccess = FILE_MAP_COPY;
926
fmap->md.hFileMap = CreateFileMapping(
934
if (fmap->md.hFileMap == NULL) {
935
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
941
PRInt32 _MD_GetMemMapAlignment(void)
944
GetSystemInfo(&info);
945
return info.dwAllocationGranularity;
948
extern PRLogModuleInfo *_pr_shma_lm;
958
dwLo = (DWORD) (offset & 0xffffffff);
959
dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff);
960
if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess,
961
dwHi, dwLo, len)) == NULL) {
966
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
969
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
974
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf ));
976
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
981
PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
983
if (UnmapViewOfFile(addr)) {
986
_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
990
PRStatus _MD_CloseFileMap(PRFileMap *fmap)
992
CloseHandle(fmap->md.hFileMap);
997
PRStatus _MD_SyncMemMap(
1002
PROsfd osfd = fd->secret->md.osfd;
1004
/* The FlushViewOfFile page on MSDN says:
1005
* To flush all the dirty pages plus the metadata for the file and
1006
* ensure that they are physically written to disk, call
1007
* FlushViewOfFile and then call the FlushFileBuffers function.
1009
if (FlushViewOfFile(addr, len) && FlushFileBuffers((HANDLE) osfd)) {
1012
_PR_MD_MAP_DEFAULT_ERROR(GetLastError());
1017
***********************************************************************
1019
* Atomic increment and decrement operations for x86 processors
1021
* We don't use InterlockedIncrement and InterlockedDecrement
1022
* because on NT 3.51 and Win95, they return a number with
1023
* the same sign as the incremented/decremented result, rather
1024
* than the result itself. On NT 4.0 these functions do return
1025
* the incremented/decremented result.
1027
* The result is returned in the eax register by the inline
1028
* assembly code. We disable the harmless "no return value"
1029
* warning (4035) for these two functions.
1031
***********************************************************************
1034
#if defined(_M_IX86) || defined(_X86_)
1036
#pragma warning(disable: 4035)
1037
PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
1039
#if defined(__GNUC__)
1041
asm volatile ("lock ; xadd %0, %1"
1042
: "=r"(result), "=m"(*val)
1043
: "0"(1), "m"(*val));
1050
lock xadd dword ptr [ecx], eax
1053
#endif /* __GNUC__ */
1055
#pragma warning(default: 4035)
1057
#pragma warning(disable: 4035)
1058
PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
1060
#if defined(__GNUC__)
1062
asm volatile ("lock ; xadd %0, %1"
1063
: "=r"(result), "=m"(*val)
1064
: "0"(-1), "m"(*val));
1065
//asm volatile("lock ; xadd %0, %1" : "=m" (val), "=a" (result) : "-1" (1));
1072
lock xadd dword ptr [ecx], eax
1075
#endif /* __GNUC__ */
1077
#pragma warning(default: 4035)
1079
#pragma warning(disable: 4035)
1080
PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val)
1082
#if defined(__GNUC__)
1084
//asm volatile("lock ; xadd %1, %0" : "=m" (intp), "=a" (result) : "1" (val));
1085
asm volatile ("lock ; xadd %0, %1"
1086
: "=r"(result), "=m"(*intp)
1087
: "0"(val), "m"(*intp));
1088
return result + val;
1095
lock xadd dword ptr [ecx], eax
1098
#endif /* __GNUC__ */
1100
#pragma warning(default: 4035)
1102
#ifdef _PR_HAVE_ATOMIC_CAS
1104
#pragma warning(disable: 4035)
1106
PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
1108
#if defined(__GNUC__)
1109
void **tos = (void **) stack;
1113
if (*tos == (void *) -1)
1116
__asm__("xchg %0,%1"
1117
: "=r" (tmp), "=m"(*tos)
1118
: "0" (-1), "m"(*tos));
1120
if (tmp == (void *) -1)
1123
*(void **)stack_elem = tmp;
1124
__asm__("" : : : "memory");
1131
retry: mov eax,[ebx]
1135
xchg dword ptr [ebx], eax
1141
#endif /* __GNUC__ */
1143
#pragma warning(default: 4035)
1145
#pragma warning(disable: 4035)
1147
PR_StackPop(PRStack *stack)
1149
#if defined(__GNUC__)
1150
void **tos = (void **) stack;
1154
if (*tos == (void *) -1)
1157
__asm__("xchg %0,%1"
1158
: "=r" (tmp), "=m"(*tos)
1159
: "0" (-1), "m"(*tos));
1161
if (tmp == (void *) -1)
1164
if (tmp != (void *) 0)
1166
void *next = *(void **)tmp;
1178
retry: mov eax,[ebx]
1182
xchg dword ptr [ebx], eax
1195
#endif /* __GNUC__ */
1197
#pragma warning(default: 4035)
1199
#endif /* _PR_HAVE_ATOMIC_CAS */
1201
#endif /* x86 processors */