1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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/
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.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
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
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
36
*------------------------------------------------------------------------
39
* Our wrapped versions of the Unix select() and poll() system calls.
41
*------------------------------------------------------------------------
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() */
56
#include <sys/types.h>
59
#define ZAP_SET(_to, _width) \
62
((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \
67
/* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */
68
static int _pr_xt_hack_fd = -1;
70
int PR_XGetXtHackFD(void)
74
if (_pr_xt_hack_fd == -1) {
76
_pr_xt_hack_fd = fds[0];
79
return _pr_xt_hack_fd;
82
static int (*_pr_xt_hack_okayToReleaseXLock)(void) = 0;
84
void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void))
86
_pr_xt_hack_okayToReleaseXLock = fn;
91
*-----------------------------------------------------------------------
94
* Wrap up the select system call so that we can deschedule
95
* a thread that tries to wait for i/o.
97
*-----------------------------------------------------------------------
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,
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)
112
int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv)
116
_PRUnixPollDesc *unixpds, *unixpd, *eunixpd;
118
PRIntervalTime timeout;
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;
128
* Easy special case: zero timeout. Simply call the native
129
* select() with no fear of blocking.
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);
135
return _MD_SELECT(width, rd, wr, ex, tv);
140
if (!_pr_initialized) {
141
_PR_ImplicitInitialization();
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);
150
if (width < 0 || width > FD_SETSIZE) {
155
/* Compute timeout */
158
* These acceptable ranges for t_sec and t_usec are taken
159
* from the select() man pages.
161
if (tv->tv_sec < 0 || tv->tv_sec > 100000000
162
|| tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
167
/* Convert microseconds to ticks */
168
timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec);
170
/* tv being a NULL pointer means blocking indefinitely */
171
timeout = PR_INTERVAL_NO_TIMEOUT;
174
/* Check for no descriptors case (just doing a timeout) */
175
if ((!rd && !wr && !ex) || !width) {
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.
187
* I allocate an array of size 'width', which is the maximum
188
* number of fds we may need to poll.
190
unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc));
198
for (osfd = 0; osfd < width; osfd++) {
200
if (rd && FD_ISSET(osfd, rd)) {
201
in_flags |= _PR_UNIX_POLL_READ;
203
if (wr && FD_ISSET(osfd, wr)) {
204
in_flags |= _PR_UNIX_POLL_WRITE;
206
if (ex && FD_ISSET(osfd, ex)) {
207
in_flags |= _PR_UNIX_POLL_EXCEPT;
211
unixpd->in_flags = in_flags;
212
unixpd->out_flags = 0;
219
* see comments in mozilla/cmd/xfe/mozilla.c (look for
223
int needToLockXAgain;
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())) {
231
needToLockXAgain = 1;
234
/* This is the potentially blocking step */
235
retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout);
237
if (needToLockXAgain) {
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);
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.
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 */
258
if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) {
260
PR_LOG(_pr_io_lm, PR_LOG_ERROR,
261
("select returns EBADF for %d", unixpd->osfd));
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.
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);
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);
284
if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE)
285
&& (unixpd->out_flags & PR_POLL_EXCEPT)) {
286
FD_SET(unixpd->osfd, ex);
289
PR_ASSERT(nbits > 0);
290
#if defined(HPUX) || defined(SOLARIS) || defined(SUNOS4) || defined(OSF1) || defined(AIX)
299
PR_ASSERT(tv || retVal != 0);
300
PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal));
307
* Redefine poll, when supported on platforms, for local threads
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)
317
#if defined(_PR_POLL_AVAILABLE) && !defined(LINUX)
320
*-----------------------------------------------------------------------
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.
329
*-----------------------------------------------------------------------
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)
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)
349
int poll(struct pollfd *filedes, unsigned long nfds, int timeout)
353
struct pollfd *filedes = (struct pollfd *) listptr;
355
struct pollfd *pfd, *epfd;
356
_PRUnixPollDesc *unixpds, *unixpd, *eunixpd;
357
PRIntervalTime ticks;
362
* Easy special case: zero timeout. Simply call the native
363
* poll() with no fear of blocking.
367
return _MD_POLL(listptr, nfds, timeout);
369
return _MD_POLL(filedes, nfds, timeout);
373
if (!_pr_initialized) {
374
_PR_ImplicitInitialization();
377
#ifndef _PR_LOCAL_THREADS_ONLY
378
if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) {
379
return _MD_POLL(filedes, nfds, timeout);
383
/* We do not support the pollmsg structures on AIX */
385
PR_ASSERT((nfds & 0xff00) == 0);
388
if (timeout < 0 && timeout != -1) {
393
/* Convert timeout from miliseconds to ticks */
395
ticks = PR_INTERVAL_NO_TIMEOUT;
397
ticks = PR_MillisecondsToInterval(timeout);
400
/* Check for no descriptor case (just do a timeout) */
406
unixpds = (_PRUnixPollDesc *)
407
PR_MALLOC(nfds * sizeof(_PRUnixPollDesc));
408
if (NULL == unixpds) {
414
epfd = filedes + nfds;
416
for (pfd = filedes; pfd < epfd; pfd++) {
418
* poll() ignores negative fd's.
421
unixpd->osfd = pfd->fd;
423
unixpd->in_flags = pfd->events;
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)
434
* The output events POLLERR and POLLHUP are never turned on.
435
* POLLNVAL may be turned on.
437
unixpd->in_flags = 0;
438
if (pfd->events & (POLLIN
443
unixpd->in_flags |= _PR_UNIX_POLL_READ;
445
if (pfd->events & (POLLOUT
450
unixpd->in_flags |= _PR_UNIX_POLL_WRITE;
452
if (pfd->events & (POLLPRI
457
unixpd->in_flags |= PR_POLL_EXCEPT;
459
#endif /* _PR_USE_POLL */
460
unixpd->out_flags = 0;
466
ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, ticks);
468
if (PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
469
errno = EINTR; /* XXX we aren't interrupted by a signal, but... */
471
errno = PR_GetOSError();
479
* Copy the out_flags from the _PRUnixPollDesc structures to the
480
* user's pollfd structures and free the allocated memory
483
for (pfd = filedes; pfd < epfd; pfd++) {
487
pfd->revents = unixpd->out_flags;
489
if (0 != unixpd->out_flags) {
490
if (unixpd->out_flags & _PR_UNIX_POLL_READ) {
491
if (pfd->events & POLLIN) {
492
pfd->revents |= POLLIN;
495
if (pfd->events & POLLRDNORM) {
496
pfd->revents |= POLLRDNORM;
500
if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) {
501
if (pfd->events & POLLOUT) {
502
pfd->revents |= POLLOUT;
505
if (pfd->events & POLLWRNORM) {
506
pfd->revents |= POLLWRNORM;
510
if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) {
511
if (pfd->events & POLLPRI) {
512
pfd->revents |= POLLPRI;
515
if (pfd->events & POLLRDBAND) {
516
pfd->revents |= POLLRDBAND;
520
if (unixpd->out_flags & _PR_UNIX_POLL_ERR) {
521
pfd->revents |= POLLERR;
523
if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) {
524
pfd->revents |= POLLNVAL;
526
if (unixpd->out_flags & _PR_UNIX_POLL_HUP) {
527
pfd->revents |= POLLHUP;
530
#endif /* _PR_USE_POLL */
540
#endif /* !defined(LINUX) */
542
#endif /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */