| OLD | NEW |
| (Empty) |
| 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.dw
MajorVersion, | |
| 831 osvi.dwMinorVers
ion); | |
| 832 break; | |
| 833 case VER_PLATFORM_WIN32_WINDOWS: | |
| 834 if (PR_SI_SYSNAME == cmd) { | |
| 835 if ((osvi.dwMajorVersion > 4) || | |
| 836 ((osvi.dwMajorVersion == 4) && (osvi.dwM
inorVersion > 0))) | |
| 837 (void)PR_snprintf(name, namelen, "Window
s_98"); | |
| 838 else | |
| 839 (void)PR_snprintf(name, namelen, "Window
s_95"); | |
| 840 } else if (PR_SI_RELEASE == cmd) { | |
| 841 (void)PR_snprintf(name, namelen, "%d.%d",osvi.dw
MajorVersion, | |
| 842 osvi.dwMinorVers
ion); | |
| 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.dw
MajorVersion, | |
| 851 osvi.dwMinorVers
ion); | |
| 852 break; | |
| 853 #endif | |
| 854 default: | |
| 855 if (PR_SI_SYSNAME == cmd) | |
| 856 (void)PR_snprintf(name, namelen, "Windows_Unknow
n"); | |
| 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.dwMajorVer
sion, | |
| 880 osvi.dwMinorVers
ion); | |
| 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 } else { | |
| 986 PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); | |
| 987 return PR_FAILURE; | |
| 988 } | |
| 989 } | |
| 990 | |
| 991 PRStatus _MD_CloseFileMap(PRFileMap *fmap) | |
| 992 { | |
| 993 CloseHandle(fmap->md.hFileMap); | |
| 994 PR_DELETE(fmap); | |
| 995 return PR_SUCCESS; | |
| 996 } | |
| 997 | |
| 998 /* | |
| 999 *********************************************************************** | |
| 1000 * | |
| 1001 * Atomic increment and decrement operations for x86 processors | |
| 1002 * | |
| 1003 * We don't use InterlockedIncrement and InterlockedDecrement | |
| 1004 * because on NT 3.51 and Win95, they return a number with | |
| 1005 * the same sign as the incremented/decremented result, rather | |
| 1006 * than the result itself. On NT 4.0 these functions do return | |
| 1007 * the incremented/decremented result. | |
| 1008 * | |
| 1009 * The result is returned in the eax register by the inline | |
| 1010 * assembly code. We disable the harmless "no return value" | |
| 1011 * warning (4035) for these two functions. | |
| 1012 * | |
| 1013 *********************************************************************** | |
| 1014 */ | |
| 1015 | |
| 1016 #if defined(_M_IX86) || defined(_X86_) | |
| 1017 | |
| 1018 #pragma warning(disable: 4035) | |
| 1019 PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val) | |
| 1020 { | |
| 1021 #if defined(__GNUC__) | |
| 1022 PRInt32 result; | |
| 1023 asm volatile ("lock ; xadd %0, %1" | |
| 1024 : "=r"(result), "=m"(*val) | |
| 1025 : "0"(1), "m"(*val)); | |
| 1026 return result + 1; | |
| 1027 #else | |
| 1028 __asm | |
| 1029 { | |
| 1030 mov ecx, val | |
| 1031 mov eax, 1 | |
| 1032 lock xadd dword ptr [ecx], eax | |
| 1033 inc eax | |
| 1034 } | |
| 1035 #endif /* __GNUC__ */ | |
| 1036 } | |
| 1037 #pragma warning(default: 4035) | |
| 1038 | |
| 1039 #pragma warning(disable: 4035) | |
| 1040 PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) | |
| 1041 { | |
| 1042 #if defined(__GNUC__) | |
| 1043 PRInt32 result; | |
| 1044 asm volatile ("lock ; xadd %0, %1" | |
| 1045 : "=r"(result), "=m"(*val) | |
| 1046 : "0"(-1), "m"(*val)); | |
| 1047 //asm volatile("lock ; xadd %0, %1" : "=m" (val), "=a" (result) : "-1" (1)); | |
| 1048 return result - 1; | |
| 1049 #else | |
| 1050 __asm | |
| 1051 { | |
| 1052 mov ecx, val | |
| 1053 mov eax, 0ffffffffh | |
| 1054 lock xadd dword ptr [ecx], eax | |
| 1055 dec eax | |
| 1056 } | |
| 1057 #endif /* __GNUC__ */ | |
| 1058 } | |
| 1059 #pragma warning(default: 4035) | |
| 1060 | |
| 1061 #pragma warning(disable: 4035) | |
| 1062 PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val) | |
| 1063 { | |
| 1064 #if defined(__GNUC__) | |
| 1065 PRInt32 result; | |
| 1066 //asm volatile("lock ; xadd %1, %0" : "=m" (intp), "=a" (result) : "1" (val)); | |
| 1067 asm volatile ("lock ; xadd %0, %1" | |
| 1068 : "=r"(result), "=m"(*intp) | |
| 1069 : "0"(val), "m"(*intp)); | |
| 1070 return result + val; | |
| 1071 #else | |
| 1072 __asm | |
| 1073 { | |
| 1074 mov ecx, intp | |
| 1075 mov eax, val | |
| 1076 mov edx, eax | |
| 1077 lock xadd dword ptr [ecx], eax | |
| 1078 add eax, edx | |
| 1079 } | |
| 1080 #endif /* __GNUC__ */ | |
| 1081 } | |
| 1082 #pragma warning(default: 4035) | |
| 1083 | |
| 1084 #ifdef _PR_HAVE_ATOMIC_CAS | |
| 1085 | |
| 1086 #pragma warning(disable: 4035) | |
| 1087 void | |
| 1088 PR_StackPush(PRStack *stack, PRStackElem *stack_elem) | |
| 1089 { | |
| 1090 #if defined(__GNUC__) | |
| 1091 void **tos = (void **) stack; | |
| 1092 void *tmp; | |
| 1093 | |
| 1094 retry: | |
| 1095 if (*tos == (void *) -1) | |
| 1096 goto retry; | |
| 1097 | |
| 1098 __asm__("xchg %0,%1" | |
| 1099 : "=r" (tmp), "=m"(*tos) | |
| 1100 : "0" (-1), "m"(*tos)); | |
| 1101 | |
| 1102 if (tmp == (void *) -1) | |
| 1103 goto retry; | |
| 1104 | |
| 1105 *(void **)stack_elem = tmp; | |
| 1106 __asm__("" : : : "memory"); | |
| 1107 *tos = stack_elem; | |
| 1108 #else | |
| 1109 __asm | |
| 1110 { | |
| 1111 mov ebx, stack | |
| 1112 mov ecx, stack_elem | |
| 1113 retry: mov eax,[ebx] | |
| 1114 cmp eax,-1 | |
| 1115 je retry | |
| 1116 mov eax,-1 | |
| 1117 xchg dword ptr [ebx], eax | |
| 1118 cmp eax,-1 | |
| 1119 je retry | |
| 1120 mov [ecx],eax | |
| 1121 mov [ebx],ecx | |
| 1122 } | |
| 1123 #endif /* __GNUC__ */ | |
| 1124 } | |
| 1125 #pragma warning(default: 4035) | |
| 1126 | |
| 1127 #pragma warning(disable: 4035) | |
| 1128 PRStackElem * | |
| 1129 PR_StackPop(PRStack *stack) | |
| 1130 { | |
| 1131 #if defined(__GNUC__) | |
| 1132 void **tos = (void **) stack; | |
| 1133 void *tmp; | |
| 1134 | |
| 1135 retry: | |
| 1136 if (*tos == (void *) -1) | |
| 1137 goto retry; | |
| 1138 | |
| 1139 __asm__("xchg %0,%1" | |
| 1140 : "=r" (tmp), "=m"(*tos) | |
| 1141 : "0" (-1), "m"(*tos)); | |
| 1142 | |
| 1143 if (tmp == (void *) -1) | |
| 1144 goto retry; | |
| 1145 | |
| 1146 if (tmp != (void *) 0) | |
| 1147 { | |
| 1148 void *next = *(void **)tmp; | |
| 1149 *tos = next; | |
| 1150 *(void **)tmp = 0; | |
| 1151 } | |
| 1152 else | |
| 1153 *tos = tmp; | |
| 1154 | |
| 1155 return tmp; | |
| 1156 #else | |
| 1157 __asm | |
| 1158 { | |
| 1159 mov ebx, stack | |
| 1160 retry: mov eax,[ebx] | |
| 1161 cmp eax,-1 | |
| 1162 je retry | |
| 1163 mov eax,-1 | |
| 1164 xchg dword ptr [ebx], eax | |
| 1165 cmp eax,-1 | |
| 1166 je retry | |
| 1167 cmp eax,0 | |
| 1168 je empty | |
| 1169 mov ecx,[eax] | |
| 1170 mov [ebx],ecx | |
| 1171 mov [eax],0 | |
| 1172 jmp done | |
| 1173 empty: | |
| 1174 mov [ebx],eax | |
| 1175 done: | |
| 1176 } | |
| 1177 #endif /* __GNUC__ */ | |
| 1178 } | |
| 1179 #pragma warning(default: 4035) | |
| 1180 | |
| 1181 #endif /* _PR_HAVE_ATOMIC_CAS */ | |
| 1182 | |
| 1183 #endif /* x86 processors */ | |
| OLD | NEW |