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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial