comparison nspr/pr/src/md/windows/ntmisc.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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/. */
5
6 /*
7 * ntmisc.c
8 *
9 */
10
11 #include "primpl.h"
12 #include <math.h> /* for fabs() */
13 #include <windows.h>
14
15 char *_PR_MD_GET_ENV(const char *name)
16 {
17 return getenv(name);
18 }
19
20 /*
21 ** _PR_MD_PUT_ENV() -- add or change environment variable
22 **
23 **
24 */
25 PRIntn _PR_MD_PUT_ENV(const char *name)
26 {
27 return(putenv(name));
28 }
29
30
31 /*
32 **************************************************************************
33 **************************************************************************
34 **
35 ** Date and time routines
36 **
37 **************************************************************************
38 **************************************************************************
39 */
40
41 /*
42 * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
43 * We store the value in a PRTime variable for convenience.
44 */
45 #ifdef __GNUC__
46 const PRTime _pr_filetime_offset = 116444736000000000LL;
47 const PRTime _pr_filetime_divisor = 10LL;
48 #else
49 const PRTime _pr_filetime_offset = 116444736000000000i64;
50 const PRTime _pr_filetime_divisor = 10i64;
51 #endif
52
53 #ifdef WINCE
54
55 #define FILETIME_TO_INT64(ft) \
56 (((PRInt64)ft.dwHighDateTime) << 32 | (PRInt64)ft.dwLowDateTime)
57
58 static void
59 LowResTime(LPFILETIME lpft)
60 {
61 GetCurrentFT(lpft);
62 }
63
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' */
68
69 /* The last high res time that we returned since recalibrating */
70 PRInt64 last;
71
72 PRBool calibrated;
73
74 CRITICAL_SECTION data_lock;
75 CRITICAL_SECTION calibration_lock;
76 PRInt64 granularity;
77 } CalibrationData;
78
79 static CalibrationData calibration;
80
81 typedef void (*GetSystemTimeAsFileTimeFcn)(LPFILETIME);
82 static GetSystemTimeAsFileTimeFcn ce6_GetSystemTimeAsFileTime = NULL;
83
84 static void
85 NowCalibrate(void)
86 {
87 FILETIME ft, ftStart;
88 LARGE_INTEGER liFreq, now;
89
90 if (calibration.freq == 0.0) {
91 if(!QueryPerformanceFrequency(&liFreq)) {
92 /* High-performance timer is unavailable */
93 calibration.freq = -1.0;
94 } else {
95 calibration.freq = (long double) liFreq.QuadPart;
96 }
97 }
98 if (calibration.freq > 0.0) {
99 PRInt64 calibrationDelta = 0;
100 /*
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.
103 */
104 timeBeginPeriod(1);
105 LowResTime(&ftStart);
106 do {
107 LowResTime(&ft);
108 } while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
109 timeEndPeriod(1);
110
111 calibration.granularity =
112 (FILETIME_TO_INT64(ft) - FILETIME_TO_INT64(ftStart))/10;
113
114 QueryPerformanceCounter(&now);
115
116 calibration.offset = (long double) FILETIME_TO_INT64(ft);
117 calibration.timer_offset = (long double) now.QuadPart;
118 /*
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)
122 */
123 calibration.offset -= _pr_filetime_offset;
124 calibration.offset *= 0.1;
125 calibration.last = 0;
126
127 calibration.calibrated = PR_TRUE;
128 }
129 }
130
131 #define CALIBRATIONLOCK_SPINCOUNT 0
132 #define DATALOCK_SPINCOUNT 4096
133 #define LASTLOCK_SPINCOUNT 4096
134
135 void
136 _MD_InitTime(void)
137 {
138 /* try for CE6 GetSystemTimeAsFileTime first */
139 HANDLE h = GetModuleHandleW(L"coredll.dll");
140 ce6_GetSystemTimeAsFileTime = (GetSystemTimeAsFileTimeFcn)
141 GetProcAddressA(h, "GetSystemTimeAsFileTime");
142
143 /* otherwise go the slow route */
144 if (ce6_GetSystemTimeAsFileTime == NULL) {
145 memset(&calibration, 0, sizeof(calibration));
146 NowCalibrate();
147 InitializeCriticalSection(&calibration.calibration_lock);
148 InitializeCriticalSection(&calibration.data_lock);
149 }
150 }
151
152 void
153 _MD_CleanupTime(void)
154 {
155 if (ce6_GetSystemTimeAsFileTime == NULL) {
156 DeleteCriticalSection(&calibration.calibration_lock);
157 DeleteCriticalSection(&calibration.data_lock);
158 }
159 }
160
161 #define MUTEX_SETSPINCOUNT(m, c)
162
163 /*
164 *-----------------------------------------------------------------------
165 *
166 * PR_Now --
167 *
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)
173 *
174 *-----------------------------------------------------------------------
175 */
176
177 PR_IMPLEMENT(PRTime)
178 PR_Now(void)
179 {
180 long double lowresTime, highresTimerValue;
181 FILETIME ft;
182 LARGE_INTEGER now;
183 PRBool calibrated = PR_FALSE;
184 PRBool needsCalibration = PR_FALSE;
185 PRInt64 returnedTime;
186 long double cachedOffset = 0.0;
187
188 if (ce6_GetSystemTimeAsFileTime) {
189 union {
190 FILETIME ft;
191 PRTime prt;
192 } currentTime;
193
194 PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
195
196 ce6_GetSystemTimeAsFileTime(&currentTime.ft);
197
198 /* written this way on purpose, since the second term becomes
199 * a constant, and the entire expression is faster to execute.
200 */
201 return currentTime.prt/_pr_filetime_divisor -
202 _pr_filetime_offset/_pr_filetime_divisor;
203 }
204
205 do {
206 if (!calibration.calibrated || needsCalibration) {
207 EnterCriticalSection(&calibration.calibration_lock);
208 EnterCriticalSection(&calibration.data_lock);
209
210 /* Recalibrate only if no one else did before us */
211 if (calibration.offset == cachedOffset) {
212 /*
213 * Since calibration can take a while, make any other
214 * threads immediately wait
215 */
216 MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
217
218 NowCalibrate();
219
220 calibrated = PR_TRUE;
221
222 /* Restore spin count */
223 MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
224 }
225 LeaveCriticalSection(&calibration.data_lock);
226 LeaveCriticalSection(&calibration.calibration_lock);
227 }
228
229 /* Calculate a low resolution time */
230 LowResTime(&ft);
231 lowresTime =
232 ((long double)(FILETIME_TO_INT64(ft) - _pr_filetime_offset)) * 0.1;
233
234 if (calibration.freq > 0.0) {
235 long double highresTime, diff;
236 DWORD timeAdjustment, timeIncrement;
237 BOOL timeAdjustmentDisabled;
238
239 /* Default to 15.625 ms if the syscall fails */
240 long double skewThreshold = 15625.25;
241
242 /* Grab high resolution time */
243 QueryPerformanceCounter(&now);
244 highresTimerValue = (long double)now.QuadPart;
245
246 EnterCriticalSection(&calibration.data_lock);
247 highresTime = calibration.offset + 1000000L *
248 (highresTimerValue-calibration.timer_offset)/calibration.freq;
249 cachedOffset = calibration.offset;
250
251 /*
252 * On some dual processor/core systems, we might get an earlier
253 * time so we cache the last time that we returned.
254 */
255 calibration.last = PR_MAX(calibration.last,(PRInt64)highresTime);
256 returnedTime = calibration.last;
257 LeaveCriticalSection(&calibration.data_lock);
258
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;
263
264 /*
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.
270 */
271 if (fabs(diff) > 2*skewThreshold) {
272 if (calibrated) {
273 /*
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.
283 */
284 returnedTime = (PRInt64)lowresTime;
285 needsCalibration = PR_FALSE;
286 } else {
287 /*
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
296 * well.
297 */
298 needsCalibration = PR_TRUE;
299 }
300 } else {
301 /* No detectable clock skew */
302 returnedTime = (PRInt64)highresTime;
303 needsCalibration = PR_FALSE;
304 }
305 } else {
306 /* No high resolution timer is available, so fall back */
307 returnedTime = (PRInt64)lowresTime;
308 }
309 } while (needsCalibration);
310
311 return returnedTime;
312 }
313
314 #else
315
316 PR_IMPLEMENT(PRTime)
317 PR_Now(void)
318 {
319 PRTime prt;
320 FILETIME ft;
321 SYSTEMTIME st;
322
323 GetSystemTime(&st);
324 SystemTimeToFileTime(&st, &ft);
325 _PR_FileTimeToPRTime(&ft, &prt);
326 return prt;
327 }
328
329 #endif
330
331 /*
332 ***********************************************************************
333 ***********************************************************************
334 *
335 * Process creation routines
336 *
337 ***********************************************************************
338 ***********************************************************************
339 */
340
341 /*
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.
345 */
346 static int assembleCmdLine(char *const *argv, char **cmdLine)
347 {
348 char *const *arg;
349 char *p, *q;
350 size_t cmdLineSize;
351 int numBackslashes;
352 int i;
353 int argNeedQuotes;
354
355 /*
356 * Find out how large the command line buffer should be.
357 */
358 cmdLineSize = 0;
359 for (arg = argv; *arg; arg++) {
360 /*
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.
366 */
367 cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
368 + 2 /* we quote every argument */
369 + 1; /* space in between, or final null */
370 }
371 p = *cmdLine = PR_MALLOC((PRUint32) cmdLineSize);
372 if (p == NULL) {
373 return -1;
374 }
375
376 for (arg = argv; *arg; arg++) {
377 /* Add a space to separates the arguments */
378 if (arg != argv) {
379 *p++ = ' ';
380 }
381 q = *arg;
382 numBackslashes = 0;
383 argNeedQuotes = 0;
384
385 /*
386 * If the argument is empty or contains white space, it needs to
387 * be quoted.
388 */
389 if (**arg == '\0' || strpbrk(*arg, " \f\n\r\t\v")) {
390 argNeedQuotes = 1;
391 }
392
393 if (argNeedQuotes) {
394 *p++ = '"';
395 }
396 while (*q) {
397 if (*q == '\\') {
398 numBackslashes++;
399 q++;
400 } else if (*q == '"') {
401 if (numBackslashes) {
402 /*
403 * Double the backslashes since they are followed
404 * by a quote
405 */
406 for (i = 0; i < 2 * numBackslashes; i++) {
407 *p++ = '\\';
408 }
409 numBackslashes = 0;
410 }
411 /* To escape the quote */
412 *p++ = '\\';
413 *p++ = *q++;
414 } else {
415 if (numBackslashes) {
416 /*
417 * Backslashes are not followed by a quote, so
418 * don't need to double the backslashes.
419 */
420 for (i = 0; i < numBackslashes; i++) {
421 *p++ = '\\';
422 }
423 numBackslashes = 0;
424 }
425 *p++ = *q++;
426 }
427 }
428
429 /* Now we are at the end of this argument */
430 if (numBackslashes) {
431 /*
432 * Double the backslashes if we have a quote string
433 * delimiter at the end.
434 */
435 if (argNeedQuotes) {
436 numBackslashes *= 2;
437 }
438 for (i = 0; i < numBackslashes; i++) {
439 *p++ = '\\';
440 }
441 }
442 if (argNeedQuotes) {
443 *p++ = '"';
444 }
445 }
446
447 *p = '\0';
448 return 0;
449 }
450
451 /*
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.
455 *
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.
459 */
460 static int assembleEnvBlock(char **envp, char **envBlock)
461 {
462 char *p;
463 char *q;
464 char **env;
465 char *curEnv;
466 char *cwdStart, *cwdEnd;
467 size_t envBlockSize;
468
469 if (envp == NULL) {
470 *envBlock = NULL;
471 return 0;
472 }
473
474 #ifdef WINCE
475 {
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);
482 free(wideCurEnv);
483 }
484 #else
485 curEnv = GetEnvironmentStrings();
486 #endif
487
488 cwdStart = curEnv;
489 while (*cwdStart) {
490 if (cwdStart[0] == '=' && cwdStart[1] != '\0'
491 && cwdStart[2] == ':' && cwdStart[3] == '=') {
492 break;
493 }
494 cwdStart += strlen(cwdStart) + 1;
495 }
496 cwdEnd = cwdStart;
497 if (*cwdEnd) {
498 cwdEnd += strlen(cwdEnd) + 1;
499 while (*cwdEnd) {
500 if (cwdEnd[0] != '=' || cwdEnd[1] == '\0'
501 || cwdEnd[2] != ':' || cwdEnd[3] != '=') {
502 break;
503 }
504 cwdEnd += strlen(cwdEnd) + 1;
505 }
506 }
507 envBlockSize = cwdEnd - cwdStart;
508
509 for (env = envp; *env; env++) {
510 envBlockSize += strlen(*env) + 1;
511 }
512 envBlockSize++;
513
514 p = *envBlock = PR_MALLOC((PRUint32) envBlockSize);
515 if (p == NULL) {
516 #ifdef WINCE
517 PR_Free(curEnv);
518 #else
519 FreeEnvironmentStrings(curEnv);
520 #endif
521 return -1;
522 }
523
524 q = cwdStart;
525 while (q < cwdEnd) {
526 *p++ = *q++;
527 }
528 #ifdef WINCE
529 PR_Free(curEnv);
530 #else
531 FreeEnvironmentStrings(curEnv);
532 #endif
533
534 for (env = envp; *env; env++) {
535 q = *env;
536 while (*q) {
537 *p++ = *q++;
538 }
539 *p++ = '\0';
540 }
541 *p = '\0';
542 return 0;
543 }
544
545 /*
546 * For qsort. We sort (case-insensitive) the environment strings
547 * before generating the environment block.
548 */
549 static int compare(const void *arg1, const void *arg2)
550 {
551 return _stricmp(* (char**)arg1, * (char**)arg2);
552 }
553
554 PRProcess * _PR_CreateWindowsProcess(
555 const char *path,
556 char *const *argv,
557 char *const *envp,
558 const PRProcessAttr *attr)
559 {
560 #ifdef WINCE
561 STARTUPINFOW startupInfo;
562 PRUnichar *wideCmdLine;
563 PRUnichar *wideCwd;
564 int len = 0;
565 #else
566 STARTUPINFO startupInfo;
567 #endif
568 DWORD creationFlags = 0;
569 PROCESS_INFORMATION procInfo;
570 BOOL retVal;
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;
577
578 proc = PR_NEW(PRProcess);
579 if (!proc) {
580 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
581 goto errorExit;
582 }
583
584 if (assembleCmdLine(argv, &cmdLine) == -1) {
585 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
586 goto errorExit;
587 }
588
589 #ifndef WINCE
590 /*
591 * If attr->fdInheritBuffer is not NULL, we need to insert
592 * it into the envp array, so envp cannot be NULL.
593 */
594 hasFdInheritBuffer = (attr && attr->fdInheritBuffer);
595 if ((envp == NULL) && hasFdInheritBuffer) {
596 envp = environ;
597 }
598
599 if (envp != NULL) {
600 int idx;
601 int numEnv;
602 PRBool found = PR_FALSE;
603
604 numEnv = 0;
605 while (envp[numEnv]) {
606 numEnv++;
607 }
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;
614 found = PR_TRUE;
615 }
616 }
617 if (hasFdInheritBuffer && !found) {
618 newEnvp[idx++] = attr->fdInheritBuffer;
619 }
620 newEnvp[idx] = NULL;
621 qsort((void *) newEnvp, (size_t) idx, sizeof(char *), compare);
622 }
623 if (assembleEnvBlock(newEnvp, &envBlock) == -1) {
624 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
625 goto errorExit;
626 }
627
628 ZeroMemory(&startupInfo, sizeof(startupInfo));
629 startupInfo.cb = sizeof(startupInfo);
630
631 if (attr) {
632 PRBool redirected = PR_FALSE;
633
634 /*
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.
638 */
639 startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
640 startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
641 startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
642 if (attr->stdinFd) {
643 startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd;
644 redirected = PR_TRUE;
645 }
646 if (attr->stdoutFd) {
647 startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd;
648 redirected = PR_TRUE;
649 /*
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.
653 */
654 creationFlags |= CREATE_NO_WINDOW;
655 }
656 if (attr->stderrFd) {
657 startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd;
658 redirected = PR_TRUE;
659 }
660 if (redirected) {
661 startupInfo.dwFlags |= STARTF_USESTDHANDLES;
662 }
663 cwd = attr->currentDirectory;
664 }
665 #endif
666
667 #ifdef WINCE
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,
675 wideCmdLine,
676 NULL, /* security attributes for the new
677 * process */
678 NULL, /* security attributes for the primary
679 * thread in the new process */
680 TRUE, /* inherit handles */
681 creationFlags,
682 envBlock, /* an environment block, consisting
683 * of a null-terminated block of
684 * null-terminated strings. Each
685 * string is in the form:
686 * name=value
687 * XXX: usually NULL */
688 wideCwd, /* current drive and directory */
689 &startupInfo,
690 &procInfo
691 );
692 PR_Free(wideCmdLine);
693 PR_Free(wideCwd);
694 #else
695 retVal = CreateProcess(NULL,
696 cmdLine,
697 NULL, /* security attributes for the new
698 * process */
699 NULL, /* security attributes for the primary
700 * thread in the new process */
701 TRUE, /* inherit handles */
702 creationFlags,
703 envBlock, /* an environment block, consisting
704 * of a null-terminated block of
705 * null-terminated strings. Each
706 * string is in the form:
707 * name=value
708 * XXX: usually NULL */
709 cwd, /* current drive and directory */
710 &startupInfo,
711 &procInfo
712 );
713 #endif
714
715 if (retVal == FALSE) {
716 /* XXX what error code? */
717 PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
718 goto errorExit;
719 }
720
721 CloseHandle(procInfo.hThread);
722 proc->md.handle = procInfo.hProcess;
723 proc->md.id = procInfo.dwProcessId;
724
725 PR_DELETE(cmdLine);
726 if (newEnvp) {
727 PR_DELETE(newEnvp);
728 }
729 if (envBlock) {
730 PR_DELETE(envBlock);
731 }
732 return proc;
733
734 errorExit:
735 if (cmdLine) {
736 PR_DELETE(cmdLine);
737 }
738 if (newEnvp) {
739 PR_DELETE(newEnvp);
740 }
741 if (envBlock) {
742 PR_DELETE(envBlock);
743 }
744 if (proc) {
745 PR_DELETE(proc);
746 }
747 return NULL;
748 } /* _PR_CreateWindowsProcess */
749
750 PRStatus _PR_DetachWindowsProcess(PRProcess *process)
751 {
752 CloseHandle(process->md.handle);
753 PR_DELETE(process);
754 return PR_SUCCESS;
755 }
756
757 /*
758 * XXX: This implementation is a temporary quick solution.
759 * It can be called by native threads only (not by fibers).
760 */
761 PRStatus _PR_WaitWindowsProcess(PRProcess *process,
762 PRInt32 *exitCode)
763 {
764 DWORD dwRetVal;
765
766 dwRetVal = WaitForSingleObject(process->md.handle, INFINITE);
767 if (dwRetVal == WAIT_FAILED) {
768 PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
769 return PR_FAILURE;
770 }
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());
775 return PR_FAILURE;
776 }
777 CloseHandle(process->md.handle);
778 PR_DELETE(process);
779 return PR_SUCCESS;
780 }
781
782 PRStatus _PR_KillWindowsProcess(PRProcess *process)
783 {
784 /*
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.
788 */
789 if (TerminateProcess(process->md.handle, 256)) {
790 return PR_SUCCESS;
791 }
792 PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
793 return PR_FAILURE;
794 }
795
796 PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen)
797 {
798 PRIntn rv;
799 PRInt32 syserror;
800
801 rv = gethostname(name, (PRInt32) namelen);
802 if (0 == rv) {
803 return PR_SUCCESS;
804 }
805 syserror = WSAGetLastError();
806 PR_ASSERT(WSANOTINITIALISED != syserror);
807 _PR_MD_MAP_GETHOSTNAME_ERROR(syserror);
808 return PR_FAILURE;
809 }
810
811 PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen)
812 {
813 OSVERSIONINFO osvi;
814
815 PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE));
816
817 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
818 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
819
820 if (! GetVersionEx (&osvi) ) {
821 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
822 return PR_FAILURE;
823 }
824
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);
832 break;
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");
838 else
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);
843 }
844 break;
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);
852 break;
853 #endif
854 default:
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);
859 break;
860 }
861 return PR_SUCCESS;
862 }
863
864 PRStatus _MD_WindowsGetReleaseName(char *name, PRUint32 namelen)
865 {
866 OSVERSIONINFO osvi;
867
868 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
869 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
870
871 if (! GetVersionEx (&osvi) ) {
872 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
873 return PR_FAILURE;
874 }
875
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);
881 break;
882 default:
883 (void)PR_snprintf(name, namelen, "%d.%d",0,0);
884 break;
885 }
886 return PR_SUCCESS;
887 }
888
889 /*
890 **********************************************************************
891 *
892 * Memory-mapped files
893 *
894 **********************************************************************
895 */
896
897 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
898 {
899 DWORD dwHi, dwLo;
900 DWORD flProtect;
901 PROsfd osfd;
902
903 osfd = ( fmap->fd == (PRFileDesc*)-1 )? -1 : fmap->fd->secret->md.osfd;
904
905 dwLo = (DWORD) (size & 0xffffffff);
906 dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
907
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;
914 } else {
915 PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
916 #ifdef WINCE
917 /* WINCE does not have FILE_MAP_COPY. */
918 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
919 return PR_FAILURE;
920 #else
921 flProtect = PAGE_WRITECOPY;
922 fmap->md.dwAccess = FILE_MAP_COPY;
923 #endif
924 }
925
926 fmap->md.hFileMap = CreateFileMapping(
927 (HANDLE) osfd,
928 NULL,
929 flProtect,
930 dwHi,
931 dwLo,
932 NULL);
933
934 if (fmap->md.hFileMap == NULL) {
935 PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
936 return PR_FAILURE;
937 }
938 return PR_SUCCESS;
939 }
940
941 PRInt32 _MD_GetMemMapAlignment(void)
942 {
943 SYSTEM_INFO info;
944 GetSystemInfo(&info);
945 return info.dwAllocationGranularity;
946 }
947
948 extern PRLogModuleInfo *_pr_shma_lm;
949
950 void * _MD_MemMap(
951 PRFileMap *fmap,
952 PROffset64 offset,
953 PRUint32 len)
954 {
955 DWORD dwHi, dwLo;
956 void *addr;
957
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) {
962 {
963 LPVOID lpMsgBuf;
964
965 FormatMessage(
966 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
967 NULL,
968 GetLastError(),
969 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
970 (LPTSTR) &lpMsgBuf,
971 0,
972 NULL
973 );
974 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf ));
975 }
976 PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
977 }
978 return addr;
979 }
980
981 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
982 {
983 if (UnmapViewOfFile(addr)) {
984 return PR_SUCCESS;
985 }
986 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
987 return PR_FAILURE;
988 }
989
990 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
991 {
992 CloseHandle(fmap->md.hFileMap);
993 PR_DELETE(fmap);
994 return PR_SUCCESS;
995 }
996
997 PRStatus _MD_SyncMemMap(
998 PRFileDesc *fd,
999 void *addr,
1000 PRUint32 len)
1001 {
1002 PROsfd osfd = fd->secret->md.osfd;
1003
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.
1008 */
1009 if (FlushViewOfFile(addr, len) && FlushFileBuffers((HANDLE) osfd)) {
1010 return PR_SUCCESS;
1011 }
1012 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
1013 return PR_FAILURE;
1014 }
1015
1016 /*
1017 ***********************************************************************
1018 *
1019 * Atomic increment and decrement operations for x86 processors
1020 *
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.
1026 *
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.
1030 *
1031 ***********************************************************************
1032 */
1033
1034 #if defined(_M_IX86) || defined(_X86_)
1035
1036 #pragma warning(disable: 4035)
1037 PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val)
1038 {
1039 #if defined(__GNUC__)
1040 PRInt32 result;
1041 asm volatile ("lock ; xadd %0, %1"
1042 : "=r"(result), "=m"(*val)
1043 : "0"(1), "m"(*val));
1044 return result + 1;
1045 #else
1046 __asm
1047 {
1048 mov ecx, val
1049 mov eax, 1
1050 lock xadd dword ptr [ecx], eax
1051 inc eax
1052 }
1053 #endif /* __GNUC__ */
1054 }
1055 #pragma warning(default: 4035)
1056
1057 #pragma warning(disable: 4035)
1058 PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val)
1059 {
1060 #if defined(__GNUC__)
1061 PRInt32 result;
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));
1066 return result - 1;
1067 #else
1068 __asm
1069 {
1070 mov ecx, val
1071 mov eax, 0ffffffffh
1072 lock xadd dword ptr [ecx], eax
1073 dec eax
1074 }
1075 #endif /* __GNUC__ */
1076 }
1077 #pragma warning(default: 4035)
1078
1079 #pragma warning(disable: 4035)
1080 PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val)
1081 {
1082 #if defined(__GNUC__)
1083 PRInt32 result;
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;
1089 #else
1090 __asm
1091 {
1092 mov ecx, intp
1093 mov eax, val
1094 mov edx, eax
1095 lock xadd dword ptr [ecx], eax
1096 add eax, edx
1097 }
1098 #endif /* __GNUC__ */
1099 }
1100 #pragma warning(default: 4035)
1101
1102 #ifdef _PR_HAVE_ATOMIC_CAS
1103
1104 #pragma warning(disable: 4035)
1105 void
1106 PR_StackPush(PRStack *stack, PRStackElem *stack_elem)
1107 {
1108 #if defined(__GNUC__)
1109 void **tos = (void **) stack;
1110 void *tmp;
1111
1112 retry:
1113 if (*tos == (void *) -1)
1114 goto retry;
1115
1116 __asm__("xchg %0,%1"
1117 : "=r" (tmp), "=m"(*tos)
1118 : "0" (-1), "m"(*tos));
1119
1120 if (tmp == (void *) -1)
1121 goto retry;
1122
1123 *(void **)stack_elem = tmp;
1124 __asm__("" : : : "memory");
1125 *tos = stack_elem;
1126 #else
1127 __asm
1128 {
1129 mov ebx, stack
1130 mov ecx, stack_elem
1131 retry: mov eax,[ebx]
1132 cmp eax,-1
1133 je retry
1134 mov eax,-1
1135 xchg dword ptr [ebx], eax
1136 cmp eax,-1
1137 je retry
1138 mov [ecx],eax
1139 mov [ebx],ecx
1140 }
1141 #endif /* __GNUC__ */
1142 }
1143 #pragma warning(default: 4035)
1144
1145 #pragma warning(disable: 4035)
1146 PRStackElem *
1147 PR_StackPop(PRStack *stack)
1148 {
1149 #if defined(__GNUC__)
1150 void **tos = (void **) stack;
1151 void *tmp;
1152
1153 retry:
1154 if (*tos == (void *) -1)
1155 goto retry;
1156
1157 __asm__("xchg %0,%1"
1158 : "=r" (tmp), "=m"(*tos)
1159 : "0" (-1), "m"(*tos));
1160
1161 if (tmp == (void *) -1)
1162 goto retry;
1163
1164 if (tmp != (void *) 0)
1165 {
1166 void *next = *(void **)tmp;
1167 *tos = next;
1168 *(void **)tmp = 0;
1169 }
1170 else
1171 *tos = tmp;
1172
1173 return tmp;
1174 #else
1175 __asm
1176 {
1177 mov ebx, stack
1178 retry: mov eax,[ebx]
1179 cmp eax,-1
1180 je retry
1181 mov eax,-1
1182 xchg dword ptr [ebx], eax
1183 cmp eax,-1
1184 je retry
1185 cmp eax,0
1186 je empty
1187 mov ecx,[eax]
1188 mov [ebx],ecx
1189 mov [eax],0
1190 jmp done
1191 empty:
1192 mov [ebx],eax
1193 done:
1194 }
1195 #endif /* __GNUC__ */
1196 }
1197 #pragma warning(default: 4035)
1198
1199 #endif /* _PR_HAVE_ATOMIC_CAS */
1200
1201 #endif /* x86 processors */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)