Mercurial > trustbridge > nss-cmake-static
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(¤tTime.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 */ |