nsprpub/pr/src/md/unix/uxwrap.c

changeset 0
6474c204b198
     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 +

mercurial