1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/md/unix/uxwrap.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,513 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + *------------------------------------------------------------------------ 1.11 + * File: uxwrap.c 1.12 + * 1.13 + * Our wrapped versions of the Unix select() and poll() system calls. 1.14 + * 1.15 + *------------------------------------------------------------------------ 1.16 + */ 1.17 + 1.18 +#include "primpl.h" 1.19 + 1.20 +#if defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(QNX) 1.21 +/* Do not wrap select() and poll(). */ 1.22 +#else /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */ 1.23 +/* The include files for select() */ 1.24 +#ifdef IRIX 1.25 +#include <unistd.h> 1.26 +#include <bstring.h> 1.27 +#endif 1.28 + 1.29 +#include <string.h> 1.30 +#include <sys/types.h> 1.31 +#include <sys/time.h> 1.32 + 1.33 +#define ZAP_SET(_to, _width) \ 1.34 + PR_BEGIN_MACRO \ 1.35 + memset(_to, 0, \ 1.36 + ((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \ 1.37 + * sizeof(int) \ 1.38 + ); \ 1.39 + PR_END_MACRO 1.40 + 1.41 +/* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */ 1.42 +static int _pr_xt_hack_fd = -1; 1.43 + 1.44 +int PR_XGetXtHackFD(void) 1.45 +{ 1.46 + int fds[2]; 1.47 + 1.48 + if (_pr_xt_hack_fd == -1) { 1.49 + if (!pipe(fds)) { 1.50 + _pr_xt_hack_fd = fds[0]; 1.51 + } 1.52 + } 1.53 + return _pr_xt_hack_fd; 1.54 +} 1.55 + 1.56 +static int (*_pr_xt_hack_okayToReleaseXLock)(void) = 0; 1.57 + 1.58 +void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void)) 1.59 +{ 1.60 + _pr_xt_hack_okayToReleaseXLock = fn; 1.61 +} 1.62 + 1.63 + 1.64 +/* 1.65 + *----------------------------------------------------------------------- 1.66 + * select() -- 1.67 + * 1.68 + * Wrap up the select system call so that we can deschedule 1.69 + * a thread that tries to wait for i/o. 1.70 + * 1.71 + *----------------------------------------------------------------------- 1.72 + */ 1.73 + 1.74 +#if defined(HPUX9) 1.75 +int select(size_t width, int *rl, int *wl, int *el, const struct timeval *tv) 1.76 +#elif defined(AIX_RENAME_SELECT) 1.77 +int wrap_select(unsigned long width, void *rl, void *wl, void *el, 1.78 + struct timeval *tv) 1.79 +#elif defined(_PR_SELECT_CONST_TIMEVAL) 1.80 +int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, 1.81 + const struct timeval *tv) 1.82 +#else 1.83 +int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) 1.84 +#endif 1.85 +{ 1.86 + int osfd; 1.87 + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; 1.88 + PRInt32 pdcnt; 1.89 + PRIntervalTime timeout; 1.90 + int retVal; 1.91 +#if defined(HPUX9) || defined(AIX_RENAME_SELECT) 1.92 + fd_set *rd = (fd_set*) rl; 1.93 + fd_set *wr = (fd_set*) wl; 1.94 + fd_set *ex = (fd_set*) el; 1.95 +#endif 1.96 + 1.97 +#if 0 1.98 + /* 1.99 + * Easy special case: zero timeout. Simply call the native 1.100 + * select() with no fear of blocking. 1.101 + */ 1.102 + if (tv != NULL && tv->tv_sec == 0 && tv->tv_usec == 0) { 1.103 +#if defined(HPUX9) || defined(AIX_RENAME_SELECT) 1.104 + return _MD_SELECT(width, rl, wl, el, tv); 1.105 +#else 1.106 + return _MD_SELECT(width, rd, wr, ex, tv); 1.107 +#endif 1.108 + } 1.109 +#endif 1.110 + 1.111 + if (!_pr_initialized) { 1.112 + _PR_ImplicitInitialization(); 1.113 + } 1.114 + 1.115 +#ifndef _PR_LOCAL_THREADS_ONLY 1.116 + if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { 1.117 + return _MD_SELECT(width, rd, wr, ex, tv); 1.118 + } 1.119 +#endif 1.120 + 1.121 + if (width < 0 || width > FD_SETSIZE) { 1.122 + errno = EINVAL; 1.123 + return -1; 1.124 + } 1.125 + 1.126 + /* Compute timeout */ 1.127 + if (tv) { 1.128 + /* 1.129 + * These acceptable ranges for t_sec and t_usec are taken 1.130 + * from the select() man pages. 1.131 + */ 1.132 + if (tv->tv_sec < 0 || tv->tv_sec > 100000000 1.133 + || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { 1.134 + errno = EINVAL; 1.135 + return -1; 1.136 + } 1.137 + 1.138 + /* Convert microseconds to ticks */ 1.139 + timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec); 1.140 + } else { 1.141 + /* tv being a NULL pointer means blocking indefinitely */ 1.142 + timeout = PR_INTERVAL_NO_TIMEOUT; 1.143 + } 1.144 + 1.145 + /* Check for no descriptors case (just doing a timeout) */ 1.146 + if ((!rd && !wr && !ex) || !width) { 1.147 + PR_Sleep(timeout); 1.148 + return 0; 1.149 + } 1.150 + 1.151 + /* 1.152 + * Set up for PR_Poll(). The PRPollDesc array is allocated 1.153 + * dynamically. If this turns out to have high performance 1.154 + * penalty, one can change to use a large PRPollDesc array 1.155 + * on the stack, and allocate dynamically only when it turns 1.156 + * out to be not large enough. 1.157 + * 1.158 + * I allocate an array of size 'width', which is the maximum 1.159 + * number of fds we may need to poll. 1.160 + */ 1.161 + unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc)); 1.162 + if (!unixpds) { 1.163 + errno = ENOMEM; 1.164 + return -1; 1.165 + } 1.166 + 1.167 + pdcnt = 0; 1.168 + unixpd = unixpds; 1.169 + for (osfd = 0; osfd < width; osfd++) { 1.170 + int in_flags = 0; 1.171 + if (rd && FD_ISSET(osfd, rd)) { 1.172 + in_flags |= _PR_UNIX_POLL_READ; 1.173 + } 1.174 + if (wr && FD_ISSET(osfd, wr)) { 1.175 + in_flags |= _PR_UNIX_POLL_WRITE; 1.176 + } 1.177 + if (ex && FD_ISSET(osfd, ex)) { 1.178 + in_flags |= _PR_UNIX_POLL_EXCEPT; 1.179 + } 1.180 + if (in_flags) { 1.181 + unixpd->osfd = osfd; 1.182 + unixpd->in_flags = in_flags; 1.183 + unixpd->out_flags = 0; 1.184 + unixpd++; 1.185 + pdcnt++; 1.186 + } 1.187 + } 1.188 + 1.189 + /* 1.190 + * see comments in mozilla/cmd/xfe/mozilla.c (look for 1.191 + * "PR_XGetXtHackFD") 1.192 + */ 1.193 + { 1.194 + int needToLockXAgain; 1.195 + 1.196 + needToLockXAgain = 0; 1.197 + if (rd && (_pr_xt_hack_fd != -1) 1.198 + && FD_ISSET(_pr_xt_hack_fd, rd) && PR_XIsLocked() 1.199 + && (!_pr_xt_hack_okayToReleaseXLock 1.200 + || _pr_xt_hack_okayToReleaseXLock())) { 1.201 + PR_XUnlock(); 1.202 + needToLockXAgain = 1; 1.203 + } 1.204 + 1.205 + /* This is the potentially blocking step */ 1.206 + retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); 1.207 + 1.208 + if (needToLockXAgain) { 1.209 + PR_XLock(); 1.210 + } 1.211 + } 1.212 + 1.213 + if (retVal > 0) { 1.214 + /* Compute select results */ 1.215 + if (rd) ZAP_SET(rd, width); 1.216 + if (wr) ZAP_SET(wr, width); 1.217 + if (ex) ZAP_SET(ex, width); 1.218 + 1.219 + /* 1.220 + * The return value can be either the number of ready file 1.221 + * descriptors or the number of set bits in the three fd_set's. 1.222 + */ 1.223 + retVal = 0; /* we're going to recompute */ 1.224 + eunixpd = unixpds + pdcnt; 1.225 + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { 1.226 + if (unixpd->out_flags) { 1.227 + int nbits = 0; /* The number of set bits on for this fd */ 1.228 + 1.229 + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { 1.230 + errno = EBADF; 1.231 + PR_LOG(_pr_io_lm, PR_LOG_ERROR, 1.232 + ("select returns EBADF for %d", unixpd->osfd)); 1.233 + retVal = -1; 1.234 + break; 1.235 + } 1.236 + /* 1.237 + * If a socket has a pending error, it is considered 1.238 + * both readable and writable. (See W. Richard Stevens, 1.239 + * Unix Network Programming, Vol. 1, 2nd Ed., Section 6.3, 1.240 + * pp. 153-154.) We also consider a socket readable if 1.241 + * it has a hangup condition. 1.242 + */ 1.243 + if (rd && (unixpd->in_flags & _PR_UNIX_POLL_READ) 1.244 + && (unixpd->out_flags & (_PR_UNIX_POLL_READ 1.245 + | _PR_UNIX_POLL_ERR | _PR_UNIX_POLL_HUP))) { 1.246 + FD_SET(unixpd->osfd, rd); 1.247 + nbits++; 1.248 + } 1.249 + if (wr && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) 1.250 + && (unixpd->out_flags & (_PR_UNIX_POLL_WRITE 1.251 + | _PR_UNIX_POLL_ERR))) { 1.252 + FD_SET(unixpd->osfd, wr); 1.253 + nbits++; 1.254 + } 1.255 + if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) 1.256 + && (unixpd->out_flags & PR_POLL_EXCEPT)) { 1.257 + FD_SET(unixpd->osfd, ex); 1.258 + nbits++; 1.259 + } 1.260 + PR_ASSERT(nbits > 0); 1.261 +#if defined(HPUX) || defined(SOLARIS) || defined(OSF1) || defined(AIX) 1.262 + retVal += nbits; 1.263 +#else /* IRIX */ 1.264 + retVal += 1; 1.265 +#endif 1.266 + } 1.267 + } 1.268 + } 1.269 + 1.270 + PR_ASSERT(tv || retVal != 0); 1.271 + PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal)); 1.272 + PR_DELETE(unixpds); 1.273 + 1.274 + return retVal; 1.275 +} 1.276 + 1.277 +/* 1.278 + * Redefine poll, when supported on platforms, for local threads 1.279 + */ 1.280 + 1.281 +/* 1.282 + * I am commenting out the poll() wrapper for Linux for now 1.283 + * because it is difficult to define _MD_POLL that works on all 1.284 + * Linux varieties. People reported that glibc 2.0.7 on Debian 1.285 + * 2.0 Linux machines doesn't have the __syscall_poll symbol 1.286 + * defined. (WTC 30 Nov. 1998) 1.287 + */ 1.288 +#if defined(_PR_POLL_AVAILABLE) && !defined(LINUX) 1.289 + 1.290 +/* 1.291 + *----------------------------------------------------------------------- 1.292 + * poll() -- 1.293 + * 1.294 + * RETURN VALUES: 1.295 + * -1: fails, errno indicates the error. 1.296 + * 0: timed out, the revents bitmasks are not set. 1.297 + * positive value: the number of file descriptors for which poll() 1.298 + * has set the revents bitmask. 1.299 + * 1.300 + *----------------------------------------------------------------------- 1.301 + */ 1.302 + 1.303 +#include <poll.h> 1.304 + 1.305 +#if defined(AIX_RENAME_SELECT) 1.306 +int wrap_poll(void *listptr, unsigned long nfds, long timeout) 1.307 +#elif (defined(AIX) && !defined(AIX_RENAME_SELECT)) 1.308 +int poll(void *listptr, unsigned long nfds, long timeout) 1.309 +#elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9)) 1.310 +int poll(struct pollfd filedes[], unsigned int nfds, int timeout) 1.311 +#elif defined(HPUX9) 1.312 +int poll(struct pollfd filedes[], int nfds, int timeout) 1.313 +#elif defined(NETBSD) 1.314 +int poll(struct pollfd *filedes, nfds_t nfds, int timeout) 1.315 +#elif defined(OPENBSD) 1.316 +int poll(struct pollfd filedes[], nfds_t nfds, int timeout) 1.317 +#elif defined(FREEBSD) 1.318 +int poll(struct pollfd *filedes, unsigned nfds, int timeout) 1.319 +#else 1.320 +int poll(struct pollfd *filedes, unsigned long nfds, int timeout) 1.321 +#endif 1.322 +{ 1.323 +#ifdef AIX 1.324 + struct pollfd *filedes = (struct pollfd *) listptr; 1.325 +#endif 1.326 + struct pollfd *pfd, *epfd; 1.327 + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; 1.328 + PRIntervalTime ticks; 1.329 + PRInt32 pdcnt; 1.330 + int ready; 1.331 + 1.332 + /* 1.333 + * Easy special case: zero timeout. Simply call the native 1.334 + * poll() with no fear of blocking. 1.335 + */ 1.336 + if (timeout == 0) { 1.337 +#if defined(AIX) 1.338 + return _MD_POLL(listptr, nfds, timeout); 1.339 +#else 1.340 + return _MD_POLL(filedes, nfds, timeout); 1.341 +#endif 1.342 + } 1.343 + 1.344 + if (!_pr_initialized) { 1.345 + _PR_ImplicitInitialization(); 1.346 + } 1.347 + 1.348 +#ifndef _PR_LOCAL_THREADS_ONLY 1.349 + if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { 1.350 + return _MD_POLL(filedes, nfds, timeout); 1.351 + } 1.352 +#endif 1.353 + 1.354 + /* We do not support the pollmsg structures on AIX */ 1.355 +#ifdef AIX 1.356 + PR_ASSERT((nfds & 0xff00) == 0); 1.357 +#endif 1.358 + 1.359 + if (timeout < 0 && timeout != -1) { 1.360 + errno = EINVAL; 1.361 + return -1; 1.362 + } 1.363 + 1.364 + /* Convert timeout from miliseconds to ticks */ 1.365 + if (timeout == -1) { 1.366 + ticks = PR_INTERVAL_NO_TIMEOUT; 1.367 + } else { 1.368 + ticks = PR_MillisecondsToInterval(timeout); 1.369 + } 1.370 + 1.371 + /* Check for no descriptor case (just do a timeout) */ 1.372 + if (nfds == 0) { 1.373 + PR_Sleep(ticks); 1.374 + return 0; 1.375 + } 1.376 + 1.377 + unixpds = (_PRUnixPollDesc *) 1.378 + PR_MALLOC(nfds * sizeof(_PRUnixPollDesc)); 1.379 + if (NULL == unixpds) { 1.380 + errno = EAGAIN; 1.381 + return -1; 1.382 + } 1.383 + 1.384 + pdcnt = 0; 1.385 + epfd = filedes + nfds; 1.386 + unixpd = unixpds; 1.387 + for (pfd = filedes; pfd < epfd; pfd++) { 1.388 + /* 1.389 + * poll() ignores negative fd's. 1.390 + */ 1.391 + if (pfd->fd >= 0) { 1.392 + unixpd->osfd = pfd->fd; 1.393 +#ifdef _PR_USE_POLL 1.394 + unixpd->in_flags = pfd->events; 1.395 +#else 1.396 + /* 1.397 + * Map the poll events to one of the three that can be 1.398 + * represented by the select fd_sets: 1.399 + * POLLIN, POLLRDNORM ===> readable 1.400 + * POLLOUT, POLLWRNORM ===> writable 1.401 + * POLLPRI, POLLRDBAND ===> exception 1.402 + * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) 1.403 + * are ignored. 1.404 + * 1.405 + * The output events POLLERR and POLLHUP are never turned on. 1.406 + * POLLNVAL may be turned on. 1.407 + */ 1.408 + unixpd->in_flags = 0; 1.409 + if (pfd->events & (POLLIN 1.410 +#ifdef POLLRDNORM 1.411 + | POLLRDNORM 1.412 +#endif 1.413 + )) { 1.414 + unixpd->in_flags |= _PR_UNIX_POLL_READ; 1.415 + } 1.416 + if (pfd->events & (POLLOUT 1.417 +#ifdef POLLWRNORM 1.418 + | POLLWRNORM 1.419 +#endif 1.420 + )) { 1.421 + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; 1.422 + } 1.423 + if (pfd->events & (POLLPRI 1.424 +#ifdef POLLRDBAND 1.425 + | POLLRDBAND 1.426 +#endif 1.427 + )) { 1.428 + unixpd->in_flags |= PR_POLL_EXCEPT; 1.429 + } 1.430 +#endif /* _PR_USE_POLL */ 1.431 + unixpd->out_flags = 0; 1.432 + unixpd++; 1.433 + pdcnt++; 1.434 + } 1.435 + } 1.436 + 1.437 + ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, ticks); 1.438 + if (-1 == ready) { 1.439 + if (PR_GetError() == PR_PENDING_INTERRUPT_ERROR) { 1.440 + errno = EINTR; /* XXX we aren't interrupted by a signal, but... */ 1.441 + } else { 1.442 + errno = PR_GetOSError(); 1.443 + } 1.444 + } 1.445 + if (ready <= 0) { 1.446 + goto done; 1.447 + } 1.448 + 1.449 + /* 1.450 + * Copy the out_flags from the _PRUnixPollDesc structures to the 1.451 + * user's pollfd structures and free the allocated memory 1.452 + */ 1.453 + unixpd = unixpds; 1.454 + for (pfd = filedes; pfd < epfd; pfd++) { 1.455 + pfd->revents = 0; 1.456 + if (pfd->fd >= 0) { 1.457 +#ifdef _PR_USE_POLL 1.458 + pfd->revents = unixpd->out_flags; 1.459 +#else 1.460 + if (0 != unixpd->out_flags) { 1.461 + if (unixpd->out_flags & _PR_UNIX_POLL_READ) { 1.462 + if (pfd->events & POLLIN) { 1.463 + pfd->revents |= POLLIN; 1.464 + } 1.465 +#ifdef POLLRDNORM 1.466 + if (pfd->events & POLLRDNORM) { 1.467 + pfd->revents |= POLLRDNORM; 1.468 + } 1.469 +#endif 1.470 + } 1.471 + if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) { 1.472 + if (pfd->events & POLLOUT) { 1.473 + pfd->revents |= POLLOUT; 1.474 + } 1.475 +#ifdef POLLWRNORM 1.476 + if (pfd->events & POLLWRNORM) { 1.477 + pfd->revents |= POLLWRNORM; 1.478 + } 1.479 +#endif 1.480 + } 1.481 + if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) { 1.482 + if (pfd->events & POLLPRI) { 1.483 + pfd->revents |= POLLPRI; 1.484 + } 1.485 +#ifdef POLLRDBAND 1.486 + if (pfd->events & POLLRDBAND) { 1.487 + pfd->revents |= POLLRDBAND; 1.488 + } 1.489 +#endif 1.490 + } 1.491 + if (unixpd->out_flags & _PR_UNIX_POLL_ERR) { 1.492 + pfd->revents |= POLLERR; 1.493 + } 1.494 + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { 1.495 + pfd->revents |= POLLNVAL; 1.496 + } 1.497 + if (unixpd->out_flags & _PR_UNIX_POLL_HUP) { 1.498 + pfd->revents |= POLLHUP; 1.499 + } 1.500 + } 1.501 +#endif /* _PR_USE_POLL */ 1.502 + unixpd++; 1.503 + } 1.504 + } 1.505 + 1.506 +done: 1.507 + PR_DELETE(unixpds); 1.508 + return ready; 1.509 +} 1.510 + 1.511 +#endif /* !defined(LINUX) */ 1.512 + 1.513 +#endif /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */ 1.514 + 1.515 +/* uxwrap.c */ 1.516 +