~ubuntu-branches/ubuntu/lucid/nspr/lucid-updates

« back to all changes in this revision

Viewing changes to nspr/pr/src/md/windows/ntmisc.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2014-09-19 08:25:13 UTC
  • mfrom: (1.2.6)
  • Revision ID: package-import@ubuntu.com-20140919082513-ldt99o79f1yggc7e
Tags: 4.10.7-0ubuntu0.10.04.1
* Update to 4.10.7 to support nss security update.
* Removed unneeded patches:
  - debian/patches/30_config_64bits.patch: no longer needed
  - debian/patches/99_configure.patch: no longer needed
  - debian/patches/CVE-2013-5607.patch: included upstream.
  - debian/patches/CVE-2014-1545.patch: included upstream.
* debian/libnspr4-0d.symbols: updated for new version.
* debian/rules: adjust paths, add --enable-64bit when appropriate.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 */