home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / uxwrap.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.0 KB  |  519 lines

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