~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/md/unix/uxwrap.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* 
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 * 
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 * 
 
13
 * The Original Code is the Netscape Portable Runtime (NSPR).
 
14
 * 
 
15
 * The Initial Developer of the Original Code is Netscape
 
16
 * Communications Corporation.  Portions created by Netscape are 
 
17
 * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
 
18
 * Rights Reserved.
 
19
 * 
 
20
 * Contributor(s):
 
21
 * 
 
22
 * Alternatively, the contents of this file may be used under the
 
23
 * terms of the GNU General Public License Version 2 or later (the
 
24
 * "GPL"), in which case the provisions of the GPL are applicable 
 
25
 * instead of those above.  If you wish to allow use of your 
 
26
 * version of this file only under the terms of the GPL and not to
 
27
 * allow others to use your version of this file under the MPL,
 
28
 * indicate your decision by deleting the provisions above and
 
29
 * replace them with the notice and other provisions required by
 
30
 * the GPL.  If you do not delete the provisions above, a recipient
 
31
 * may use your version of this file under either the MPL or the
 
32
 * GPL.
 
33
 */
 
34
 
 
35
/*
 
36
 *------------------------------------------------------------------------
 
37
 * File: uxwrap.c
 
38
 *
 
39
 *     Our wrapped versions of the Unix select() and poll() system calls.
 
40
 *
 
41
 *------------------------------------------------------------------------
 
42
 */
 
43
 
 
44
#include "primpl.h"
 
45
 
 
46
#if defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(QNX)
 
47
/* Do not wrap select() and poll(). */
 
48
#else  /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */
 
49
/* The include files for select() */
 
50
#ifdef IRIX
 
51
#include <unistd.h>
 
52
#include <bstring.h>
 
53
#endif
 
54
 
 
55
#include <string.h>
 
56
#include <sys/types.h>
 
57
#include <sys/time.h>
 
58
 
 
59
#define ZAP_SET(_to, _width)                                  \
 
60
    PR_BEGIN_MACRO                                            \
 
61
        memset(_to, 0,                                        \
 
62
               ((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \
 
63
                * sizeof(int)                                 \
 
64
               );                                             \
 
65
    PR_END_MACRO
 
66
 
 
67
/* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */
 
68
static int _pr_xt_hack_fd = -1;
 
69
 
 
70
int PR_XGetXtHackFD(void)
 
71
{
 
72
    int fds[2];
 
73
 
 
74
    if (_pr_xt_hack_fd == -1) {
 
75
        if (!pipe(fds)) {
 
76
            _pr_xt_hack_fd = fds[0];
 
77
        }
 
78
    }
 
79
    return _pr_xt_hack_fd;
 
80
}
 
81
 
 
82
static int (*_pr_xt_hack_okayToReleaseXLock)(void) = 0;
 
83
 
 
84
void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void))
 
85
{
 
86
    _pr_xt_hack_okayToReleaseXLock = fn; 
 
87
}
 
88
 
 
89
 
 
90
/*
 
91
 *-----------------------------------------------------------------------
 
92
 *  select() --
 
93
 *
 
94
 *    Wrap up the select system call so that we can deschedule
 
95
 *    a thread that tries to wait for i/o.
 
96
 *
 
97
 *-----------------------------------------------------------------------
 
98
 */
 
99
 
 
100
#if defined(HPUX9)
 
101
int select(size_t width, int *rl, int *wl, int *el, const struct timeval *tv)
 
102
#elif defined(NEXTSTEP)
 
103
int wrap_select(int width, fd_set *rd, fd_set *wr, fd_set *ex,
 
104
        const struct timeval *tv)
 
105
#elif defined(AIX_RENAME_SELECT)
 
106
int wrap_select(unsigned long width, void *rl, void *wl, void *el,
 
107
        struct timeval *tv)
 
108
#elif defined(_PR_SELECT_CONST_TIMEVAL)
 
109
int select(int width, fd_set *rd, fd_set *wr, fd_set *ex,
 
110
        const struct timeval *tv)
 
111
#else
 
112
int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv)
 
113
#endif
 
114
{
 
115
    int osfd;
 
116
    _PRUnixPollDesc *unixpds, *unixpd, *eunixpd;
 
117
    PRInt32 pdcnt;
 
118
    PRIntervalTime timeout;
 
119
    int retVal;
 
120
#if defined(HPUX9) || defined(AIX_RENAME_SELECT)
 
121
    fd_set *rd = (fd_set*) rl;
 
122
    fd_set *wr = (fd_set*) wl;
 
123
    fd_set *ex = (fd_set*) el;
 
124
#endif
 
125
 
 
126
#if 0
 
127
    /*
 
128
     * Easy special case: zero timeout.  Simply call the native
 
129
     * select() with no fear of blocking.
 
130
     */
 
131
    if (tv != NULL && tv->tv_sec == 0 && tv->tv_usec == 0) {
 
132
#if defined(HPUX9) || defined(AIX_RENAME_SELECT)
 
133
        return _MD_SELECT(width, rl, wl, el, tv);
 
134
#else
 
135
        return _MD_SELECT(width, rd, wr, ex, tv);
 
136
#endif
 
137
    }
 
138
#endif
 
139
 
 
140
    if (!_pr_initialized) {
 
141
        _PR_ImplicitInitialization();
 
142
    }
 
143
                
 
144
#ifndef _PR_LOCAL_THREADS_ONLY
 
145
    if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) {
 
146
        return _MD_SELECT(width, rd, wr, ex, tv);       
 
147
    }
 
148
#endif
 
149
 
 
150
    if (width < 0 || width > FD_SETSIZE) {
 
151
        errno = EINVAL;
 
152
        return -1;
 
153
    }
 
154
 
 
155
    /* Compute timeout */
 
156
    if (tv) {
 
157
        /*
 
158
         * These acceptable ranges for t_sec and t_usec are taken
 
159
         * from the select() man pages.
 
160
         */
 
161
        if (tv->tv_sec < 0 || tv->tv_sec > 100000000
 
162
                || tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
 
163
            errno = EINVAL;
 
164
            return -1;
 
165
        }
 
166
 
 
167
        /* Convert microseconds to ticks */
 
168
        timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec);
 
169
    } else {
 
170
        /* tv being a NULL pointer means blocking indefinitely */
 
171
        timeout = PR_INTERVAL_NO_TIMEOUT;
 
172
    }
 
173
 
 
174
    /* Check for no descriptors case (just doing a timeout) */
 
175
    if ((!rd && !wr && !ex) || !width) {
 
176
        PR_Sleep(timeout);
 
177
        return 0;
 
178
    }
 
179
 
 
180
    /*
 
181
     * Set up for PR_Poll().  The PRPollDesc array is allocated
 
182
     * dynamically.  If this turns out to have high performance
 
183
     * penalty, one can change to use a large PRPollDesc array
 
184
     * on the stack, and allocate dynamically only when it turns
 
185
     * out to be not large enough.
 
186
     *
 
187
     * I allocate an array of size 'width', which is the maximum
 
188
     * number of fds we may need to poll.
 
189
     */
 
190
    unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc));
 
191
    if (!unixpds) {
 
192
        errno = ENOMEM;
 
193
        return -1;
 
194
    }
 
195
 
 
196
    pdcnt = 0;
 
197
    unixpd = unixpds;
 
198
    for (osfd = 0; osfd < width; osfd++) {
 
199
        int in_flags = 0;
 
200
        if (rd && FD_ISSET(osfd, rd)) {
 
201
            in_flags |= _PR_UNIX_POLL_READ;
 
202
        }
 
203
        if (wr && FD_ISSET(osfd, wr)) {
 
204
            in_flags |= _PR_UNIX_POLL_WRITE;
 
205
        }
 
206
        if (ex && FD_ISSET(osfd, ex)) {
 
207
            in_flags |= _PR_UNIX_POLL_EXCEPT;
 
208
        }
 
209
        if (in_flags) {
 
210
            unixpd->osfd = osfd;
 
211
            unixpd->in_flags = in_flags;
 
212
            unixpd->out_flags = 0;
 
213
            unixpd++;
 
214
            pdcnt++;
 
215
        }
 
216
    }
 
217
 
 
218
    /*
 
219
     * see comments in mozilla/cmd/xfe/mozilla.c (look for
 
220
     * "PR_XGetXtHackFD")
 
221
     */
 
222
   {
 
223
     int needToLockXAgain;
 
224
 
 
225
     needToLockXAgain = 0;
 
226
     if (rd && (_pr_xt_hack_fd != -1)
 
227
             && FD_ISSET(_pr_xt_hack_fd, rd) && PR_XIsLocked()
 
228
             && (!_pr_xt_hack_okayToReleaseXLock
 
229
             || _pr_xt_hack_okayToReleaseXLock())) {
 
230
         PR_XUnlock();
 
231
         needToLockXAgain = 1;
 
232
     }
 
233
 
 
234
    /* This is the potentially blocking step */
 
235
    retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout);
 
236
 
 
237
     if (needToLockXAgain) {
 
238
         PR_XLock();
 
239
     }
 
240
   }
 
241
 
 
242
    if (retVal > 0) {
 
243
        /* Compute select results */
 
244
        if (rd) ZAP_SET(rd, width);
 
245
        if (wr) ZAP_SET(wr, width);
 
246
        if (ex) ZAP_SET(ex, width);
 
247
 
 
248
        /*
 
249
         * The return value can be either the number of ready file
 
250
         * descriptors or the number of set bits in the three fd_set's.
 
251
         */
 
252
        retVal = 0;  /* we're going to recompute */
 
253
        eunixpd = unixpds + pdcnt;
 
254
        for (unixpd = unixpds; unixpd < eunixpd; unixpd++) {
 
255
            if (unixpd->out_flags) {
 
256
                int nbits = 0;  /* The number of set bits on for this fd */
 
257
 
 
258
                if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) {
 
259
                    errno = EBADF;
 
260
                    PR_LOG(_pr_io_lm, PR_LOG_ERROR,
 
261
                            ("select returns EBADF for %d", unixpd->osfd));
 
262
                    retVal = -1;
 
263
                    break;
 
264
                }
 
265
                /*
 
266
                 * If a socket has a pending error, it is considered
 
267
                 * both readable and writable.  (See W. Richard Stevens,
 
268
                 * Unix Network Programming, Vol. 1, 2nd Ed., Section 6.3,
 
269
                 * pp. 153-154.)  We also consider a socket readable if
 
270
                 * it has a hangup condition.
 
271
                 */
 
272
                if (rd && (unixpd->in_flags & _PR_UNIX_POLL_READ)
 
273
                        && (unixpd->out_flags & (_PR_UNIX_POLL_READ
 
274
                        | _PR_UNIX_POLL_ERR | _PR_UNIX_POLL_HUP))) {
 
275
                    FD_SET(unixpd->osfd, rd);
 
276
                    nbits++;
 
277
                }
 
278
                if (wr && (unixpd->in_flags & _PR_UNIX_POLL_WRITE)
 
279
                        && (unixpd->out_flags & (_PR_UNIX_POLL_WRITE
 
280
                        | _PR_UNIX_POLL_ERR))) {
 
281
                    FD_SET(unixpd->osfd, wr);
 
282
                    nbits++;
 
283
                }
 
284
                if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE)
 
285
                        && (unixpd->out_flags & PR_POLL_EXCEPT)) {
 
286
                    FD_SET(unixpd->osfd, ex);
 
287
                    nbits++;
 
288
                }
 
289
                PR_ASSERT(nbits > 0);
 
290
#if defined(HPUX) || defined(SOLARIS) || defined(SUNOS4) || defined(OSF1) || defined(AIX)
 
291
                retVal += nbits;
 
292
#else /* IRIX */
 
293
                retVal += 1;
 
294
#endif
 
295
            }
 
296
        }
 
297
    }
 
298
 
 
299
    PR_ASSERT(tv || retVal != 0);
 
300
    PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal));
 
301
    PR_DELETE(unixpds);
 
302
 
 
303
    return retVal;
 
304
}
 
305
 
 
306
/*
 
307
 * Redefine poll, when supported on platforms, for local threads
 
308
 */
 
309
 
 
310
/*
 
311
 * I am commenting out the poll() wrapper for Linux for now
 
312
 * because it is difficult to define _MD_POLL that works on all
 
313
 * Linux varieties.  People reported that glibc 2.0.7 on Debian
 
314
 * 2.0 Linux machines doesn't have the __syscall_poll symbol
 
315
 * defined.  (WTC 30 Nov. 1998)
 
316
 */
 
317
#if defined(_PR_POLL_AVAILABLE) && !defined(LINUX)
 
318
 
 
319
/*
 
320
 *-----------------------------------------------------------------------
 
321
 * poll() --
 
322
 *
 
323
 * RETURN VALUES: 
 
324
 *     -1:  fails, errno indicates the error.
 
325
 *      0:  timed out, the revents bitmasks are not set.
 
326
 *      positive value: the number of file descriptors for which poll()
 
327
 *          has set the revents bitmask.
 
328
 *
 
329
 *-----------------------------------------------------------------------
 
330
 */
 
331
 
 
332
#include <poll.h>
 
333
 
 
334
#if defined(AIX_RENAME_SELECT)
 
335
int wrap_poll(void *listptr, unsigned long nfds, long timeout)
 
336
#elif (defined(AIX) && !defined(AIX_RENAME_SELECT))
 
337
int poll(void *listptr, unsigned long nfds, long timeout)
 
338
#elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9))
 
339
int poll(struct pollfd filedes[], unsigned int nfds, int timeout)
 
340
#elif defined(HPUX9)
 
341
int poll(struct pollfd filedes[], int nfds, int timeout)
 
342
#elif defined(NETBSD)
 
343
int poll(struct pollfd *filedes, nfds_t nfds, int timeout)
 
344
#elif defined(OPENBSD)
 
345
int poll(struct pollfd *filedes, int nfds, int timeout)
 
346
#elif defined(FREEBSD)
 
347
int poll(struct pollfd *filedes, unsigned nfds, int timeout)
 
348
#else
 
349
int poll(struct pollfd *filedes, unsigned long nfds, int timeout)
 
350
#endif
 
351
{
 
352
#ifdef AIX
 
353
    struct pollfd *filedes = (struct pollfd *) listptr;
 
354
#endif
 
355
    struct pollfd *pfd, *epfd;
 
356
    _PRUnixPollDesc *unixpds, *unixpd, *eunixpd;
 
357
    PRIntervalTime ticks;
 
358
    PRInt32 pdcnt;
 
359
    int ready;
 
360
 
 
361
    /*
 
362
     * Easy special case: zero timeout.  Simply call the native
 
363
     * poll() with no fear of blocking.
 
364
     */
 
365
    if (timeout == 0) {
 
366
#if defined(AIX)
 
367
        return _MD_POLL(listptr, nfds, timeout);
 
368
#else
 
369
        return _MD_POLL(filedes, nfds, timeout);
 
370
#endif
 
371
    }
 
372
 
 
373
    if (!_pr_initialized) {
 
374
        _PR_ImplicitInitialization();
 
375
    }
 
376
 
 
377
#ifndef _PR_LOCAL_THREADS_ONLY
 
378
    if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) {
 
379
        return _MD_POLL(filedes, nfds, timeout);
 
380
    }
 
381
#endif
 
382
 
 
383
    /* We do not support the pollmsg structures on AIX */
 
384
#ifdef AIX
 
385
    PR_ASSERT((nfds & 0xff00) == 0);
 
386
#endif
 
387
 
 
388
    if (timeout < 0 && timeout != -1) {
 
389
        errno = EINVAL;
 
390
        return -1;
 
391
    }
 
392
 
 
393
    /* Convert timeout from miliseconds to ticks */
 
394
    if (timeout == -1) {
 
395
        ticks = PR_INTERVAL_NO_TIMEOUT;
 
396
    } else {
 
397
        ticks = PR_MillisecondsToInterval(timeout);
 
398
    }
 
399
 
 
400
    /* Check for no descriptor case (just do a timeout) */
 
401
    if (nfds == 0) {
 
402
        PR_Sleep(ticks);
 
403
        return 0;
 
404
    }
 
405
 
 
406
    unixpds = (_PRUnixPollDesc *)
 
407
            PR_MALLOC(nfds * sizeof(_PRUnixPollDesc));
 
408
    if (NULL == unixpds) {
 
409
        errno = EAGAIN;
 
410
        return -1;
 
411
    }
 
412
 
 
413
    pdcnt = 0;
 
414
    epfd = filedes + nfds;
 
415
    unixpd = unixpds;
 
416
    for (pfd = filedes; pfd < epfd; pfd++) {
 
417
        /*
 
418
         * poll() ignores negative fd's.
 
419
         */
 
420
        if (pfd->fd >= 0) {
 
421
            unixpd->osfd = pfd->fd;
 
422
#ifdef _PR_USE_POLL
 
423
            unixpd->in_flags = pfd->events;
 
424
#else
 
425
            /*
 
426
             * Map the poll events to one of the three that can be
 
427
             * represented by the select fd_sets:
 
428
             *     POLLIN, POLLRDNORM  ===> readable
 
429
             *     POLLOUT, POLLWRNORM ===> writable
 
430
             *     POLLPRI, POLLRDBAND ===> exception
 
431
             *     POLLNORM, POLLWRBAND (and POLLMSG on some platforms)
 
432
             *     are ignored.
 
433
             *
 
434
             * The output events POLLERR and POLLHUP are never turned on.
 
435
             * POLLNVAL may be turned on.
 
436
             */
 
437
            unixpd->in_flags = 0;
 
438
            if (pfd->events & (POLLIN
 
439
#ifdef POLLRDNORM
 
440
                    | POLLRDNORM
 
441
#endif
 
442
                    )) {
 
443
                unixpd->in_flags |= _PR_UNIX_POLL_READ;
 
444
            }
 
445
            if (pfd->events & (POLLOUT
 
446
#ifdef POLLWRNORM
 
447
                    | POLLWRNORM
 
448
#endif
 
449
                    )) {
 
450
                unixpd->in_flags |= _PR_UNIX_POLL_WRITE;
 
451
            }
 
452
            if (pfd->events & (POLLPRI
 
453
#ifdef POLLRDBAND
 
454
                    | POLLRDBAND
 
455
#endif
 
456
                    )) {
 
457
                unixpd->in_flags |= PR_POLL_EXCEPT;
 
458
            }
 
459
#endif  /* _PR_USE_POLL */
 
460
            unixpd->out_flags = 0;
 
461
            unixpd++;
 
462
            pdcnt++;
 
463
        }
 
464
    }
 
465
 
 
466
    ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, ticks);
 
467
    if (-1 == ready) {
 
468
        if (PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
 
469
            errno = EINTR;  /* XXX we aren't interrupted by a signal, but... */
 
470
        } else {
 
471
            errno = PR_GetOSError();
 
472
        }
 
473
    }
 
474
    if (ready <= 0) {
 
475
        goto done;
 
476
    }
 
477
 
 
478
    /*
 
479
     * Copy the out_flags from the _PRUnixPollDesc structures to the
 
480
     * user's pollfd structures and free the allocated memory
 
481
     */
 
482
    unixpd = unixpds;
 
483
    for (pfd = filedes; pfd < epfd; pfd++) {
 
484
        pfd->revents = 0;
 
485
        if (pfd->fd >= 0) {
 
486
#ifdef _PR_USE_POLL
 
487
            pfd->revents = unixpd->out_flags;
 
488
#else
 
489
            if (0 != unixpd->out_flags) {
 
490
                if (unixpd->out_flags & _PR_UNIX_POLL_READ) {
 
491
                    if (pfd->events & POLLIN) {
 
492
                        pfd->revents |= POLLIN;
 
493
                    }
 
494
#ifdef POLLRDNORM
 
495
                    if (pfd->events & POLLRDNORM) {
 
496
                        pfd->revents |= POLLRDNORM;
 
497
                    }
 
498
#endif
 
499
                }
 
500
                if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) {
 
501
                    if (pfd->events & POLLOUT) {
 
502
                        pfd->revents |= POLLOUT;
 
503
                    }
 
504
#ifdef POLLWRNORM
 
505
                    if (pfd->events & POLLWRNORM) {
 
506
                        pfd->revents |= POLLWRNORM;
 
507
                    }
 
508
#endif
 
509
                }
 
510
                if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) {
 
511
                    if (pfd->events & POLLPRI) {
 
512
                        pfd->revents |= POLLPRI;
 
513
                    }
 
514
#ifdef POLLRDBAND
 
515
                    if (pfd->events & POLLRDBAND) {
 
516
                        pfd->revents |= POLLRDBAND;
 
517
                    }
 
518
#endif
 
519
                }
 
520
                if (unixpd->out_flags & _PR_UNIX_POLL_ERR) {
 
521
                    pfd->revents |= POLLERR;
 
522
                }
 
523
                if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) {
 
524
                    pfd->revents |= POLLNVAL;
 
525
                }
 
526
                if (unixpd->out_flags & _PR_UNIX_POLL_HUP) {
 
527
                    pfd->revents |= POLLHUP;
 
528
                }
 
529
            }
 
530
#endif  /* _PR_USE_POLL */
 
531
            unixpd++;
 
532
        }
 
533
    }
 
534
 
 
535
done:
 
536
    PR_DELETE(unixpds);
 
537
    return ready;
 
538
}
 
539
 
 
540
#endif  /* !defined(LINUX) */
 
541
 
 
542
#endif  /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */
 
543
 
 
544
/* uxwrap.c */
 
545