home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / pthreads / ptio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  103.6 KB  |  3,382 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. ** File:   ptio.c
  21. ** Descritpion:  Implemenation of I/O methods for pthreads
  22. ** Exports:   ptio.h
  23. */
  24.  
  25. #if defined(_PR_PTHREADS)
  26.  
  27. #include <string.h>  /* for memset() */
  28. #include <sys/types.h>
  29. #include <dirent.h>
  30.  
  31. /*
  32.  * XXX: On Linux 2.0.27 sched.h uses this _P macro that seems to be undefined.
  33.  * I suspect that it is a typo (should be __P).
  34.  */
  35. #if defined(LINUX)
  36. #define _P(x) __P(x)
  37. #endif
  38. #include <pthread.h>
  39.  
  40. #include <fcntl.h>
  41. #include <unistd.h>
  42. #include <sys/socket.h>
  43. #include <sys/stat.h>
  44. #include <sys/uio.h>
  45. #include <sys/file.h>
  46. #include <sys/ioctl.h>
  47. #ifdef SOLARIS
  48. #include <sys/filio.h>  /* to pick up FIONREAD */
  49. #endif
  50. /* Linux (except glibc) and FreeBSD don't have poll */
  51. #if !(defined(LINUX) && !(defined(__GLIBC__) && __GLIBC__ >= 2)) \
  52.     && !defined(FREEBSD)
  53. #include <poll.h>
  54. #endif
  55. #ifdef AIX
  56. /* To pick up sysconf() */
  57. #include <unistd.h>
  58. #else
  59. /* To pick up getrlimit() etc. */
  60. #include <sys/time.h>
  61. #include <sys/resource.h>
  62. #endif
  63.  
  64. #include "primpl.h"
  65.  
  66. /* On Alpha Linux, these are already defined in sys/socket.h */
  67. #if !(defined(LINUX) && defined(__alpha))
  68. #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
  69. #endif
  70.  
  71. #if defined(SOLARIS)
  72. #define _PRSockOptVal_t char *
  73. #elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(HPUX) \
  74.     || defined(LINUX) || defined(FREEBSD)
  75. #define _PRSockOptVal_t void *
  76. #else
  77. #error "Cannot determine architecture"
  78. #endif
  79.  
  80. #if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
  81. #define _PRSelectFdSetArg_t int *
  82. #elif defined(AIX4_1)
  83. #define _PRSelectFdSetArg_t void *
  84. #elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
  85.     || defined(OSF1) || defined(SOLARIS) \
  86.     || defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) \
  87.     || defined(FREEBSD)
  88. #define _PRSelectFdSetArg_t fd_set *
  89. #else
  90. #error "Cannot determine architecture"
  91. #endif
  92.  
  93. static PRStatus pt_InitIOContinuation(void);
  94. static PRFileDesc *pt_SetMethods(PRIntn osfd, PRDescType type);
  95.  
  96. static pthread_condattr_t _pt_cvar_attr;
  97. static PRLock *_pr_flock_lock;  /* For PR_LockFile() etc. */
  98. static PRLock *_pr_rename_lock;  /* For PR_Rename() */
  99.  
  100. extern struct _PT_Bookeeping pt_book;  /* defined in ptthread.c */
  101. extern PRIntn pt_schedpriv;  /* defined in ptthread.c */
  102.  
  103. /*****************************************************************************/
  104. /*****************************************************************************/
  105. /************************** File descriptor caching **************************/
  106. /*****************************************************************************/
  107. /*****************************************************************************/
  108.  
  109. typedef struct _PT_Fd_Cache
  110. {
  111.     PRLock *ml;
  112.     PRIntn count;
  113.     PRIntn limit;
  114.     PRFileDesc *fd;
  115. } _PT_Fd_Cache;
  116. static _PT_Fd_Cache pt_fd_cache;
  117.  
  118. /*
  119. ** Get a FileDescriptor from the cache if one exists. If not allocate
  120. ** a new one from the heap.
  121. */
  122. static PRFileDesc *pt_Getfd(void)
  123. {
  124.     PRFileDesc *fd;
  125.     do
  126.     {
  127.         fd = pt_fd_cache.fd;  /* quick, unsafe check */
  128.         if (NULL == fd)
  129.         {
  130.             fd = PR_NEWZAP(PRFileDesc);
  131.             if (NULL == fd) goto finished;
  132.             fd->secret = PR_NEWZAP(PRFilePrivate);
  133.             if (NULL == fd->secret)
  134.             {
  135.                 PR_DELETE(fd);
  136.                 goto finished;
  137.             }
  138.         }
  139.         else
  140.         {
  141.             PRFilePrivate *secret;
  142.             PR_Lock(pt_fd_cache.ml);
  143.             fd = pt_fd_cache.fd;  /* safer extraction */
  144.             if (NULL != fd)
  145.             {
  146.                 pt_fd_cache.count -= 1;
  147.                 pt_fd_cache.fd = fd->higher;
  148.                 fd->higher = NULL;
  149.             }
  150.             PR_Unlock(pt_fd_cache.ml);
  151.             secret = fd->secret;
  152.             memset(fd, 0, sizeof(PRFileDesc));
  153.             memset(secret, 0, sizeof(PRFilePrivate));
  154.             fd->secret = secret;
  155.         }
  156.     } while (NULL == fd);
  157. finished:
  158.     return fd;
  159. }  /* pt_Getfd */
  160.  
  161. /*
  162. ** Return a file descriptor to the cache unless there are too many in
  163. ** there already. If put in cache, clear the fields first.
  164. */
  165. static void pt_Putfd(PRFileDesc *fd)
  166. {
  167.     PR_ASSERT(_PR_FILEDESC_CLOSED == fd->secret->state);
  168.     PR_ASSERT(pt_fd_cache.count < pt_fd_cache.limit);
  169.  
  170.     fd->secret->state = _PR_FILEDESC_FREED;
  171.     if (pt_fd_cache.count > pt_fd_cache.limit)
  172.     {
  173.         PR_DELETE(fd->secret);
  174.         PR_DELETE(fd);
  175.     }
  176.     else
  177.     {
  178.         PR_Lock(pt_fd_cache.ml);
  179.         pt_fd_cache.count += 1;
  180.         fd->higher = pt_fd_cache.fd;
  181.         pt_fd_cache.fd = fd;
  182.         PR_Unlock(pt_fd_cache.ml);
  183.     }
  184. }  /* pt_Putfd */
  185.     
  186. /*****************************************************************************/
  187. /************************* I/O Continuation machinery ************************/
  188. /*****************************************************************************/
  189.  
  190. /*
  191.  * The polling interval defines the maximum amount of time that a thread
  192.  * might hang up before an interrupt is noticed.
  193.  */
  194. #define PT_DEFAULT_POLL_MSEC 100
  195.  
  196. /*
  197.  * Latest POSIX defines this type as socklen_t.  It may also be
  198.  * size_t or int.
  199.  */
  200. #if (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2 \
  201.     && !defined(__alpha))
  202. typedef socklen_t pt_SockLen;
  203. #elif defined(AIX) || (defined(LINUX) && defined(__alpha))
  204. typedef PRSize pt_SockLen;
  205. #else
  206. typedef PRIntn pt_SockLen;
  207. #endif
  208.  
  209. typedef struct pt_Continuation pt_Continuation;
  210. typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
  211.  
  212. typedef enum pr_ContuationStatus
  213. {
  214.     pt_continuation_sumbitted,
  215.     pt_continuation_inprogress,
  216.     pt_continuation_abort,
  217.     pt_continuation_done
  218. } pr_ContuationStatus;
  219.  
  220. struct pt_Continuation
  221. {
  222.     /* These objects are linked in ascending timeout order */
  223.     pt_Continuation *next, *prev;           /* self linked list of these things */
  224.  
  225.     /* The building of the continuation operation */
  226.     ContinuationFn function;                /* what function to continue */
  227.     union { PRIntn osfd; } arg1;            /* #1 - the op's fd */
  228.     union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
  229.     union {
  230.         PRSize amount;                      /* #3 - size of 'buffer', or */
  231.         pt_SockLen *addr_len;                  /*    - length of address */
  232. #ifdef HPUX11
  233.         /*
  234.          * For sendfile()
  235.          */
  236.         off_t offset;                       /* offset in file to send */
  237. #endif
  238.     } arg3;
  239.     union { PRIntn flags; } arg4;           /* #4 - read/write flags */
  240.     union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
  241.  
  242. #ifdef HPUX11
  243.     /*
  244.      * For sendfile()
  245.      */
  246.     int filedesc;                           /* descriptor of file to send */
  247.     int nbytes_to_send;                     /* size of header and file */
  248. #endif  /* HPUX11 */
  249.     
  250.     PRIntervalTime timeout;                 /* client (relative) timeout */
  251.     PRIntervalTime absolute;                /* internal (absolute) timeout */
  252.  
  253.     PRInt16 event;                           /* flags for poll()'s events */
  254.  
  255.     /*
  256.     ** The representation and notification of the results of the operation.
  257.     ** These function can either return an int return code or a pointer to
  258.     ** some object.
  259.     */
  260.     union { PRSize code; void *object; } result;
  261.  
  262.     PRIntn syserrno;                        /* in case it failed, why (errno) */
  263.     pr_ContuationStatus status;             /* the status of the operation */
  264.     PRCondVar complete;                     /* to notify the initiating thread */
  265. };
  266.  
  267. static struct pt_TimedQueue
  268. {
  269.     PRCallOnceType once;                    /* controls the initialization
  270.                                              * of this structure */
  271.     PRLock *ml;                             /* a little protection */
  272.     PRThread *thread;                       /* internal thread's identification */
  273.     PRCondVar *new_op;                      /* new operation supplied */
  274.     PRUintn op_count;                       /* number of operations in the list */
  275.     pt_Continuation *head, *tail;           /* head/tail of list of operations */
  276.  
  277.     pt_Continuation *op;                    /* timed operation furthest in future */
  278.     PRBool exitFlag;                        /* a Boolean flag for signaling the
  279.                                              * continuation thread to exit */
  280. } pt_tq;
  281.  
  282. #if defined(DEBUG)
  283. static struct pt_debug_s
  284. {
  285.     PRUintn predictionsFoiled;
  286.     PRUintn pollingListMax;
  287.     PRUintn continuationsServed;
  288. } pt_debug;
  289. #endif  /* DEBUG */
  290.  
  291. /*
  292.  * The following two functions, pt_InsertTimedInternal and
  293.  * pt_FinishTimedInternal, are always called with the pt_tq.ml
  294.  * lock held.  The "internal" in the functions' names come from
  295.  * the Mesa programming language.  Internal functions are always
  296.  * called from inside a monitor.
  297.  */
  298.  
  299. static void pt_InsertTimedInternal(pt_Continuation *op)
  300. {
  301.     pt_Continuation *t_op = NULL;
  302.     PRIntervalTime now = PR_IntervalNow();
  303.  
  304.     /*
  305.      * If this element operation isn't timed, it gets queued at the
  306.      * end of the list (just after pt_tq.tail) and we're
  307.      * finishd early.
  308.      */
  309.     if (PR_INTERVAL_NO_TIMEOUT == op->timeout)
  310.     {
  311.         t_op = pt_tq.tail;  /* put it at the end */
  312.         goto done;
  313.     }
  314.  
  315.     /*
  316.      * The portion of this routine deals with timed ops.
  317.      */
  318.     op->absolute = now + op->timeout;  /* absolute ticks */
  319.     if (NULL == pt_tq.op) pt_tq.op = op;
  320.     else
  321.     {
  322.         /*
  323.          * To find where in the list to put the new operation, based
  324.          * on the absolute time the operation in question will expire.
  325.          *
  326.          * The new operation ('op') will expire at now() + op->timeout.
  327.          *
  328.          * This should be easy!
  329.          */
  330.  
  331.         for (t_op = pt_tq.op; NULL != t_op; t_op = t_op->prev)
  332.         {
  333.             /*
  334.              * If 'op' expires later than t_op, then insert 'op' just
  335.              * ahead of t_op. Otherwise, compute when operation[n-1]
  336.              * expires and try again.
  337.              *
  338.              * The actual different between the expiriation of 'op'
  339.              * and the current operation what becomes the new operaton's
  340.              * timeout interval. That interval is also subtracted from
  341.              * the interval of the operation immediately following where
  342.              * we stick 'op' (unless the next one isn't timed). The new
  343.              * timeout assigned to 'op' takes into account the values of
  344.              * now() and when the previous intervals were computed.
  345.              */
  346.             if ((PRInt32)(op->absolute - t_op->absolute) >= 0)
  347.             {
  348.                 if (t_op == pt_tq.op) pt_tq.op = op;
  349.                 break;
  350.             }
  351.         }
  352.     }
  353.  
  354. done:
  355.  
  356.     /*
  357.      * Insert 'op' into the queue just after t_op or if t_op is null,
  358.      * at the head of the list.
  359.      *
  360.      * We need to set up the 'next' and 'prev' pointers of 'op'
  361.      * correctly before inserting 'op' into the queue.  Also, we insert
  362.      * 'op' by updating pt_tq.head or op->prev->next first, and then
  363.      * updating op->next->prev.  We want to make sure that the 'next'
  364.      * pointers are linked up correctly at all times so that we can
  365.      * traverse the queue by starting with pt_tq.head and following
  366.      * the 'next' pointers, without having to acquire the pt_tq.ml lock.
  367.      * (We do that in ContinuationThread.)  We traverse the 'prev'
  368.      * pointers only in this function, which is called with the lock held.
  369.      *
  370.      * Similar care is taken in pt_FinishTimedInternal where we remove
  371.      * an op from the queue.
  372.      */
  373.     if (NULL == t_op)
  374.     {
  375.         op->prev = NULL;
  376.         op->next = pt_tq.head;
  377.         pt_tq.head = op;
  378.         if (NULL == pt_tq.tail) pt_tq.tail = op;
  379.         else op->next->prev = op;
  380.     }
  381.     else
  382.     {
  383.         op->prev = t_op;
  384.         op->next = t_op->next;
  385.         if (NULL != op->prev)
  386.             op->prev->next = op;
  387.         if (NULL != op->next)
  388.             op->next->prev = op;
  389.         if (t_op == pt_tq.tail)
  390.             pt_tq.tail = op;
  391.     }
  392.  
  393.     pt_tq.op_count += 1;
  394.  
  395. }  /* pt_InsertTimedInternal */
  396.  
  397. /*
  398.  * function: pt_FinishTimedInternal
  399.  *
  400.  * Takes the finished operation out of the timed queue. It
  401.  * notifies the initiating thread that the opertions is
  402.  * complete and returns to the caller the value of the next
  403.  * operation in the list (or NULL).
  404.  */
  405. static pt_Continuation *pt_FinishTimedInternal(pt_Continuation *op)
  406. {
  407.     pt_Continuation *next;
  408.  
  409.     /* remove this one from the list */
  410.     if (NULL == op->prev) pt_tq.head = op->next;
  411.     else op->prev->next = op->next;
  412.     if (NULL == op->next) pt_tq.tail = op->prev;
  413.     else op->next->prev = op->prev;
  414.  
  415.     /* did we happen to hit the timed op? */
  416.     if (op == pt_tq.op) pt_tq.op = op->prev;
  417.  
  418.     next = op->next;
  419.     op->next = op->prev = NULL;
  420.     op->status = pt_continuation_done;
  421.  
  422.     pt_tq.op_count -= 1;
  423.  
  424. #if defined(DEBUG)
  425.     pt_debug.continuationsServed += 1;
  426. #endif
  427.     PR_NotifyCondVar(&op->complete);
  428.  
  429.     return next;
  430. }  /* pt_FinishTimedInternal */
  431.  
  432. static void ContinuationThread(void *arg)
  433. {
  434.     /* initialization */
  435.     PRInt32 msecs, mx_poll_ticks;
  436.     struct pollfd *pollingList = 0;         /* list built for polling */
  437.     PRIntn pollingListUsed;                 /* # entries used in the list */
  438.     PRIntn pollingListNeeded;               /* # entries needed this time */
  439.     PRIntn pollingSlotsAllocated = 0;       /* # entries available in list */
  440.     
  441.     mx_poll_ticks = (PRInt32)PR_MillisecondsToInterval(PT_DEFAULT_POLL_MSEC);
  442.  
  443.     /* do some real work */
  444.     while (PR_TRUE)
  445.     {
  446.         PRIntn rv;
  447.         PRInt32 timeout;
  448.         PRIntn pollIndex;
  449.         PRIntervalTime now;
  450.         pt_Continuation *op;
  451.  
  452.         PR_Lock(pt_tq.ml);
  453.         while (!pt_tq.exitFlag && (NULL == pt_tq.head))
  454.             PR_WaitCondVar(pt_tq.new_op, PR_INTERVAL_NO_TIMEOUT);
  455.         pollingListNeeded = pt_tq.op_count;
  456.         PR_Unlock(pt_tq.ml);
  457.  
  458.         /* Okay. We're history */
  459.         if (pt_tq.exitFlag) break;
  460.  
  461.     /*
  462.      * We are not holding the pt_tq.ml lock now, so more items may
  463.      * get added to pt_tq during this window of time.  We hope
  464.      * that 10 more spaces in the polling list should be enough.
  465.      */
  466.         pollingListNeeded += 10;
  467.         if (pollingListNeeded > pollingSlotsAllocated)
  468.         {
  469.             if (NULL != pollingList) PR_DELETE(pollingList);
  470.             pollingList = (struct pollfd*)PR_Malloc(
  471.                 pollingListNeeded * sizeof(struct pollfd));
  472.             PR_ASSERT(NULL != pollingList);
  473.             pollingSlotsAllocated = pollingListNeeded;
  474.         }
  475.  
  476. #if defined(DEBUG)
  477.         if (pollingListNeeded > pt_debug.pollingListMax)
  478.             pt_debug.pollingListMax = pollingListNeeded;
  479. #endif
  480.  
  481.         /*
  482.          * Build up a polling list.
  483.          * This list is sorted on time. Operations that have been
  484.          * interrupted are completed and not included in the list.
  485.          * There is an assertion that the operation is in progress.
  486.          */
  487.         pollingListUsed = 0;
  488.         PR_Lock(pt_tq.ml);
  489.  
  490.         for (op = pt_tq.head; NULL != op;)
  491.         {
  492.             if (pt_continuation_abort == op->status)
  493.             {
  494.                 op->result.code = -1;
  495.                 op->syserrno = EINTR;
  496.                 op = pt_FinishTimedInternal(op);
  497.             }
  498.             else
  499.             {
  500.                 if (pollingListUsed == pollingSlotsAllocated) break;
  501.                 PR_ASSERT(pt_continuation_done != op->status);
  502.                 op->status = pt_continuation_inprogress;
  503.                 pollingList[pollingListUsed].revents = 0;
  504.                 pollingList[pollingListUsed].fd = op->arg1.osfd;
  505.                 pollingList[pollingListUsed].events = op->event;
  506.                 pollingListUsed += 1;
  507.                 op = op->next;
  508.             }
  509.         }
  510.  
  511.         PR_Unlock(pt_tq.ml);
  512.  
  513.         /*
  514.          * If 'op' isn't NULL at this point, then we didn't get to
  515.          * the end of the list. That means that more items got added
  516.          * to the list than we anticipated. So, forget this iteration,
  517.          * go around the horn again.
  518.          * One would hope this doesn't happen all that often.
  519.          */
  520.         if (NULL != op)
  521.         {
  522. #if defined(DEBUG)
  523.             pt_debug.predictionsFoiled += 1;  /* keep track */
  524. #endif
  525.             continue;  /* make it rethink things */
  526.         }
  527.  
  528.         if (NULL == pt_tq.head) continue;  /* did list evaporate? */
  529.  
  530.         /*
  531.          * We don't want to wait forever on this poll. So keep
  532.          * the interval down. The operations, if they are timed,
  533.          * still have to timeout, while those that are not timed
  534.          * should persist forever. But they may be aborted. That's
  535.          * what this anxiety is all about.
  536.          */
  537.         if (PR_INTERVAL_NO_TIMEOUT == pt_tq.head->timeout)
  538.             msecs = PT_DEFAULT_POLL_MSEC;
  539.         else
  540.         {
  541.             timeout = pt_tq.head->absolute - PR_IntervalNow();
  542.             if (timeout <= 0) msecs = 0;  /* already timed out */
  543.             else if (timeout >= mx_poll_ticks) msecs = PT_DEFAULT_POLL_MSEC;
  544.             else msecs = (PRInt32)PR_IntervalToMilliseconds(timeout);
  545.     }
  546.  
  547.         rv = poll(pollingList, pollingListUsed, msecs);
  548.         
  549.         if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
  550.             continue; /* go around the loop again */
  551.  
  552.     if (rv > 0)
  553.     {
  554.             /*
  555.              * poll() says that something in our list is ready for some more
  556.              * action. Find it, load up the operation and see what happens.
  557.              */
  558.  
  559.             /*
  560.              * This may work out okay. The rule is that only this thread,
  561.              * the continuation thread, can remove elements from the list.
  562.              * Therefore, the list is at worst, longer than when we built
  563.              * the polling list.
  564.              */
  565.  
  566.             op = pt_tq.head;
  567.             for (pollIndex = 0; pollIndex < pollingListUsed; ++pollIndex)
  568.             {
  569.                 PR_ASSERT(NULL != op);
  570.                 if (0 != pollingList[pollIndex].revents)
  571.                 {
  572.                     /*
  573.                      * This one wants attention. Redo the operation.
  574.                      * We know that there can only be more elements
  575.                      * in the op list than we knew about when we created
  576.                      * the poll list. Therefore, we might have to skip
  577.                      * a few ops to find the right one to operate on.
  578.                      */
  579.                     while ((pollingList[pollIndex].fd != op->arg1.osfd)
  580.                     || (pollingList[pollIndex].events != op->event))
  581.                     {
  582.                         PR_ASSERT(NULL != op->next);  /* it has to be in there */
  583.                         op = op->next;  /* keep advancing down the list */
  584.                     }
  585.  
  586.                     /*
  587.                      * Skip over all those not in progress. They'll be
  588.                      * pruned next time we build a polling list. Call
  589.                      * the continuation function. If it reports completion,
  590.                      * finish off the operation.
  591.                      */
  592.                     if ((pt_continuation_inprogress == op->status)
  593.                     && (op->function(op, pollingList[pollIndex].revents)))
  594.                     {
  595.                         PR_Lock(pt_tq.ml);
  596.                         op = pt_FinishTimedInternal(op);
  597.                         PR_Unlock(pt_tq.ml);
  598.                     }
  599.                     continue;
  600.                 }
  601.                 op = op->next;  /* progress to next operation */
  602.             }
  603.         }
  604.  
  605.         /*
  606.          * This is timeout processing. It is done after checking
  607.          * for good completions. Those that just made it under the
  608.          * wire are lucky, but none the less, valid.
  609.          */
  610.         if ((NULL != pt_tq.head)
  611.         && (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout))
  612.         {
  613.             now = PR_IntervalNow();
  614.             while ((PRInt32)(pt_tq.head->absolute - now) <= 0)
  615.             {
  616.                 /* 
  617.                  * The leading element of the timed queue has timed
  618.                  * out. Get rid of it. In any case go around the
  619.                  * loop again, computing the polling list, checking
  620.                  * for interrupted operations.
  621.                  */
  622.  
  623.                 PR_Lock(pt_tq.ml);
  624.                 pt_tq.head->result.code = -1;
  625.                 pt_tq.head->syserrno = ETIMEDOUT;
  626.                 (void)pt_FinishTimedInternal(pt_tq.head);
  627.                 PR_Unlock(pt_tq.ml);
  628.                 if ((NULL == pt_tq.head)
  629.                 || (PR_INTERVAL_NO_TIMEOUT == pt_tq.head->timeout))
  630.                     break;
  631.             }
  632.         }
  633.     }
  634.     if (NULL != pollingList) PR_DELETE(pollingList);
  635. }  /* ContinuationThread */
  636.  
  637. static PRIntn pt_Continue(pt_Continuation *op)
  638. {
  639.     PRIntn rc;
  640.     PRStatus rv;
  641. #ifdef DEBUG
  642.     PRBool waitcv_interrupted = PR_FALSE;
  643. #endif /* DEBUG */
  644.  
  645.     PR_CallOnce(&pt_tq.once, pt_InitIOContinuation);
  646.  
  647.     /* Finish filling in the blank slots */
  648.     /* op->complete = PR_NewCondVar(pt_tq.ml); */
  649.     op->complete.lock = pt_tq.ml;
  650.     rc = PTHREAD_COND_INIT(op->complete.cv, _pt_cvar_attr);  PR_ASSERT(0 == rc);
  651.     op->status = pt_continuation_sumbitted;
  652.     PR_Lock(pt_tq.ml);  /* we provide the locking */
  653.  
  654.     pt_InsertTimedInternal(op);  /* insert in the structure */
  655.  
  656.     PR_NotifyCondVar(pt_tq.new_op);  /* notify the continuation thread */
  657.  
  658.     while (pt_continuation_done != op->status)  /* wait for completion */
  659.     {
  660.         rv = PR_WaitCondVar(&op->complete, PR_INTERVAL_NO_TIMEOUT);
  661.         /*
  662.          * If we get interrupted, we set state the continuation thread will
  663.          * see and allow it to finish the I/O operation w/ error. That way
  664.          * the rule that only the continuation thread is removing elements
  665.          * from the list is still valid.
  666.          *
  667.          * Don't call interrupt on the continuation thread. That'll just
  668.          * irritate him. He's cycling around at least every mx_poll_ticks
  669.          * anyhow and should notice the request in there.
  670.          */
  671.         if ((PR_FAILURE == rv)
  672.         && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
  673.         {
  674. #ifdef DEBUG
  675.             waitcv_interrupted = PR_TRUE;
  676. #endif /* DEBUG */
  677.             if (pt_continuation_done != op->status)
  678.             {
  679.                 /* tell the continuation thread to abort the operation */
  680.                 op->status = pt_continuation_abort;
  681.             }
  682.             else
  683.             {
  684.                 op->result.code = -1;
  685.                 op->syserrno = EINTR;
  686.             }
  687.         }
  688.     }
  689.  
  690.     PR_Unlock(pt_tq.ml);  /* we provide the locking */
  691.     rc = pthread_cond_destroy(&op->complete.cv); PR_ASSERT(0 == rc);
  692.  
  693.     /* make sure that the continuation thread did abort the operation */
  694. #ifdef DEBUG
  695.     if (PR_TRUE == waitcv_interrupted)
  696.     {
  697.         PR_ASSERT(-1 == op->result.code);
  698.         PR_ASSERT(EINTR == op->syserrno);
  699.     }
  700. #endif /* DEBUG */
  701.     return op->result.code;  /* and the primary answer */
  702. }  /* pt_Continue */
  703.  
  704. /*****************************************************************************/
  705. /*********************** specific continuation functions *********************/
  706. /*****************************************************************************/
  707. static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
  708. {
  709.     op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
  710.     if (op->syserrno != 0) {
  711.         op->result.code = -1;
  712.     } else {
  713.         op->result.code = 0;
  714.     }
  715.     return PR_TRUE; /* this one is cooked */
  716. }  /* pt_connect_cont */
  717.  
  718. static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
  719. {
  720.     op->syserrno = 0;
  721.     op->result.code = accept(
  722.         op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
  723.     if (-1 == op->result.code)
  724.     {
  725.         op->syserrno = errno;
  726.         if (EWOULDBLOCK == errno || EAGAIN == errno)  /* the only thing we allow */
  727.             return PR_FALSE;  /* do nothing - this one ain't finished */
  728.     }
  729.     return PR_TRUE;
  730. }  /* pt_accept_cont */
  731.  
  732. static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
  733. {
  734.     /*
  735.      * Any number of bytes will complete the operation. It need
  736.      * not (and probably will not) satisfy the request. The only
  737.      * error we continue is EWOULDBLOCK|EAGAIN.
  738.      */
  739.     op->result.code = read(
  740.         op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
  741.     op->syserrno = errno;
  742.     return ((-1 == op->result.code) && 
  743.             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
  744.         PR_FALSE : PR_TRUE;
  745. }  /* pt_read_cont */
  746.  
  747. static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
  748. {
  749.     /*
  750.      * Any number of bytes will complete the operation. It need
  751.      * not (and probably will not) satisfy the request. The only
  752.      * error we continue is EWOULDBLOCK|EAGAIN.
  753.      */
  754.     op->result.code = recv(
  755.         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
  756.     op->syserrno = errno;
  757.     return ((-1 == op->result.code) && 
  758.             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
  759.         PR_FALSE : PR_TRUE;
  760. }  /* pt_recv_cont */
  761.  
  762. static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
  763. {
  764.     /*
  765.      * We want to write the entire amount out, no matter how many
  766.      * tries it takes. Keep advancing the buffer and the decrementing
  767.      * the amount until the amount goes away. Return the total bytes
  768.      * (which should be the original amount) when finished (or an
  769.      * error).
  770.      */
  771.     PRIntn bytes = send(
  772.         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
  773.     op->syserrno = errno;
  774.     if (bytes > 0)  /* this is progress */
  775.     {
  776.         char *bp = (char*)op->arg2.buffer;
  777.         bp += bytes;  /* adjust the buffer pointer */
  778.         op->arg2.buffer = bp;
  779.         op->result.code += bytes;  /* accumulate the number sent */
  780.         op->arg3.amount -= bytes;  /* and reduce the required count */
  781.         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
  782.     }
  783.     else return ((-1 == bytes) &&
  784.         (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? 
  785.         PR_FALSE : PR_TRUE;
  786. }  /* pt_send_cont */
  787.  
  788. static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
  789. {
  790.     /*
  791.      * We want to write the entire amount out, no matter how many
  792.      * tries it takes. Keep advancing the buffer and the decrementing
  793.      * the amount until the amount goes away. Return the total bytes
  794.      * (which should be the original amount) when finished (or an
  795.      * error).
  796.      */
  797.     PRIntn bytes = write(
  798.         op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
  799.     op->syserrno = errno;
  800.     if (bytes > 0)  /* this is progress */
  801.     {
  802.         char *bp = (char*)op->arg2.buffer;
  803.         bp += bytes;  /* adjust the buffer pointer */
  804.         op->arg2.buffer = bp;
  805.         op->result.code += bytes;  /* accumulate the number sent */
  806.         op->arg3.amount -= bytes;  /* and reduce the required count */
  807.         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
  808.     }
  809.     else return ((-1 == bytes) &&
  810.         (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? 
  811.         PR_FALSE : PR_TRUE;
  812. }  /* pt_write_cont */
  813.  
  814. static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
  815. {
  816.     /*
  817.      * Same rules as write, but continuing seems to be a bit more
  818.      * complicated. As the number of bytes sent grows, we have to
  819.      * redefine the vector we're pointing at. We might have to
  820.      * modify an individual vector parms or we might have to eliminate
  821.      * a pair altogether.
  822.      */
  823.     PRIntn bytes = writev(
  824.         op->arg1.osfd, (struct iovec*)op->arg2.buffer, op->arg3.amount);
  825.     op->syserrno = errno;
  826.     if (bytes > 0)  /* this is progress */
  827.     {
  828.         PRIntn iov_index;
  829.         struct iovec *iov = (struct iovec*)op->arg2.buffer;
  830.     op->result.code += bytes;  /* accumulate the number sent */
  831.         for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
  832.         {
  833.             /* how much progress did we make in the i/o vector? */
  834.             if (bytes < iov[iov_index].iov_len)
  835.             {
  836.                 /* this element's not done yet */
  837.                 char **bp = (char**)&(iov[iov_index].iov_base);
  838.                 iov[iov_index].iov_len -= bytes;  /* there's that much left */
  839.                 *bp += bytes;  /* starting there */
  840.                 break;  /* go off and do that */
  841.             }
  842.             bytes -= iov[iov_index].iov_len;  /* that element's consumed */
  843.         }
  844.         op->arg2.buffer = &iov[iov_index];  /* new start of array */
  845.         op->arg3.amount -= iov_index;  /* and array length */
  846.         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
  847.     }
  848.     else return ((-1 == bytes) &&
  849.         (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? 
  850.         PR_FALSE : PR_TRUE;
  851. }  /* pt_writev_cont */
  852.  
  853. static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
  854. {
  855.     PRIntn bytes = sendto(
  856.         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
  857.         (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
  858.     op->syserrno = errno;
  859.     if (bytes > 0)  /* this is progress */
  860.     {
  861.         char *bp = (char*)op->arg2.buffer;
  862.         bp += bytes;  /* adjust the buffer pointer */
  863.         op->arg2.buffer = bp;
  864.         op->result.code += bytes;  /* accumulate the number sent */
  865.         op->arg3.amount -= bytes;  /* and reduce the required count */
  866.         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
  867.     }
  868.     else return ((-1 == bytes) && 
  869.         (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
  870.     PR_FALSE : PR_TRUE;
  871. }  /* pt_sendto_cont */
  872.  
  873. static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
  874. {
  875.     pt_SockLen addr_len = sizeof(PRNetAddr);
  876.     op->result.code = recvfrom(
  877.         op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
  878.         op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
  879.     op->syserrno = errno;
  880.     return ((-1 == op->result.code) && 
  881.             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
  882.         PR_FALSE : PR_TRUE;
  883. }  /* pt_recvfrom_cont */
  884.  
  885. #ifdef HPUX11
  886. static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
  887. {
  888.     struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
  889.     int count;
  890.  
  891.     count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.offset, 0,
  892.             hdtrl, op->arg4.flags);
  893.     PR_ASSERT(count <= op->nbytes_to_send);
  894.  
  895.     if (count != -1) {
  896.         op->result.code += count;
  897.     } else if (errno != EWOULDBLOCK && errno != EAGAIN) {
  898.         op->result.code = -1;
  899.     } else {
  900.         return PR_FALSE;
  901.     }
  902.  
  903.     if (count != -1 && count < op->nbytes_to_send) {
  904.         if (hdtrl[0].iov_len == 0) {
  905.             PR_ASSERT(hdtrl[0].iov_base == NULL);
  906.             op->arg3.offset += count;
  907.         } else if (count < hdtrl[0].iov_len) {
  908.             PR_ASSERT(op->arg3.offset == 0);
  909.             hdtrl[0].iov_base = (char *) hdtrl[0].iov_base + count;
  910.             hdtrl[0].iov_len -= count;
  911.         } else {
  912.             op->arg3.offset = count - hdtrl[0].iov_len;
  913.             hdtrl[0].iov_base = NULL;
  914.             hdtrl[0].iov_len = 0;
  915.         }
  916.         op->nbytes_to_send -= count;
  917.         return PR_FALSE;
  918.     }
  919.  
  920.     return PR_TRUE;
  921. }
  922. #endif  /* HPUX11 */
  923.  
  924. #if !defined(PT_NO_ATFORK)
  925.  
  926. static void pt_BeforeFork()
  927. {
  928.     PRStatus rv;
  929.     PRThread *thred = pt_tq.thread;
  930.  
  931.     /*
  932.      * We shut down the continuation thread cleanly only if there are
  933.      * no other threads in the process when fork() is called.
  934.      * If there are other threads, they won't be duplicated in the child
  935.      * process.  Then the child process may already be unclean, so there
  936.      * is no point for us to try to be clean.
  937.      */
  938.  
  939.     if ((NULL != thred) && (2 == pt_book.user + pt_book.system))
  940.     {
  941.         /* pt_tq should be empty */
  942.         PR_ASSERT((0 == pt_tq.op_count)
  943.             && (NULL == pt_tq.head)
  944.             && (NULL == pt_tq.tail)
  945.             && (NULL == pt_tq.op));
  946.         pt_tq.exitFlag = PR_TRUE;
  947.         rv = PR_Interrupt(thred);
  948.         PR_ASSERT(PR_SUCCESS == rv);
  949.         rv = PR_JoinThread(thred);
  950.         PR_ASSERT(PR_SUCCESS == rv);
  951.         pt_tq.exitFlag = PR_FALSE;
  952.         /* Indicates that the continuation thread is shut down cleanly */
  953.         pt_tq.thread = NULL;
  954.         memset(&pt_tq.once, 0, sizeof(pt_tq.once));
  955.         PR_ASSERT(1 == pt_book.user + pt_book.system);
  956.     }
  957. }  /* pt_BeforeFork */
  958.  
  959. static void pt_AfterForkParent(void)
  960. {
  961. }  /* pt_AfterForkParent */
  962.  
  963. static void pt_AfterForkChild(void)
  964. {
  965.     /*
  966.      * pt_tq may be in a corrupted state if the continuation thread
  967.      * existed and was not terminated cleanly before fork.  In this
  968.      * case, we expect the child process to call exec immediately.
  969.      */
  970. }  /* pt_AfterForkChild */
  971.  
  972. #endif  /* PT_NO_ATFORK */
  973.  
  974. void _PR_InitIO()
  975. {
  976.     _pr_stdin = pt_SetMethods(0, PR_DESC_FILE);
  977.     _pr_stdout = pt_SetMethods(1, PR_DESC_FILE);
  978.     _pr_stderr = pt_SetMethods(2, PR_DESC_FILE);
  979.  
  980.     PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
  981.  
  982.     _pr_flock_lock = PR_NewLock();
  983.     PR_ASSERT(NULL != _pr_flock_lock);
  984.     _pr_rename_lock = PR_NewLock();
  985.     PR_ASSERT(NULL != _pr_rename_lock);
  986.  
  987.     pt_fd_cache.ml = PR_NewLock();
  988.     PR_ASSERT(NULL != pt_fd_cache.ml);
  989.     pt_fd_cache.limit = FD_SETSIZE;
  990. }  /* _PR_InitIO */
  991.  
  992. static PRStatus pt_InitIOContinuation()
  993. {
  994.     PRIntn rv;
  995.  
  996.     PR_ASSERT((0 == pt_tq.op_count)
  997.         && (NULL == pt_tq.head)
  998.         && (NULL == pt_tq.tail)
  999.         && (NULL == pt_tq.op)
  1000.         && (PR_FALSE == pt_tq.exitFlag));
  1001.  
  1002.     if (NULL == pt_tq.ml)
  1003.     {
  1004.         /* The very first time */
  1005.         pt_tq.ml = PR_NewLock();
  1006.         PR_ASSERT(NULL != pt_tq.ml);
  1007.         pt_tq.new_op = PR_NewCondVar(pt_tq.ml);
  1008.         PR_ASSERT(NULL != pt_tq.new_op);
  1009.         rv = PTHREAD_CONDATTR_INIT(&_pt_cvar_attr);
  1010.         PR_ASSERT(0 == rv);
  1011.  
  1012. #if !defined(PT_NO_ATFORK)
  1013.     rv = pthread_atfork(pt_BeforeFork,
  1014.             pt_AfterForkParent, pt_AfterForkChild);
  1015.         PR_ASSERT(0 == rv);
  1016. #endif
  1017.     }
  1018.  
  1019.     pt_tq.thread = PR_CreateThread(
  1020.         PR_SYSTEM_THREAD, ContinuationThread, NULL,
  1021.         PR_PRIORITY_URGENT, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
  1022.     PR_ASSERT(NULL != pt_tq.thread);
  1023.  
  1024.     return PR_SUCCESS;
  1025. }
  1026.  
  1027. PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
  1028. {
  1029.     PRFileDesc *result = NULL;
  1030.     PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
  1031.  
  1032.     if (!_pr_initialized) _PR_ImplicitInitialization();
  1033.     
  1034.     switch (osfd)
  1035.     {
  1036.         case PR_StandardInput: result = _pr_stdin; break;
  1037.         case PR_StandardOutput: result = _pr_stdout; break;
  1038.         case PR_StandardError: result = _pr_stderr; break;
  1039.         default:
  1040.             (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1041.     }
  1042.     return result;
  1043. }  /* PR_GetSpecialFD */
  1044.  
  1045. /*****************************************************************************/
  1046. /***************************** I/O private methods ***************************/
  1047. /*****************************************************************************/
  1048.  
  1049. static PRBool pt_TestAbort(void)
  1050. {
  1051.     PRThread *me = PR_CurrentThread();
  1052.     if(me->state & PT_THREAD_ABORTED)
  1053.     {
  1054.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  1055.         me->state &= ~PT_THREAD_ABORTED;
  1056.         return PR_TRUE;
  1057.     }
  1058.     return PR_FALSE;
  1059. }  /* pt_TestAbort */
  1060.  
  1061. static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
  1062. {
  1063.     switch (syserrno)
  1064.     {
  1065.         case EINTR:
  1066.             PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
  1067.         case ETIMEDOUT:
  1068.             PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
  1069.         default:
  1070.             mapper(syserrno);
  1071.     }
  1072. }  /* pt_MapError */
  1073.  
  1074. static PRStatus pt_Close(PRFileDesc *fd)
  1075. {
  1076.     PRIntn syserrno, rv = 0;
  1077.     if ((NULL == fd) || (NULL == fd->secret))
  1078.     {
  1079.         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1080.         return PR_FAILURE;
  1081.     }
  1082.     if (pt_TestAbort()) return PR_FAILURE;
  1083.  
  1084.     if (_PR_FILEDESC_OPEN == fd->secret->state)
  1085.     {
  1086.         fd->secret->state = _PR_FILEDESC_CLOSED;
  1087.         rv = close(fd->secret->md.osfd);
  1088.         syserrno = errno;
  1089.     }
  1090.  
  1091.     pt_Putfd(fd);
  1092.     if (-1 == rv)
  1093.     {
  1094.         pt_MapError(_PR_MD_MAP_CLOSE_ERROR, syserrno);
  1095.         return PR_FAILURE;
  1096.     }
  1097.     return PR_SUCCESS;
  1098. }  /* pt_Close */
  1099.  
  1100. static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
  1101. {
  1102.     PRInt32 syserrno, bytes = -1;
  1103.  
  1104.     if (pt_TestAbort()) return PR_FAILURE;
  1105.  
  1106.     bytes = read(fd->secret->md.osfd, buf, amount);
  1107.     syserrno = errno;
  1108.  
  1109.     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1110.         && (!fd->secret->nonblocking))
  1111.     {
  1112.         pt_Continuation op;
  1113.         op.arg1.osfd = fd->secret->md.osfd;
  1114.         op.arg2.buffer = buf;
  1115.         op.arg3.amount = amount;
  1116.         op.timeout = PR_INTERVAL_NO_TIMEOUT;
  1117.         op.function = pt_read_cont;
  1118.         op.event = POLLIN | POLLPRI;
  1119.         bytes = pt_Continue(&op);
  1120.         syserrno = op.syserrno;
  1121.     }
  1122.     if (bytes < 0)
  1123.         pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
  1124.     return bytes;
  1125. }  /* pt_Read */
  1126.  
  1127. static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
  1128. {
  1129.     PRInt32 syserrno, bytes = -1;
  1130.     PRBool fNeedContinue = PR_FALSE;
  1131.  
  1132.     if (pt_TestAbort()) return PR_FAILURE;
  1133.  
  1134.     bytes = write(fd->secret->md.osfd, buf, amount);
  1135.     syserrno = errno;
  1136.  
  1137.     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
  1138.     {
  1139.         buf = (char *) buf + bytes;
  1140.         amount -= bytes;
  1141.         fNeedContinue = PR_TRUE;
  1142.     }
  1143.     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1144.         && (!fd->secret->nonblocking) )
  1145.     {
  1146.         bytes = 0;
  1147.         fNeedContinue = PR_TRUE;
  1148.     }
  1149.  
  1150.     if (fNeedContinue == PR_TRUE)
  1151.     {
  1152.         pt_Continuation op;
  1153.         op.arg1.osfd = fd->secret->md.osfd;
  1154.         op.arg2.buffer = (void*)buf;
  1155.         op.arg3.amount = amount;
  1156.         op.timeout = PR_INTERVAL_NO_TIMEOUT;
  1157.         op.result.code = bytes;  /* initialize the number sent */
  1158.         op.function = pt_write_cont;
  1159.         op.event = POLLOUT | POLLPRI;
  1160.         bytes = pt_Continue(&op);
  1161.         syserrno = op.syserrno;
  1162.     }
  1163.     if (bytes == -1)
  1164.         pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
  1165.     return bytes;
  1166. }  /* pt_Write */
  1167.  
  1168. static PRInt32 pt_Writev(
  1169.     PRFileDesc *fd, PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
  1170. {
  1171.     PRIntn iov_index = 0;
  1172.     PRBool fNeedContinue = PR_FALSE;
  1173.     PRInt32 syserrno, bytes = -1, rv = -1;
  1174.  
  1175.     if (pt_TestAbort()) return rv;
  1176.  
  1177.     /*
  1178.      * The first shot at this can use the client's iov directly.
  1179.      * Only if we have to continue the operation do we have to
  1180.      * make a copy that we can modify.
  1181.      */
  1182.     rv = bytes = writev(fd->secret->md.osfd, (struct iovec*)iov, iov_len);
  1183.     syserrno = errno;
  1184.  
  1185.     /*
  1186.      * If we moved some bytes (ie., bytes > 0) how does that implicate
  1187.      * the i/o vector list. In other words, exactly where are we within
  1188.      * that array? What are the parameters for resumption? Maybe we're
  1189.      * done!
  1190.      */
  1191.     if ((bytes > 0) && (!fd->secret->nonblocking))
  1192.     {
  1193.         for (iov_index = 0; iov_index < iov_len; ++iov_index)
  1194.         {
  1195.             if (bytes < iov[iov_index].iov_len) break; /* continue w/ what's left */
  1196.             bytes -= iov[iov_index].iov_len;  /* this one's done cooked */
  1197.         }
  1198.     }
  1199.  
  1200.     if ((bytes >= 0) && (iov_index < iov_len) && (!fd->secret->nonblocking))
  1201.     {
  1202.         if (PR_INTERVAL_NO_WAIT == timeout)
  1203.         {
  1204.             rv = -1;
  1205.             syserrno = ETIMEDOUT;
  1206.         }
  1207.         else fNeedContinue = PR_TRUE;
  1208.     }
  1209.     else if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1210.         && (!fd->secret->nonblocking))
  1211.     {
  1212.         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1213.         else
  1214.         {
  1215.             rv = bytes = 0;
  1216.             fNeedContinue = PR_TRUE;
  1217.         }
  1218.     }
  1219.  
  1220.     if (fNeedContinue == PR_TRUE)
  1221.     {
  1222.         pt_Continuation op;
  1223.         /*
  1224.          * Okay. Now we need a modifiable copy of the array.
  1225.          * Allocate some storage and copy the (already) modified
  1226.          * bits into the new vector. The is copying only the
  1227.          * part of the array that's still valid. The array may
  1228.          * have a new length and the first element of the array may
  1229.          * have different values.
  1230.          */
  1231.         struct iovec *osiov = NULL, *tiov;
  1232.         PRIntn osiov_len = iov_len - iov_index;  /* recompute */
  1233.         osiov = (struct iovec*)PR_Malloc(osiov_len * sizeof(struct iovec));
  1234.         PR_ASSERT(NULL != osiov);
  1235.         for (tiov = osiov; iov_index < iov_len; ++iov_index)
  1236.         {
  1237.             tiov->iov_base = iov[iov_index].iov_base;
  1238.             tiov->iov_len = iov[iov_index].iov_len;
  1239.             tiov += 1;
  1240.         }
  1241.         osiov->iov_len -= bytes;  /* that may be partially done */
  1242.         /* so advance the description */
  1243.         osiov->iov_base = (char*)osiov->iov_base + bytes;
  1244.  
  1245.         op.arg1.osfd = fd->secret->md.osfd;
  1246.         op.arg2.buffer = (void*)osiov;
  1247.         op.arg3.amount = osiov_len;
  1248.         op.timeout = timeout;
  1249.         op.result.code = rv;
  1250.         op.function = pt_writev_cont;
  1251.         op.event = POLLOUT | POLLPRI;
  1252.         rv = pt_Continue(&op);
  1253.         syserrno = op.syserrno;
  1254.         PR_DELETE(osiov);
  1255.     }
  1256.     if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
  1257.     return rv;
  1258. }  /* pt_Writev */
  1259.  
  1260. static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
  1261. {
  1262.     PRIntn how;
  1263.     off_t pos = -1;
  1264.     
  1265.     if (pt_TestAbort()) return pos;
  1266.  
  1267.     switch (whence)
  1268.     {
  1269.         case PR_SEEK_SET: how = SEEK_SET; break;
  1270.         case PR_SEEK_CUR: how = SEEK_CUR; break;
  1271.         case PR_SEEK_END: how = SEEK_END; break;
  1272.         default:
  1273.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1274.             return pos;
  1275.     }
  1276.     pos = lseek(fd->secret->md.osfd, offset, how);
  1277.     if (pos == -1)
  1278.         pt_MapError(_PR_MD_MAP_LSEEK_ERROR, errno);
  1279.     return pos;
  1280. }  /* pt_Seek */
  1281.  
  1282. static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
  1283. {
  1284.     PRInt64 on;
  1285.     PRInt32 off, position = -1;
  1286.     LL_L2I(off, offset);  /* possible loss of bits */
  1287.     LL_I2L(on, off);  /* get back original or notice we didn't */
  1288.     if (LL_EQ(on, offset)) position = pt_Seek(fd, off, whence);
  1289.     LL_I2L(on, position);  /* might not have worked */
  1290.     return on;
  1291. }  /* pt_Seek64 */
  1292.  
  1293. static PRInt32 pt_Available(PRFileDesc *fd)
  1294. {
  1295.     PRInt32 rv, bytes = -1;
  1296.     if (pt_TestAbort()) return bytes;
  1297.  
  1298.     rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
  1299.  
  1300.     if (rv == -1)
  1301.         pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
  1302.     return bytes;
  1303. }  /* pt_Available */
  1304.  
  1305. static PRInt64 pt_Available64(PRFileDesc *fd)
  1306. {
  1307.     PRInt64 rv;
  1308.     PRInt32 avail = pt_Available(fd);
  1309.     LL_I2L(rv, avail);
  1310.     return rv;
  1311. }  /* pt_Available64 */
  1312.  
  1313. static PRStatus pt_Synch(PRFileDesc *fd)
  1314. {
  1315.     return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
  1316. } /* pt_Synch */
  1317.  
  1318. static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
  1319. {
  1320.     PRInt32 rv;
  1321.     struct stat sb;
  1322.     PRInt64 s, s2us;
  1323.  
  1324.     if ((rv = fstat(fd->secret->md.osfd, &sb)) == 0 )
  1325.     {
  1326.         if (info)
  1327.         {
  1328.             if (S_IFREG & sb.st_mode)
  1329.                 info->type = PR_FILE_FILE ;
  1330.             else if (S_IFDIR & sb.st_mode)
  1331.                 info->type = PR_FILE_DIRECTORY;
  1332.             else
  1333.                 info->type = PR_FILE_OTHER;
  1334.             info->size = sb.st_size;
  1335. #if defined(IRIX) && defined(HAVE_LONG_LONG)
  1336.             info->modifyTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_mtim.tv_sec);
  1337.             info->creationTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_ctim.tv_sec);
  1338.             info->modifyTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_mtime);
  1339.             info->creationTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_ctime);
  1340. #else
  1341.             LL_I2L(s, sb.st_mtime);
  1342.             LL_I2L(s2us, PR_USEC_PER_SEC);
  1343.             LL_MUL(s, s, s2us);
  1344.             info->modifyTime = s;
  1345.             LL_I2L(s, sb.st_ctime);
  1346.             LL_MUL(s, s, s2us);
  1347.             info->creationTime = s;
  1348. #endif
  1349.         }
  1350.     }
  1351.     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  1352. }  /* pt_FileInfo */
  1353.  
  1354. static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
  1355. {
  1356.     PRFileInfo info32;
  1357.     PRStatus rv = pt_FileInfo(fd, &info32);
  1358.     if (PR_SUCCESS == rv)
  1359.     {
  1360.         info->type = info32.type;
  1361.         info->creationTime = info32.creationTime;
  1362.         info->modifyTime = info32.modifyTime;
  1363.         LL_I2L(info->size, info32.size);
  1364.     }
  1365.     return rv;
  1366. }  /* pt_FileInfo64 */
  1367.  
  1368. static PRStatus pt_Fsync(PRFileDesc *fd)
  1369. {
  1370.     PRIntn rv = -1;
  1371.     if (pt_TestAbort()) return PR_FAILURE;
  1372.  
  1373.     rv = fsync(fd->secret->md.osfd);
  1374.     if (rv < 0) {
  1375.         pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
  1376.         return PR_FAILURE;
  1377.     }
  1378.     return PR_SUCCESS;
  1379. }  /* pt_Fsync */
  1380.  
  1381. static PRStatus pt_Connect(
  1382.     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
  1383. {
  1384.     PRIntn rv = -1, syserrno;
  1385.     PRSize addr_len = PR_NETADDR_SIZE(addr);
  1386.  
  1387.     if (pt_TestAbort()) return PR_FAILURE;
  1388.  
  1389.     rv = connect(fd->secret->md.osfd, (struct sockaddr*)addr, addr_len);
  1390.     syserrno = errno;
  1391.     if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
  1392.     {
  1393.         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1394.         else
  1395.         {
  1396.             pt_Continuation op;
  1397.             op.arg1.osfd = fd->secret->md.osfd;
  1398.             op.arg2.buffer = (void*)addr;
  1399.             op.arg3.amount = addr_len;
  1400.             op.timeout = timeout;
  1401.             op.function = pt_connect_cont;
  1402.             op.event = POLLOUT | POLLPRI;
  1403.             rv = pt_Continue(&op);
  1404.             syserrno = op.syserrno;
  1405.         }
  1406.     }
  1407.     if (-1 == rv) {
  1408.         pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
  1409.         return PR_FAILURE;
  1410.     }
  1411.     return PR_SUCCESS;
  1412. }  /* pt_Connect */
  1413.  
  1414. PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
  1415. {
  1416.     PRInt32 osfd;
  1417.     PRFileDesc *bottom = pd->fd;
  1418.     int err;
  1419.  
  1420.     if (pd->out_flags & PR_POLL_NVAL) {
  1421.         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1422.         return PR_FAILURE;
  1423.     }
  1424.     if ((pd->out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
  1425.         PR_ASSERT(pd->out_flags == 0);
  1426.         PR_SetError(PR_IN_PROGRESS_ERROR, 0);
  1427.         return PR_FAILURE;
  1428.     }
  1429.  
  1430.     while (bottom->lower != NULL) {
  1431.         bottom = bottom->lower;
  1432.     }
  1433.     osfd = bottom->secret->md.osfd;
  1434.  
  1435.     err = _MD_unix_get_nonblocking_connect_error(osfd);
  1436.     if (err != 0) {
  1437.         _PR_MD_MAP_CONNECT_ERROR(err);
  1438.         return PR_FAILURE;
  1439.     }
  1440.     return PR_SUCCESS;
  1441. }
  1442.  
  1443. static PRFileDesc* pt_Accept(
  1444.     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
  1445. {
  1446.     PRFileDesc *newfd = NULL;
  1447.     PRIntn syserrno, osfd = -1;
  1448.     pt_SockLen addr_len = sizeof(PRNetAddr);
  1449.  
  1450.     if (pt_TestAbort()) return newfd;
  1451.  
  1452.     osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1453.     syserrno = errno;
  1454.  
  1455.     if (osfd == -1)
  1456.     {
  1457.         if (fd->secret->nonblocking) goto failed;
  1458.  
  1459.         if (EWOULDBLOCK != syserrno && EAGAIN != syserrno) goto failed;
  1460.         else
  1461.         {
  1462.             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1463.             else
  1464.             {
  1465.                 pt_Continuation op;
  1466.                 op.arg1.osfd = fd->secret->md.osfd;
  1467.                 op.arg2.buffer = addr;
  1468.                 op.arg3.addr_len = &addr_len;
  1469.                 op.timeout = timeout;
  1470.                 op.function = pt_accept_cont;
  1471.                 op.event = POLLIN | POLLPRI;
  1472.                 osfd = pt_Continue(&op);
  1473.                 syserrno = op.syserrno;
  1474.             }
  1475.             if (osfd < 0) goto failed;
  1476.         }
  1477.     }
  1478. #ifdef AIX
  1479.     /* mask off the first byte of struct sockaddr (the length field) */
  1480.     if (addr)
  1481.     addr->inet.family &= 0x00ff;
  1482. #endif
  1483.     newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP);
  1484.     if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
  1485.     else
  1486.     {
  1487.         PR_ASSERT((NULL == addr) || (PR_NETADDR_SIZE(addr) == addr_len));
  1488. #if defined(_PR_INET6)
  1489.         PR_ASSERT((NULL == addr) || (addr->raw.family == AF_INET)
  1490.                 || (addr->raw.family == AF_INET6));
  1491. #else
  1492.         PR_ASSERT((NULL == addr) || (addr->raw.family == AF_INET));
  1493. #endif
  1494.     }
  1495.     return newfd;
  1496.  
  1497. failed:
  1498.     pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
  1499.     return NULL;
  1500. }  /* pt_Accept */
  1501.  
  1502. static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
  1503. {
  1504.     PRIntn rv;
  1505.     PRInt32 one = 1;
  1506.  
  1507.     if (pt_TestAbort()) return PR_FAILURE;
  1508.  
  1509. #if defined(_PR_INET6)
  1510.     PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  1511. #else
  1512.     PR_ASSERT(addr->raw.family == AF_INET);
  1513. #endif
  1514.  
  1515.     rv = setsockopt(
  1516.         fd->secret->md.osfd, SOL_SOCKET, SO_REUSEADDR,
  1517.         (_PRSockOptVal_t) &one, sizeof(one));
  1518.     if (rv == -1) {
  1519.         pt_MapError(_PR_MD_MAP_SETSOCKOPT_ERROR, errno);
  1520.         return PR_FAILURE;
  1521.     }
  1522.  
  1523.     rv = bind(fd->secret->md.osfd, (struct sockaddr*)addr, PR_NETADDR_SIZE(addr));
  1524.  
  1525.     if (rv == -1) {
  1526.         pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
  1527.         return PR_FAILURE;
  1528.     }
  1529.     return PR_SUCCESS;
  1530. }  /* pt_Bind */
  1531.  
  1532. static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
  1533. {
  1534.     PRIntn rv;
  1535.  
  1536.     if (pt_TestAbort()) return PR_FAILURE;
  1537.  
  1538.     rv = listen(fd->secret->md.osfd, backlog);
  1539.     if (rv == -1) {
  1540.         pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
  1541.         return PR_FAILURE;
  1542.     }
  1543.     return PR_SUCCESS;
  1544. }  /* pt_Listen */
  1545.  
  1546. static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
  1547. {
  1548.     PRIntn rv = -1;
  1549.     if (pt_TestAbort()) return PR_FAILURE;
  1550.  
  1551.     rv = shutdown(fd->secret->md.osfd, how);
  1552.  
  1553.     if (rv == -1) {
  1554.         pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
  1555.         return PR_FAILURE;
  1556.     }
  1557.     return PR_SUCCESS;
  1558. }  /* pt_Shutdown */
  1559.  
  1560. static PRInt32 pt_Recv(
  1561.     PRFileDesc *fd, void *buf, PRInt32 amount,
  1562.     PRIntn flags, PRIntervalTime timeout)
  1563. {
  1564.     PRInt32 syserrno, bytes = -1;
  1565.  
  1566.     if (pt_TestAbort()) return PR_FAILURE;
  1567.  
  1568.     bytes = recv(fd->secret->md.osfd, buf, amount, flags);
  1569.     syserrno = errno;
  1570.  
  1571.     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1572.         && (!fd->secret->nonblocking))
  1573.     {
  1574.         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1575.         else
  1576.         {
  1577.             pt_Continuation op;
  1578.             op.arg1.osfd = fd->secret->md.osfd;
  1579.             op.arg2.buffer = buf;
  1580.             op.arg3.amount = amount;
  1581.             op.arg4.flags = flags;
  1582.             op.timeout = timeout;
  1583.             op.function = pt_recv_cont;
  1584.             op.event = POLLIN | POLLPRI;
  1585.             bytes = pt_Continue(&op);
  1586.             syserrno = op.syserrno;
  1587.         }
  1588.     }
  1589.     if (bytes < 0)
  1590.         pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
  1591.     return bytes;
  1592. }  /* pt_Recv */
  1593.  
  1594. static PRInt32 pt_Send(
  1595.     PRFileDesc *fd, const void *buf, PRInt32 amount,
  1596.     PRIntn flags, PRIntervalTime timeout)
  1597. {
  1598.     PRInt32 syserrno, bytes = -1;
  1599.     PRBool fNeedContinue = PR_FALSE;
  1600.  
  1601.     /*
  1602.      * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
  1603.      * which has the following:
  1604.      *     #  define send        cma_send
  1605.      *     extern int  cma_send (int , void *, int, int );
  1606.      * So we need to cast away the 'const' of argument #2 for send().
  1607.      */
  1608. #if defined (HPUX) && defined(_PR_DCETHREADS)
  1609. #define PT_SENDBUF_CAST (void *)
  1610. #else
  1611. #define PT_SENDBUF_CAST
  1612. #endif
  1613.  
  1614.     if (pt_TestAbort()) return PR_FAILURE;
  1615.  
  1616.     bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
  1617.     syserrno = errno;
  1618.  
  1619.     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
  1620.     {
  1621.         if (PR_INTERVAL_NO_WAIT == timeout)
  1622.         {
  1623.             bytes = -1;
  1624.             syserrno = ETIMEDOUT;
  1625.         }
  1626.         else
  1627.         {
  1628.             buf = (char *) buf + bytes;
  1629.             amount -= bytes;
  1630.             fNeedContinue = PR_TRUE;
  1631.         }
  1632.     }
  1633.     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1634.         && (!fd->secret->nonblocking) )
  1635.     {
  1636.         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1637.         else
  1638.         {
  1639.             bytes = 0;
  1640.             fNeedContinue = PR_TRUE;
  1641.         }
  1642.     }
  1643.  
  1644.     if (fNeedContinue == PR_TRUE)
  1645.     {
  1646.         pt_Continuation op;
  1647.         op.arg1.osfd = fd->secret->md.osfd;
  1648.         op.arg2.buffer = (void*)buf;
  1649.         op.arg3.amount = amount;
  1650.         op.arg4.flags = flags;
  1651.         op.timeout = timeout;
  1652.         op.result.code = bytes;  /* initialize the number sent */
  1653.         op.function = pt_send_cont;
  1654.         op.event = POLLOUT | POLLPRI;
  1655.         bytes = pt_Continue(&op);
  1656.         syserrno = op.syserrno;
  1657.     }
  1658.     if (bytes == -1)
  1659.         pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
  1660.     return bytes;
  1661. }  /* pt_Send */
  1662.  
  1663. static PRInt32 pt_SendTo(
  1664.     PRFileDesc *fd, const void *buf,
  1665.     PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
  1666.     PRIntervalTime timeout)
  1667. {
  1668.     PRInt32 syserrno, bytes = -1;
  1669.     PRBool fNeedContinue = PR_FALSE;
  1670.  
  1671.     if (pt_TestAbort()) return PR_FAILURE;
  1672.  
  1673. #if defined(_PR_INET6)
  1674.     PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  1675. #else
  1676.     PR_ASSERT(addr->raw.family == AF_INET);
  1677. #endif
  1678.     bytes = sendto(
  1679.         fd->secret->md.osfd, buf, amount, flags,
  1680.         (struct sockaddr*)addr, PR_NETADDR_SIZE(addr));
  1681.     syserrno = errno;
  1682.     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1683.         && (!fd->secret->nonblocking) )
  1684.     {
  1685.         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1686.         else fNeedContinue = PR_TRUE;
  1687.     }
  1688.     if (fNeedContinue == PR_TRUE)
  1689.     {
  1690.         pt_Continuation op;
  1691.         op.arg1.osfd = fd->secret->md.osfd;
  1692.         op.arg2.buffer = (void*)buf;
  1693.         op.arg3.amount = amount;
  1694.         op.arg4.flags = flags;
  1695.         op.arg5.addr = (PRNetAddr*)addr;
  1696.         op.timeout = timeout;
  1697.         op.result.code = 0;  /* initialize the number sent */
  1698.         op.function = pt_sendto_cont;
  1699.         op.event = POLLOUT | POLLPRI;
  1700.         bytes = pt_Continue(&op);
  1701.         syserrno = op.syserrno;
  1702.     }
  1703.     if (bytes < 0)
  1704.         pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
  1705.     return bytes;
  1706. }  /* pt_SendTo */
  1707.  
  1708. static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
  1709.     PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
  1710. {
  1711.     PRBool fNeedContinue = PR_FALSE;
  1712.     PRInt32 syserrno, bytes = -1;
  1713.     pt_SockLen addr_len = sizeof(PRNetAddr);
  1714.  
  1715.     if (pt_TestAbort()) return PR_FAILURE;
  1716.  
  1717.     bytes = recvfrom(
  1718.         fd->secret->md.osfd, buf, amount, flags,
  1719.         (struct sockaddr*)addr, &addr_len);
  1720.     syserrno = errno;
  1721.  
  1722.     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1723.         && (!fd->secret->nonblocking) )
  1724.     {
  1725.         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1726.         else fNeedContinue = PR_TRUE;
  1727.     }
  1728.  
  1729.     if (fNeedContinue == PR_TRUE)
  1730.     {
  1731.         pt_Continuation op;
  1732.         op.arg1.osfd = fd->secret->md.osfd;
  1733.         op.arg2.buffer = buf;
  1734.         op.arg3.amount = amount;
  1735.         op.arg4.flags = flags;
  1736.         op.arg5.addr = addr;
  1737.         op.timeout = timeout;
  1738.         op.function = pt_recvfrom_cont;
  1739.         op.event = POLLIN | POLLPRI;
  1740.         bytes = pt_Continue(&op);
  1741.         syserrno = op.syserrno;
  1742.     }
  1743. #ifdef AIX
  1744.     /* mask off the first byte of struct sockaddr (the length field) */
  1745.     if (addr) addr->inet.family &= 0x00ff;
  1746. #endif
  1747.     if (bytes < 0)
  1748.         pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
  1749.     return bytes;
  1750. }  /* pt_RecvFrom */
  1751.  
  1752. #ifdef HPUX11
  1753. /*
  1754.  * pt_HPUXTransmitFile
  1755.  *
  1756.  *    Send file fd across socket sd. If headers is non-NULL, 'hlen'
  1757.  *    bytes of headers is sent before sending the file.
  1758.  *
  1759.  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  1760.  *    
  1761.  *    return number of bytes sent or -1 on error
  1762.  *
  1763.  *      This implementation takes advantage of the sendfile() system
  1764.  *      call available in HP-UX B.11.00.
  1765.  */
  1766.  
  1767. static PRInt32 pt_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
  1768.         const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
  1769.         PRIntervalTime timeout)
  1770. {
  1771.     struct stat statbuf;
  1772.     size_t nbytes_to_send;
  1773.     struct iovec hdtrl[2];  /* optional header and trailer buffers */
  1774.     int send_flags;
  1775.     PRInt32 count;
  1776.     int syserrno;
  1777.  
  1778.     /* Get file size */
  1779.     if (fstat(fd->secret->md.osfd, &statbuf) == -1) {
  1780.         _PR_MD_MAP_FSTAT_ERROR(errno);
  1781.         return -1;
  1782.     }
  1783.     nbytes_to_send = hlen + statbuf.st_size;
  1784.  
  1785.     hdtrl[0].iov_base = (void *) headers;  /* cast away the 'const' */
  1786.     hdtrl[0].iov_len = hlen;
  1787.     hdtrl[1].iov_base = NULL;
  1788.     hdtrl[1].iov_base = 0;
  1789.     /*
  1790.      * SF_DISCONNECT seems to close the socket even if sendfile()
  1791.      * only does a partial send on a nonblocking socket.  This
  1792.      * would prevent the subsequent sendfile() calls on that socket
  1793.      * from working.  So we don't use the SD_DISCONNECT flag.
  1794.      */
  1795.     send_flags = 0;
  1796.  
  1797.     do {
  1798.         count = sendfile(sd->secret->md.osfd, fd->secret->md.osfd,
  1799.                 0, 0, hdtrl, send_flags);
  1800.         PR_ASSERT(count <= nbytes_to_send);
  1801.     } while (count == -1 && (syserrno = errno) == EINTR);
  1802.  
  1803.     if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
  1804.         count = 0;
  1805.     }
  1806.     if (count != -1 && count < nbytes_to_send) {
  1807.         pt_Continuation op;
  1808.  
  1809.         if (count < hlen) {
  1810.             hdtrl[0].iov_base = ((char *) headers) + count;
  1811.             hdtrl[0].iov_len = hlen - count;
  1812.             op.arg3.offset = 0;
  1813.         } else {
  1814.             hdtrl[0].iov_base = NULL;
  1815.             hdtrl[0].iov_len = 0;
  1816.             op.arg3.offset = count - hlen;
  1817.         }
  1818.  
  1819.         op.arg1.osfd = sd->secret->md.osfd;
  1820.         op.filedesc = fd->secret->md.osfd;
  1821.         op.arg2.buffer = hdtrl;
  1822.         op.arg4.flags = send_flags;
  1823.         op.nbytes_to_send = nbytes_to_send - count;
  1824.         op.result.code = count;
  1825.         op.timeout = timeout;
  1826.         op.function = pt_hpux_transmitfile_cont;
  1827.         op.event = POLLOUT | POLLPRI;
  1828.         count = pt_Continue(&op);
  1829.         syserrno = op.syserrno;
  1830.     }
  1831.  
  1832.     if (count == -1) {
  1833.         _MD_hpux_map_sendfile_error(syserrno);
  1834.     return -1;
  1835.     }
  1836.     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  1837.         PR_Close(sd);
  1838.     }
  1839.     return count;
  1840. }
  1841. #endif  /* HPUX11 */
  1842.  
  1843. static PRInt32 pt_TransmitFile(
  1844.     PRFileDesc *sd, PRFileDesc *fd, const void *headers,
  1845.     PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
  1846. {
  1847.     if (pt_TestAbort()) return -1;
  1848.  
  1849. #ifdef HPUX11
  1850.     return pt_HPUXTransmitFile(sd, fd, headers, hlen, flags, timeout);
  1851. #else
  1852.     return _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
  1853. #endif
  1854. }  /* pt_TransmitFile */
  1855.  
  1856. /*
  1857.  * XXX: When IPv6 is running, we need to see if this code works
  1858.  * with a PRNetAddr structure that supports both IPv4 and IPv6.
  1859.  */
  1860. static PRInt32 pt_AcceptRead(
  1861.     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
  1862.     void *buf, PRInt32 amount, PRIntervalTime timeout)
  1863. {
  1864.     PRInt32 rv = -1;
  1865.     PRNetAddr remote;
  1866.     PRFileDesc *accepted = NULL;
  1867.     PRIntervalTime start, elapsed;
  1868.  
  1869.     if (pt_TestAbort()) return rv;
  1870.  
  1871.     if (PR_INTERVAL_NO_TIMEOUT != timeout) start = PR_IntervalNow();
  1872.     if ((accepted = PR_Accept(sd, &remote, timeout)) == NULL) return rv;
  1873.  
  1874.     if (PR_INTERVAL_NO_TIMEOUT != timeout)
  1875.     {
  1876.         elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
  1877.         if (elapsed > timeout)
  1878.         {
  1879.             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
  1880.             goto failed;
  1881.         }
  1882.         else timeout = timeout - elapsed;
  1883.     }
  1884.  
  1885.     rv = PR_Recv(accepted, buf, amount, 0, timeout);
  1886.     if (rv >= 0)
  1887.     {
  1888.         /* copy the new info out where caller can see it */
  1889.         *nd = accepted;
  1890.         *raddr = (PRNetAddr *)((char*)buf + amount);
  1891.         memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
  1892.         return rv;
  1893.     }
  1894.  
  1895. failed:
  1896.     PR_Close(accepted);
  1897.     return rv;
  1898. }  /* pt_AcceptRead */
  1899.  
  1900. static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
  1901. {
  1902.     PRIntn rv = -1;
  1903.     pt_SockLen addr_len = sizeof(PRNetAddr);
  1904.  
  1905.     if (pt_TestAbort()) return PR_FAILURE;
  1906.  
  1907.     rv = getsockname(
  1908.         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1909. #ifdef AIX
  1910.     /* mask off the first byte of struct sockaddr (the length field) */
  1911.     if (addr) addr->inet.family &= 0x00ff;
  1912. #endif
  1913.     if (rv == -1) {
  1914.         pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
  1915.         return PR_FAILURE;
  1916.     } else {
  1917.         PR_ASSERT(addr_len == PR_NETADDR_SIZE(addr));
  1918. #if defined(_PR_INET6)
  1919.         PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  1920. #else
  1921.     PR_ASSERT(addr->raw.family == AF_INET);
  1922. #endif
  1923.         return PR_SUCCESS;
  1924.     }
  1925. }  /* pt_GetSockName */
  1926.  
  1927. static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
  1928. {
  1929.     PRIntn rv = -1;
  1930.     pt_SockLen addr_len = sizeof(PRNetAddr);
  1931.  
  1932.     if (pt_TestAbort()) return PR_FAILURE;
  1933.  
  1934.     rv = getpeername(
  1935.         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1936.  
  1937. #ifdef AIX
  1938.     /* mask off the first byte of struct sockaddr (the length field) */
  1939.     if (addr) addr->inet.family &= 0x00ff;
  1940. #endif
  1941.     if (rv == -1) {
  1942.         pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
  1943.         return PR_FAILURE;
  1944.     } else {
  1945.         PR_ASSERT(addr_len == PR_NETADDR_SIZE(addr));
  1946. #if defined(_PR_INET6)
  1947.         PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  1948. #else
  1949.     PR_ASSERT(addr->raw.family == AF_INET);
  1950. #endif
  1951.         return PR_SUCCESS;
  1952.     }
  1953. }  /* pt_GetPeerName */
  1954.  
  1955. static PRStatus pt_GetSockOpt(
  1956.     PRFileDesc *fd, PRSockOption optname, void* optval, PRInt32* optlen)
  1957. {
  1958.     PRIntn rv = -1;
  1959.     PRInt32 level, name;
  1960.  
  1961.     if (pt_TestAbort()) return PR_FAILURE;
  1962.  
  1963.     /*
  1964.      * PR_SockOpt_Nonblocking is a special case that does not
  1965.      * translate to a getsockopt() call.
  1966.      */
  1967.     if (PR_SockOpt_Nonblocking == optname)
  1968.     {
  1969.         PR_ASSERT(sizeof(PRIntn) <= *optlen);
  1970.         *((PRIntn *) optval) = (PRIntn) fd->secret->nonblocking;
  1971.         *optlen = sizeof(PRIntn);
  1972.         return PR_SUCCESS;
  1973.     }
  1974.  
  1975.     rv = _PR_MapOptionName(optname, &level, &name);
  1976.     if (0 == rv)
  1977.     {
  1978.         if (PR_SockOpt_Linger == optname)
  1979.         {
  1980.             struct linger linger;
  1981.             pt_SockLen len = sizeof(linger);
  1982.             rv = getsockopt(fd->secret->md.osfd, level, name,
  1983.                 (char *) &linger, &len);
  1984.             if (0 == rv)
  1985.             {
  1986.                 ((PRLinger*)(optval))->polarity = linger.l_onoff
  1987.                     ? PR_TRUE : PR_FALSE;
  1988.                 ((PRLinger*)(optval))->linger = PR_SecondsToInterval(
  1989.                     linger.l_linger);
  1990.                 *optlen = sizeof(PRLinger);
  1991.             }
  1992.         }
  1993.         else
  1994.         {
  1995.             /* Make sure the pointer type cast below is safe */
  1996.             PR_ASSERT(sizeof(PRInt32) == sizeof(PRIntn));
  1997.             rv = getsockopt(fd->secret->md.osfd, level, name,
  1998.                 optval, (pt_SockLen*)optlen);
  1999.         }
  2000.     }
  2001.  
  2002.     if (rv == -1) {
  2003.         pt_MapError(_PR_MD_MAP_GETSOCKOPT_ERROR, errno);
  2004.         return PR_FAILURE;
  2005.     } else {
  2006.         return PR_SUCCESS;
  2007.     }
  2008. }  /* pt_GetSockOpt */
  2009.  
  2010. static PRStatus pt_SetSockOpt(
  2011.     PRFileDesc *fd, PRSockOption optname, const void* optval, PRInt32 optlen)
  2012. {
  2013.     PRIntn rv = -1;
  2014.     PRInt32 level, name;
  2015.  
  2016.     if (pt_TestAbort()) return PR_FAILURE;
  2017.  
  2018.     /*
  2019.      * PR_SockOpt_Nonblocking is a special case that does not
  2020.      * translate to a setsockopt() call.
  2021.      */
  2022.     if (PR_SockOpt_Nonblocking == optname)
  2023.     {
  2024.         PR_ASSERT(sizeof(PRIntn) == optlen);
  2025.         fd->secret->nonblocking = *((PRIntn *) optval) ? PR_TRUE : PR_FALSE;
  2026.         return PR_SUCCESS;
  2027.     }
  2028.  
  2029.     rv = _PR_MapOptionName(optname, &level, &name);
  2030.     if (0 == rv)
  2031.     {
  2032.         if (PR_SockOpt_Linger == optname)
  2033.         {
  2034.             struct linger linger;
  2035.             linger.l_onoff = ((PRLinger*)(optval))->polarity;
  2036.             linger.l_linger = PR_IntervalToSeconds(
  2037.                 ((PRLinger*)(optval))->linger);
  2038.             rv = setsockopt(fd->secret->md.osfd, level, name,
  2039.                 (char *) &linger, sizeof(linger));
  2040.         }
  2041.         else
  2042.         {
  2043.             rv = setsockopt(fd->secret->md.osfd, level, name,
  2044.                 optval, optlen);
  2045.         }
  2046.     }
  2047.  
  2048.     if (rv == -1) {
  2049.         pt_MapError(_PR_MD_MAP_SETSOCKOPT_ERROR, errno);
  2050.         return PR_FAILURE;
  2051.     } else {
  2052.         return PR_SUCCESS;
  2053.     }
  2054. }  /* pt_SetSockOpt */
  2055.  
  2056. static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
  2057. {
  2058.     PRIntn rv;
  2059.     pt_SockLen length;
  2060.     PRInt32 level, name;
  2061.  
  2062.     /*
  2063.      * PR_SockOpt_Nonblocking is a special case that does not
  2064.      * translate to a getsockopt() call
  2065.      */
  2066.     if (PR_SockOpt_Nonblocking == data->option)
  2067.     {
  2068.         data->value.non_blocking = fd->secret->nonblocking;
  2069.         return PR_SUCCESS;
  2070.     }
  2071.  
  2072.     rv = _PR_MapOptionName(data->option, &level, &name);
  2073.     if (PR_SUCCESS == rv)
  2074.     {
  2075.         switch (data->option)
  2076.         {
  2077.             case PR_SockOpt_Linger:
  2078.             {
  2079.                 struct linger linger;
  2080.                 length = sizeof(linger);
  2081.                 rv = getsockopt(
  2082.                     fd->secret->md.osfd, level, name, (char *) &linger, &length);
  2083.                 PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
  2084.                 data->value.linger.polarity =
  2085.                     (linger.l_onoff) ? PR_TRUE : PR_FALSE;
  2086.                 data->value.linger.linger =
  2087.                     PR_SecondsToInterval(linger.l_linger);
  2088.                 break;
  2089.             }
  2090.             case PR_SockOpt_Reuseaddr:
  2091.             case PR_SockOpt_Keepalive:
  2092.             case PR_SockOpt_NoDelay:
  2093.             {
  2094.                 PRIntn value;
  2095.                 length = sizeof(PRIntn);
  2096.                 rv = getsockopt(
  2097.                     fd->secret->md.osfd, level, name, (char*)&value, &length);
  2098.                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  2099.                 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
  2100.                 break;
  2101.             }
  2102.             case PR_SockOpt_McastLoopback:
  2103.             {
  2104.                 PRUint8 boolean;
  2105.                 length = sizeof(boolean);
  2106.                 rv = getsockopt(
  2107.                     fd->secret->md.osfd, level, name,
  2108.                     (char*)&boolean, &length);
  2109.                 PR_ASSERT((-1 == rv) || (sizeof(boolean) == length));
  2110.                 data->value.mcast_loopback = (0 == boolean) ? PR_FALSE : PR_TRUE;
  2111.                 break;
  2112.             }
  2113.             case PR_SockOpt_RecvBufferSize:
  2114.             case PR_SockOpt_SendBufferSize:
  2115.             case PR_SockOpt_MaxSegment:
  2116.             {
  2117.                 PRIntn value;
  2118.                 length = sizeof(PRIntn);
  2119.                 rv = getsockopt(
  2120.                     fd->secret->md.osfd, level, name, (char*)&value, &length);
  2121.                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  2122.                 data->value.recv_buffer_size = value;
  2123.                 break;
  2124.             }
  2125.             case PR_SockOpt_IpTimeToLive:
  2126.             case PR_SockOpt_IpTypeOfService:
  2127.             {
  2128.                 length = sizeof(PRUintn);
  2129.                 rv = getsockopt(
  2130.                     fd->secret->md.osfd, level, name,
  2131.                     (char*)&data->value.ip_ttl, &length);
  2132.                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  2133.                 break;
  2134.             }
  2135.             case PR_SockOpt_McastTimeToLive:
  2136.             {
  2137.                 PRUint8 ttl;
  2138.                 length = sizeof(ttl);
  2139.                 rv = getsockopt(
  2140.                     fd->secret->md.osfd, level, name,
  2141.                     (char*)&ttl, &length);
  2142.                 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
  2143.                 data->value.mcast_ttl = ttl;
  2144.                 break;
  2145.             }
  2146.             case PR_SockOpt_AddMember:
  2147.             case PR_SockOpt_DropMember:
  2148.             {
  2149.                 struct ip_mreq mreq;
  2150.                 length = sizeof(mreq);
  2151.                 rv = getsockopt(
  2152.                     fd->secret->md.osfd, level, name, (char*)&mreq, &length);
  2153.                 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
  2154.                 data->value.add_member.mcaddr.inet.ip =
  2155.                     mreq.imr_multiaddr.s_addr;
  2156.                 data->value.add_member.ifaddr.inet.ip =
  2157.                     mreq.imr_interface.s_addr;
  2158.                 break;
  2159.             }
  2160.             case PR_SockOpt_McastInterface:
  2161.             {
  2162.                 length = sizeof(data->value.mcast_if.inet.ip);
  2163.                 rv = getsockopt(
  2164.                     fd->secret->md.osfd, level, name,
  2165.                     (char*)&data->value.mcast_if.inet.ip, &length);
  2166.                 PR_ASSERT((-1 == rv)
  2167.                     || (sizeof(data->value.mcast_if.inet.ip) == length));
  2168.                 break;
  2169.             }
  2170.             default:
  2171.                 PR_NOT_REACHED("Unknown socket option");
  2172.                 break;
  2173.         }
  2174.         if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
  2175.     }
  2176.     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  2177. }  /* pt_GetSocketOption */
  2178.  
  2179. static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
  2180. {
  2181.     PRIntn rv;
  2182.     PRInt32 level, name;
  2183.  
  2184.     /*
  2185.      * PR_SockOpt_Nonblocking is a special case that does not
  2186.      * translate to a setsockopt call.
  2187.      */
  2188.     if (PR_SockOpt_Nonblocking == data->option)
  2189.     {
  2190.         fd->secret->nonblocking = data->value.non_blocking;
  2191.         return PR_SUCCESS;
  2192.     }
  2193.  
  2194.     rv = _PR_MapOptionName(data->option, &level, &name);
  2195.     if (PR_SUCCESS == rv)
  2196.     {
  2197.         switch (data->option)
  2198.         {
  2199.             case PR_SockOpt_Linger:
  2200.             {
  2201.                 struct linger linger;
  2202.                 linger.l_onoff = data->value.linger.polarity;
  2203.                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
  2204.                 rv = setsockopt(
  2205.                     fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
  2206.                 break;
  2207.             }
  2208.             case PR_SockOpt_Reuseaddr:
  2209.             case PR_SockOpt_Keepalive:
  2210.             case PR_SockOpt_NoDelay:
  2211.             {
  2212.                 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
  2213.                 rv = setsockopt(
  2214.                     fd->secret->md.osfd, level, name,
  2215.                     (char*)&value, sizeof(PRIntn));
  2216.                 break;
  2217.             }
  2218.             case PR_SockOpt_McastLoopback:
  2219.             {
  2220.                 PRUint8 boolean = data->value.mcast_loopback ? 1 : 0;
  2221.                 rv = setsockopt(
  2222.                     fd->secret->md.osfd, level, name,
  2223.                     (char*)&boolean, sizeof(boolean));
  2224.                 break;
  2225.             }
  2226.             case PR_SockOpt_RecvBufferSize:
  2227.             case PR_SockOpt_SendBufferSize:
  2228.             case PR_SockOpt_MaxSegment:
  2229.             {
  2230.                 PRIntn value = data->value.recv_buffer_size;
  2231.                 rv = setsockopt(
  2232.                     fd->secret->md.osfd, level, name,
  2233.                     (char*)&value, sizeof(PRIntn));
  2234.                 break;
  2235.             }
  2236.             case PR_SockOpt_IpTimeToLive:
  2237.             case PR_SockOpt_IpTypeOfService:
  2238.             {
  2239.                 rv = setsockopt(
  2240.                     fd->secret->md.osfd, level, name,
  2241.                     (char*)&data->value.ip_ttl, sizeof(PRUintn));
  2242.                 break;
  2243.             }
  2244.             case PR_SockOpt_McastTimeToLive:
  2245.             {
  2246.                 PRUint8 ttl = data->value.mcast_ttl;
  2247.                 rv = setsockopt(
  2248.                     fd->secret->md.osfd, level, name,
  2249.                     (char*)&ttl, sizeof(ttl));
  2250.                 break;
  2251.             }
  2252.             case PR_SockOpt_AddMember:
  2253.             case PR_SockOpt_DropMember:
  2254.             {
  2255.                 struct ip_mreq mreq;
  2256.                 mreq.imr_multiaddr.s_addr =
  2257.                     data->value.add_member.mcaddr.inet.ip;
  2258.                 mreq.imr_interface.s_addr =
  2259.                     data->value.add_member.ifaddr.inet.ip;
  2260.                 rv = setsockopt(
  2261.                     fd->secret->md.osfd, level, name,
  2262.                     (char*)&mreq, sizeof(mreq));
  2263.                 break;
  2264.             }
  2265.             case PR_SockOpt_McastInterface:
  2266.             {
  2267.                 rv = setsockopt(
  2268.                     fd->secret->md.osfd, level, name,
  2269.                     (char*)&data->value.mcast_if.inet.ip,
  2270.                     sizeof(data->value.mcast_if.inet.ip));
  2271.                 break;
  2272.             }
  2273.             default:
  2274.                 PR_NOT_REACHED("Unknown socket option");
  2275.                 break;
  2276.         }
  2277.         if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
  2278.     }
  2279.     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  2280. }  /* pt_SetSocketOption */
  2281.  
  2282. /*****************************************************************************/
  2283. /****************************** I/O method objects ***************************/
  2284. /*****************************************************************************/
  2285.  
  2286. static PRIOMethods _pr_file_methods = {
  2287.     PR_DESC_FILE,
  2288.     pt_Close,
  2289.     pt_Read,
  2290.     pt_Write,
  2291.     pt_Available,
  2292.     pt_Available64,
  2293.     pt_Fsync,
  2294.     pt_Seek,
  2295.     pt_Seek64,
  2296.     pt_FileInfo,
  2297.     pt_FileInfo64,
  2298.     (PRWritevFN)_PR_InvalidInt,        
  2299.     (PRConnectFN)_PR_InvalidStatus,        
  2300.     (PRAcceptFN)_PR_InvalidDesc,        
  2301.     (PRBindFN)_PR_InvalidStatus,        
  2302.     (PRListenFN)_PR_InvalidStatus,        
  2303.     (PRShutdownFN)_PR_InvalidStatus,    
  2304.     (PRRecvFN)_PR_InvalidInt,        
  2305.     (PRSendFN)_PR_InvalidInt,        
  2306.     (PRRecvfromFN)_PR_InvalidInt,    
  2307.     (PRSendtoFN)_PR_InvalidInt,        
  2308.     (PRPollFN)0,         
  2309.     (PRAcceptreadFN)_PR_InvalidInt,   
  2310.     (PRTransmitfileFN)_PR_InvalidInt, 
  2311.     (PRGetsocknameFN)_PR_InvalidStatus,    
  2312.     (PRGetpeernameFN)_PR_InvalidStatus,    
  2313.     (PRGetsockoptFN)_PR_InvalidStatus,    
  2314.     (PRSetsockoptFN)_PR_InvalidStatus,    
  2315. };
  2316.  
  2317. static PRIOMethods _pr_tcp_methods = {
  2318.     PR_DESC_SOCKET_TCP,
  2319.     pt_Close,
  2320.     pt_Read,
  2321.     pt_Write,
  2322.     pt_Available,
  2323.     pt_Available64,
  2324.     pt_Synch,
  2325.     (PRSeekFN)_PR_InvalidInt,
  2326.     (PRSeek64FN)_PR_InvalidInt64,
  2327.     (PRFileInfoFN)_PR_InvalidStatus,
  2328.     (PRFileInfo64FN)_PR_InvalidStatus,
  2329.     pt_Writev,
  2330.     pt_Connect,
  2331.     pt_Accept,
  2332.     pt_Bind,
  2333.     pt_Listen,
  2334.     pt_Shutdown,
  2335.     pt_Recv,
  2336.     pt_Send,
  2337.     (PRRecvfromFN)_PR_InvalidInt,
  2338.     (PRSendtoFN)_PR_InvalidInt,
  2339.     (PRPollFN)0,
  2340.     pt_AcceptRead,
  2341.     pt_TransmitFile,
  2342.     pt_GetSockName,
  2343.     pt_GetPeerName,
  2344.     pt_GetSockOpt,
  2345.     pt_SetSockOpt,
  2346.     pt_GetSocketOption,
  2347.     pt_SetSocketOption
  2348. };
  2349.  
  2350. static PRIOMethods _pr_udp_methods = {
  2351.     PR_DESC_SOCKET_UDP,
  2352.     pt_Close,
  2353.     pt_Read,
  2354.     pt_Write,
  2355.     pt_Available,
  2356.     pt_Available64,
  2357.     pt_Synch,
  2358.     (PRSeekFN)_PR_InvalidInt,
  2359.     (PRSeek64FN)_PR_InvalidInt64,
  2360.     (PRFileInfoFN)_PR_InvalidStatus,
  2361.     (PRFileInfo64FN)_PR_InvalidStatus,
  2362.     pt_Writev,
  2363.     pt_Connect,
  2364.     (PRAcceptFN)_PR_InvalidDesc,
  2365.     pt_Bind,
  2366.     pt_Listen,
  2367.     pt_Shutdown,
  2368.     pt_Recv,
  2369.     pt_Send,
  2370.     pt_RecvFrom,
  2371.     pt_SendTo,
  2372.     (PRPollFN)0,
  2373.     (PRAcceptreadFN)_PR_InvalidInt,
  2374.     (PRTransmitfileFN)_PR_InvalidInt,
  2375.     pt_GetSockName,
  2376.     pt_GetPeerName,
  2377.     pt_GetSockOpt,
  2378.     pt_SetSockOpt,
  2379.     pt_GetSocketOption,
  2380.     pt_SetSocketOption
  2381. };
  2382.  
  2383. #if defined(_PR_FCNTL_FLAGS)
  2384. #undef _PR_FCNTL_FLAGS
  2385. #endif
  2386.  
  2387. #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
  2388.     || defined(AIX) || defined(LINUX) || defined(FREEBSD)
  2389. #define _PR_FCNTL_FLAGS O_NONBLOCK
  2390. #else
  2391. #error "Can't determine architecture"
  2392. #endif
  2393.  
  2394. static PRFileDesc *pt_SetMethods(PRIntn osfd, PRDescType type)
  2395. {
  2396.     PRInt32 flags, one = 1;
  2397.     PRFileDesc *fd = pt_Getfd();
  2398.     
  2399.     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  2400.     else
  2401.     {
  2402.         fd->secret->md.osfd = osfd;
  2403.         fd->secret->state = _PR_FILEDESC_OPEN;
  2404.         switch (type)
  2405.         {
  2406.             case PR_DESC_FILE:
  2407.                 fd->methods = PR_GetFileMethods();
  2408.                 break;
  2409.             case PR_DESC_SOCKET_TCP:
  2410.                 fd->methods = PR_GetTCPMethods();
  2411.                 flags = fcntl(osfd, F_GETFL, 0);
  2412.                 flags |= _PR_FCNTL_FLAGS;
  2413.                 (void)fcntl(osfd, F_SETFL, flags);
  2414.                 (void)setsockopt(osfd, SOL_SOCKET, SO_KEEPALIVE,
  2415.                     (_PRSockOptVal_t) &one, sizeof(one));
  2416.                 break;
  2417.             case PR_DESC_SOCKET_UDP:
  2418.                 fd->methods = PR_GetUDPMethods();
  2419.                 flags = fcntl(osfd, F_GETFL, 0);
  2420.                 flags |= _PR_FCNTL_FLAGS;
  2421.                 (void)fcntl(osfd, F_SETFL, flags);
  2422.                 break;
  2423.             default:
  2424.                 break;
  2425.         }
  2426.     }
  2427.     return fd;
  2428. }  /* pt_SetMethods */
  2429.  
  2430. PR_IMPLEMENT(PRIOMethods*) PR_GetFileMethods()
  2431. {
  2432.     return &_pr_file_methods;
  2433. }  /* PR_GetFileMethods */
  2434.  
  2435. PR_IMPLEMENT(PRIOMethods*) PR_GetTCPMethods()
  2436. {
  2437.     return &_pr_tcp_methods;
  2438. }  /* PR_GetTCPMethods */
  2439.  
  2440. PR_IMPLEMENT(PRIOMethods*) PR_GetUDPMethods()
  2441. {
  2442.     return &_pr_udp_methods;
  2443. }  /* PR_GetUDPMethods */
  2444.  
  2445. PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(PRInt32 osfd, PRIOMethods *methods)
  2446. {
  2447.     PRFileDesc *fd = pt_Getfd();
  2448.  
  2449.     /*
  2450.      * Assert that the file descriptor is small enough to fit in the
  2451.      * fd_set passed to select
  2452.      */
  2453.     PR_ASSERT(osfd < FD_SETSIZE);
  2454.     if (NULL == fd) goto failed;
  2455.  
  2456.     fd->methods = methods;
  2457.     fd->secret->md.osfd = osfd;
  2458.     /* Make fd non-blocking */
  2459.     if (osfd > 2)
  2460.     {
  2461.         /* Don't mess around with stdin, stdout or stderr */
  2462.         PRIntn flags;
  2463.         flags = fcntl(osfd, F_GETFL, 0);
  2464.         fcntl(osfd, F_SETFL, flags | _PR_FCNTL_FLAGS);
  2465.     }
  2466.     fd->secret->state = _PR_FILEDESC_OPEN;
  2467.     return fd;
  2468.     
  2469. failed:
  2470.     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  2471.     return fd;
  2472. }  /* PR_AllocFileDesc */
  2473.  
  2474. PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
  2475. {
  2476.     PRIntn osfd;
  2477.     PRDescType ftype;
  2478.     PRFileDesc *fd = NULL;
  2479.  
  2480.     if (!_pr_initialized) _PR_ImplicitInitialization();
  2481.  
  2482.     if (pt_TestAbort()) return NULL;
  2483.  
  2484.     if (PF_INET != domain
  2485. #if defined(_PR_INET6)
  2486.     && PF_INET6 != domain
  2487. #endif
  2488.     )
  2489.     {
  2490.         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  2491.         return fd;
  2492.     }
  2493.     if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
  2494.     else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
  2495.     else
  2496.     {
  2497.         (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  2498.         return fd;
  2499.     }
  2500.  
  2501.     osfd = socket(domain, type, proto);
  2502.     if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
  2503.     else
  2504.     {
  2505.         fd = pt_SetMethods(osfd, ftype);
  2506.         if (fd == NULL) close(osfd);
  2507.     }
  2508.     return fd;
  2509. }  /* PR_Socket */
  2510.  
  2511. /*****************************************************************************/
  2512. /****************************** I/O public methods ***************************/
  2513. /*****************************************************************************/
  2514.  
  2515. PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
  2516. {
  2517.     PRFileDesc *fd = NULL;
  2518.     PRIntn syserrno, osfd = -1, osflags = 0;;
  2519.  
  2520.     if (!_pr_initialized) _PR_ImplicitInitialization();
  2521.  
  2522.     if (pt_TestAbort()) return NULL;
  2523.  
  2524.     if (flags & PR_RDONLY) osflags |= O_RDONLY;
  2525.     if (flags & PR_WRONLY) osflags |= O_WRONLY;
  2526.     if (flags & PR_RDWR) osflags |= O_RDWR;
  2527.     if (flags & PR_APPEND) osflags |= O_APPEND;
  2528.     if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
  2529.  
  2530.     /*
  2531.     ** We have to hold the lock across the creation in order to
  2532.     ** enforce the sematics of PR_Rename(). (see the latter for
  2533.     ** more details)
  2534.     */
  2535.     if (flags & PR_CREATE_FILE)
  2536.     {
  2537.         osflags |= O_CREAT;
  2538.         if (NULL !=_pr_rename_lock)
  2539.             PR_Lock(_pr_rename_lock);
  2540.     }
  2541.  
  2542.     osfd = open(name, osflags, mode);
  2543.     syserrno = errno;
  2544.  
  2545.     if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
  2546.         PR_Unlock(_pr_rename_lock);
  2547.  
  2548.     if (osfd == -1)
  2549.         pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
  2550.     else
  2551.     {
  2552.         fd = pt_SetMethods(osfd, PR_DESC_FILE);
  2553.         if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
  2554.     }
  2555.     return fd;
  2556. }  /* PR_Open */
  2557.  
  2558. PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
  2559. {
  2560.     PRIntn rv = -1;
  2561.  
  2562.     if (!_pr_initialized) _PR_ImplicitInitialization();
  2563.  
  2564.     if (pt_TestAbort()) return PR_FAILURE;
  2565.  
  2566.     rv = unlink(name);
  2567.  
  2568.     if (rv == -1) {
  2569.         pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
  2570.         return PR_FAILURE;
  2571.     } else
  2572.         return PR_SUCCESS;
  2573. }  /* PR_Delete */
  2574.  
  2575. PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
  2576. {
  2577.     PRIntn rv;
  2578.  
  2579.     if (pt_TestAbort()) return PR_FAILURE;
  2580.  
  2581.     switch (how)
  2582.     {
  2583.     case PR_ACCESS_READ_OK:
  2584.         rv =  access(name, R_OK);
  2585.         break;
  2586.     case PR_ACCESS_WRITE_OK:
  2587.         rv = access(name, W_OK);
  2588.         break;
  2589.     case PR_ACCESS_EXISTS:
  2590.     default:
  2591.         rv = access(name, F_OK);
  2592.     }
  2593.     if (0 == rv) return PR_SUCCESS;
  2594.     pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
  2595.     return PR_FAILURE;
  2596.     
  2597. }  /* PR_Access */
  2598.  
  2599. PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
  2600. {
  2601.     PRInt32 rv;
  2602.     struct stat sb;
  2603.     PRInt64 s, s2us;
  2604.  
  2605.     if (pt_TestAbort()) return PR_FAILURE;
  2606.  
  2607.     if ((rv = stat(fn, &sb)) == 0 )
  2608.     {
  2609.         if (info)
  2610.         {
  2611.             if (S_IFREG & sb.st_mode)
  2612.                 info->type = PR_FILE_FILE ;
  2613.             else if (S_IFDIR & sb.st_mode)
  2614.                 info->type = PR_FILE_DIRECTORY;
  2615.             else
  2616.                 info->type = PR_FILE_OTHER;
  2617.             info->size = sb.st_size;
  2618. #if defined(IRIX) && defined(HAVE_LONG_LONG)
  2619.             info->modifyTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_mtim.tv_sec);
  2620.             info->creationTime = (PR_USEC_PER_SEC * (PRInt64)sb.st_ctim.tv_sec);
  2621. #else
  2622.             LL_I2L(s, sb.st_mtime);
  2623.             LL_I2L(s2us, PR_USEC_PER_SEC);
  2624.             LL_MUL(s, s, s2us);
  2625.             info->modifyTime = s;
  2626.             LL_I2L(s, sb.st_ctime);
  2627.             LL_MUL(s, s, s2us);
  2628.             info->creationTime = s;
  2629. #endif
  2630.         }
  2631.     }
  2632.     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  2633. }  /* PR_GetFileInfo */
  2634.  
  2635. PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
  2636. {
  2637.     PRIntn rv = -1;
  2638.  
  2639.     if (pt_TestAbort()) return PR_FAILURE;
  2640.  
  2641.     /*
  2642.     ** We have to acquire a lock here to stiffle anybody trying to create
  2643.     ** a new file at the same time. And we have to hold that lock while we
  2644.     ** test to see if the file exists and do the rename. The other place
  2645.     ** where the lock is held is in PR_Open() when possibly creating a 
  2646.     ** new file.
  2647.     */
  2648.  
  2649.     PR_Lock(_pr_rename_lock);
  2650.     rv = access(to, F_OK);
  2651.     if (0 == rv)
  2652.     {
  2653.         PR_SetError(PR_FILE_EXISTS_ERROR, 0);
  2654.         rv = -1;
  2655.     }
  2656.     else
  2657.     {
  2658.         rv = rename(from, to);
  2659.         if (rv == -1)
  2660.             pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
  2661.     }
  2662.     PR_Unlock(_pr_rename_lock);
  2663.     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  2664. }  /* PR_Rename */
  2665.  
  2666. PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
  2667. {
  2668.     if (pt_TestAbort()) return PR_FAILURE;
  2669.  
  2670.     if (NULL != dir->md.d)
  2671.     {
  2672.         closedir(dir->md.d);
  2673.         dir->md.d = NULL;
  2674.     }
  2675.     return PR_SUCCESS;
  2676. }  /* PR_CloseDir */
  2677.  
  2678. PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
  2679. {
  2680.     PRInt32 rv = -1;
  2681.  
  2682.     if (pt_TestAbort()) return PR_FAILURE;
  2683.  
  2684.     /*
  2685.     ** This lock is used to enforce rename semantics as described
  2686.     ** in PR_Rename.
  2687.     */
  2688.     if (NULL !=_pr_rename_lock)
  2689.         PR_Lock(_pr_rename_lock);
  2690.     rv = mkdir(name, mode);
  2691.     if (-1 == rv)
  2692.         pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
  2693.     if (NULL !=_pr_rename_lock)
  2694.         PR_Unlock(_pr_rename_lock);
  2695.  
  2696.     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  2697. }  /* PR_Mkdir */
  2698.  
  2699. PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
  2700. {
  2701.     PRInt32 rv;
  2702.  
  2703.     if (pt_TestAbort()) return PR_FAILURE;
  2704.  
  2705.     rv = rmdir(name);
  2706.     if (0 == rv) {
  2707.     return PR_SUCCESS;
  2708.     } else {
  2709.     pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
  2710.     return PR_FAILURE;
  2711.     }
  2712. }  /* PR_Rmdir */
  2713.  
  2714.  
  2715. PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
  2716. {
  2717.     DIR *osdir;
  2718.     PRDir *dir = NULL;
  2719.  
  2720.     if (pt_TestAbort()) return dir;
  2721.  
  2722.     osdir = opendir(name);
  2723.     if (osdir == NULL)
  2724.         pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
  2725.     else
  2726.     {
  2727.         dir = PR_NEWZAP(PRDir);
  2728.         dir->md.d = osdir;
  2729.     }
  2730.     return dir;
  2731. }  /* PR_OpenDir */
  2732.  
  2733. PR_IMPLEMENT(PRInt32) PR_Poll(
  2734.     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  2735. {
  2736.     PRInt32 ready = 0;
  2737.     /*
  2738.      * For restarting poll() if it is interrupted by a signal.
  2739.      * We use these variables to figure out how much time has
  2740.      * elapsed and how much of the timeout still remains.
  2741.      */
  2742.     PRIntervalTime start, elapsed, remaining;
  2743.  
  2744.     if (0 == npds) PR_Sleep(timeout);
  2745.     else
  2746.     {
  2747.         PRIntn index, msecs;
  2748.         struct pollfd *syspoll = NULL;
  2749.         syspoll = (struct pollfd*)PR_Malloc(npds * sizeof(struct pollfd));
  2750.         for (index = 0; index < npds; ++index)
  2751.         {
  2752.             PRFileDesc *bottom = pds[index].fd;
  2753.  
  2754.             if (bottom == NULL)
  2755.             {
  2756.                 /* make poll() ignore this entry */
  2757.                 syspoll[index].fd = -1;
  2758.                 continue;
  2759.             }
  2760.  
  2761.             while (bottom->lower != NULL) bottom = bottom->lower;
  2762.             syspoll[index].fd = bottom->secret->md.osfd;
  2763.  
  2764.             syspoll[index].events = 0;
  2765.             if (pds[index].in_flags & PR_POLL_READ)
  2766.                 syspoll[index].events |= POLLIN;
  2767.             if (pds[index].in_flags & PR_POLL_WRITE)
  2768.                 syspoll[index].events |= POLLOUT;
  2769.             if (pds[index].in_flags & PR_POLL_EXCEPT)
  2770.                 syspoll[index].events |= POLLPRI;
  2771.             if (_PR_FILEDESC_OPEN == bottom->secret->state)
  2772.                 pds[index].out_flags = 0;  /* init the result */
  2773.             else
  2774.             {
  2775.                 ready += 1;  /* this will cause an abrupt return */
  2776.                 pds[index].out_flags = POLLNVAL;  /* bogii */
  2777.             }
  2778.         }
  2779.         if (0 == ready)
  2780.         {
  2781.             switch (timeout)
  2782.             {
  2783.             case PR_INTERVAL_NO_WAIT: msecs = 0; break;
  2784.             case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
  2785.             default:
  2786.                 msecs = PR_IntervalToMilliseconds(timeout);
  2787.                 start = PR_IntervalNow();
  2788.             }
  2789.  
  2790. retry:
  2791.             ready = poll(syspoll, npds, msecs);
  2792.             if (-1 == ready)
  2793.             {
  2794.                 PRIntn oserror = errno;
  2795.                 PRErrorCode prerror;
  2796.  
  2797.                 switch (oserror) {
  2798.                     case EAGAIN:
  2799.                         prerror = PR_INSUFFICIENT_RESOURCES_ERROR;
  2800.                         break;
  2801.                     case EINTR:
  2802.                         if (timeout == PR_INTERVAL_NO_TIMEOUT)
  2803.                             goto retry;
  2804.                         else if (timeout == PR_INTERVAL_NO_WAIT)
  2805.                             ready = 0;  /* don't retry, just time out */
  2806.                         {
  2807.                             elapsed = (PRIntervalTime) (PR_IntervalNow()
  2808.                                     - start);
  2809.                             if (elapsed > timeout)
  2810.                                 ready = 0;  /* timed out */
  2811.                             else
  2812.                             {
  2813.                                 remaining = timeout - elapsed;
  2814.                                 msecs = PR_IntervalToMilliseconds(remaining);
  2815.                                 goto retry;
  2816.                             }
  2817.                         }
  2818.                         break;
  2819.                 case EINVAL:
  2820.                         prerror = PR_INVALID_ARGUMENT_ERROR;
  2821.                         break;
  2822.                     case EFAULT:
  2823.                         prerror = PR_ACCESS_FAULT_ERROR;
  2824.                         break;
  2825.                     default:
  2826.                         prerror = PR_UNKNOWN_ERROR;
  2827.                         break;
  2828.                 } 
  2829.                 PR_SetError(prerror, oserror);
  2830.             }
  2831.             else if (ready > 0)
  2832.             {
  2833.                 for (index = 0; index < npds; ++index)
  2834.                 {
  2835.                     if (pds[index].fd == NULL) continue;
  2836.                     PR_ASSERT(0 == pds[index].out_flags);
  2837.                     if (0 != syspoll[index].revents)
  2838.                     {
  2839.                         if (syspoll[index].revents & POLLIN)
  2840.                             pds[index].out_flags |= PR_POLL_READ;
  2841.                         if (syspoll[index].revents & POLLOUT)
  2842.                             pds[index].out_flags |= PR_POLL_WRITE;
  2843.                         if (syspoll[index].revents & POLLPRI)
  2844.                             pds[index].out_flags |= PR_POLL_EXCEPT;
  2845.                         if (syspoll[index].revents & POLLERR)
  2846.                             pds[index].out_flags |= PR_POLL_ERR;
  2847.                         if (syspoll[index].revents & POLLNVAL)
  2848.                             pds[index].out_flags |= PR_POLL_NVAL;
  2849.                     }
  2850.                 }
  2851.             }
  2852.         }
  2853.  
  2854.         PR_DELETE(syspoll);
  2855.  
  2856.     }
  2857.     return ready;
  2858.  
  2859. } /* PR_Poll */
  2860.  
  2861. PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
  2862. {
  2863.     struct dirent *dp;
  2864.  
  2865.     if (pt_TestAbort()) return NULL;
  2866.  
  2867.     for (;;)
  2868.     {
  2869.         dp = readdir(dir->md.d);
  2870.         if (NULL == dp) return NULL;
  2871.         if ((flags & PR_SKIP_DOT)
  2872.             && ('.' == dp->d_name[0])
  2873.             && (0 == dp->d_name[1])) continue;
  2874.         if ((flags & PR_SKIP_DOT_DOT)
  2875.             && ('.' == dp->d_name[0])
  2876.             && ('.' == dp->d_name[1])
  2877.             && (0 == dp->d_name[2])) continue;
  2878.         if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
  2879.             continue;
  2880.         break;
  2881.     }
  2882.     dir->d.name = dp->d_name;
  2883.     return &dir->d;
  2884. }  /* PR_ReadDir */
  2885.  
  2886. PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket()
  2887. {
  2888.     PRFileDesc *fd = NULL;
  2889.     PRIntn osfd = -1, syserrno;
  2890.     PRIntn domain = PF_INET;
  2891.  
  2892.     if (!_pr_initialized) _PR_ImplicitInitialization();
  2893.  
  2894.     if (pt_TestAbort()) return NULL;
  2895.  
  2896. #if defined(_PR_INET6)
  2897.     if (_pr_ipv6_enabled)
  2898.         domain = PF_INET6;
  2899. #endif
  2900.     osfd = socket(domain, SOCK_DGRAM, 0);
  2901.     syserrno = errno;
  2902.  
  2903.     if (osfd == -1)
  2904.         pt_MapError(_PR_MD_MAP_SOCKET_ERROR, syserrno);
  2905.     else
  2906.     {
  2907.         fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP);
  2908.         if (fd == NULL) close(osfd);
  2909.     }
  2910.     return fd;
  2911. }  /* PR_NewUDPSocket */
  2912.  
  2913. PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket()
  2914. {
  2915.     PRIntn osfd = -1;
  2916.     PRFileDesc *fd = NULL;
  2917.     PRIntn domain = PF_INET;
  2918.  
  2919.     if (!_pr_initialized) _PR_ImplicitInitialization();
  2920.  
  2921.     if (pt_TestAbort()) return NULL;
  2922.  
  2923. #if defined(_PR_INET6)
  2924.     if (_pr_ipv6_enabled)
  2925.         domain = PF_INET6;
  2926. #endif
  2927.     osfd = socket(domain, SOCK_STREAM, 0);
  2928.  
  2929.     if (osfd == -1)
  2930.         pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
  2931.     else
  2932.     {
  2933.         fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP);
  2934.         if (fd == NULL) close(osfd);
  2935.     }
  2936.     return fd;
  2937. }  /* PR_NewTCPSocket */
  2938.  
  2939. PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
  2940. {
  2941.     PRInt32 osfd[2];
  2942.  
  2943.     if (pt_TestAbort()) return PR_FAILURE;
  2944.  
  2945.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
  2946.     pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
  2947.     return PR_FAILURE;
  2948.     }
  2949.  
  2950.     fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP);
  2951.     if (fds[0] == NULL) {
  2952.         close(osfd[0]);
  2953.         close(osfd[1]);
  2954.         return PR_FAILURE;
  2955.     }
  2956.     fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP);
  2957.     if (fds[1] == NULL) {
  2958.         PR_Close(fds[0]);
  2959.         close(osfd[1]);
  2960.         return PR_FAILURE;
  2961.     }
  2962.     return PR_SUCCESS;
  2963. }  /* PR_NewTCPSocketPair */
  2964.  
  2965. PR_IMPLEMENT(PRStatus) PR_CreatePipe(
  2966.     PRFileDesc **readPipe,
  2967.     PRFileDesc **writePipe
  2968. )
  2969. {
  2970.     int pipefd[2];
  2971.     int flags;
  2972.  
  2973.     if (pt_TestAbort()) return PR_FAILURE;
  2974.  
  2975.     if (pipe(pipefd) == -1)
  2976.     {
  2977.     /* XXX map pipe error */
  2978.         PR_SetError(PR_UNKNOWN_ERROR, errno);
  2979.         return PR_FAILURE;
  2980.     }
  2981.     *readPipe = pt_SetMethods(pipefd[0], PR_DESC_FILE);
  2982.     if (NULL == *readPipe)
  2983.     {
  2984.         close(pipefd[0]);
  2985.         close(pipefd[1]);
  2986.         return PR_FAILURE;
  2987.     }
  2988.     flags = fcntl(pipefd[0], F_GETFL, 0);
  2989.     flags |= _PR_FCNTL_FLAGS;
  2990.     (void)fcntl(pipefd[0], F_SETFL, flags);
  2991.     *writePipe = pt_SetMethods(pipefd[1], PR_DESC_FILE);
  2992.     if (NULL == *writePipe)
  2993.     {
  2994.         PR_Close(*readPipe);
  2995.         close(pipefd[1]);
  2996.         return PR_FAILURE;
  2997.     }
  2998.     flags = fcntl(pipefd[1], F_GETFL, 0);
  2999.     flags |= _PR_FCNTL_FLAGS;
  3000.     (void)fcntl(pipefd[1], F_SETFL, flags);
  3001.     return PR_SUCCESS;
  3002. }
  3003.  
  3004. /*****************************************************************************/
  3005. /***************************** I/O friends methods ***************************/
  3006. /*****************************************************************************/
  3007.  
  3008. PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
  3009. {
  3010.     PRFileDesc *fd = pt_SetMethods(osfd, PR_DESC_FILE);
  3011.     if (NULL == fd) close(osfd);
  3012.     return fd;
  3013. }  /* PR_ImportFile */
  3014.  
  3015. PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
  3016. {
  3017.     PRFileDesc *fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP);
  3018.     if (NULL == fd) close(osfd);
  3019.     return fd;
  3020. }  /* PR_ImportTCPSocket */
  3021.  
  3022. PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
  3023. {
  3024.     PRFileDesc *fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP);
  3025.     if (NULL != fd) close(osfd);
  3026.     return fd;
  3027. }  /* PR_ImportUDPSocket */
  3028.  
  3029. PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *fd)
  3030. {
  3031.     if (fd)
  3032.     {
  3033.         /*
  3034.          * The fd may be layered.  Chase the links to the
  3035.          * bottom layer to get the osfd.
  3036.          */
  3037.         PRFileDesc *bottom = fd;
  3038.         while (bottom->lower != NULL) {
  3039.             bottom = bottom->lower;
  3040.         }
  3041.         return bottom->secret->md.osfd;
  3042.     }
  3043.     else
  3044.     {
  3045.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  3046.         return -1;
  3047.     }
  3048. }  /* PR_FileDesc2NativeHandle */
  3049.  
  3050. PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
  3051.     PRInt32 handle)
  3052. {
  3053.     if (fd) fd->secret->md.osfd = handle;
  3054. }  /*  PR_ChangeFileDescNativeHandle*/
  3055.  
  3056. PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
  3057. {
  3058.     PRStatus status = PR_SUCCESS;
  3059.  
  3060.     if (pt_TestAbort()) return PR_FAILURE;
  3061.  
  3062.     PR_Lock(_pr_flock_lock);
  3063.     if (0 == fd->secret->lockCount)
  3064.     {
  3065.         status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
  3066.         if (PR_SUCCESS == status) fd->secret->lockCount = 1;
  3067.     }
  3068.     else fd->secret->lockCount += 1;
  3069.     PR_Unlock(_pr_flock_lock);
  3070.  
  3071.     return status;
  3072. }  /* PR_LockFile */
  3073.  
  3074. PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
  3075. {
  3076.     PRStatus status = PR_SUCCESS;
  3077.  
  3078.     if (pt_TestAbort()) return PR_FAILURE;
  3079.  
  3080.     PR_Lock(_pr_flock_lock);
  3081.     if (0 == fd->secret->lockCount)
  3082.     {
  3083.         status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
  3084.         if (PR_SUCCESS == status) fd->secret->lockCount = 1;
  3085.     }
  3086.     else fd->secret->lockCount += 1;
  3087.     PR_Unlock(_pr_flock_lock);
  3088.  
  3089.     return status;
  3090. }  /* PR_TLockFile */
  3091.  
  3092. PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
  3093. {
  3094.     PRStatus status = PR_SUCCESS;
  3095.  
  3096.     if (pt_TestAbort()) return PR_FAILURE;
  3097.  
  3098.     PR_Lock(_pr_flock_lock);
  3099.     if (fd->secret->lockCount == 1)
  3100.     {
  3101.         status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
  3102.         if (PR_SUCCESS == status) fd->secret->lockCount = 0;
  3103.     }
  3104.     else fd->secret->lockCount -= 1;
  3105.     PR_Unlock(_pr_flock_lock);
  3106.  
  3107.     return status;
  3108. }
  3109.  
  3110. /*
  3111.  * The next two entry points should not be in the API, but they are
  3112.  * defined here for historical (or hysterical) reasons.
  3113.  */
  3114.  
  3115. PRInt32 PR_GetSysfdTableMax(void)
  3116. {
  3117. #if defined(XP_UNIX) && !defined(AIX)
  3118.     struct rlimit rlim;
  3119.  
  3120.     if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) 
  3121.        return -1;
  3122.  
  3123.     return rlim.rlim_max;
  3124. #elif defined(AIX)
  3125.     return sysconf(_SC_OPEN_MAX);
  3126. #endif
  3127. }
  3128.  
  3129. PRInt32 PR_SetSysfdTableSize(PRIntn table_size)
  3130. {
  3131. #if defined(XP_UNIX) && !defined(AIX)
  3132.     struct rlimit rlim;
  3133.     PRInt32 tableMax = PR_GetSysfdTableMax();
  3134.  
  3135.     if (tableMax < 0) return -1;
  3136.     rlim.rlim_max = tableMax;
  3137.  
  3138.     /* Grow as much as we can; even if too big */
  3139.     if ( rlim.rlim_max < table_size )
  3140.         rlim.rlim_cur = rlim.rlim_max;
  3141.     else
  3142.         rlim.rlim_cur = table_size;
  3143.  
  3144.     if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) 
  3145.         return -1;
  3146.  
  3147.     return rlim.rlim_cur;
  3148. #elif defined(AIX)
  3149.     return -1;
  3150. #endif
  3151. }
  3152.  
  3153. /*
  3154.  * PR_Stat is supported for backward compatibility; some existing Java
  3155.  * code uses it.  New code should use PR_GetFileInfo.
  3156.  */
  3157.  
  3158. #ifndef NO_NSPR_10_SUPPORT
  3159. PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
  3160. {
  3161.     static PRBool unwarned = PR_TRUE;
  3162.     if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
  3163.  
  3164.     if (pt_TestAbort()) return PR_FAILURE;
  3165.  
  3166.     if (-1 == stat(name, buf)) {
  3167.         pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
  3168.         return PR_FAILURE;
  3169.     } else {
  3170.         return PR_SUCCESS;
  3171.     }
  3172. }
  3173. #endif /* ! NO_NSPR_10_SUPPORT */
  3174.  
  3175.  
  3176. PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
  3177. {
  3178.     static PRBool unwarned = PR_TRUE;
  3179.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
  3180.     memset(set, 0, sizeof(PR_fd_set));
  3181. }
  3182.  
  3183. PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
  3184. {
  3185.     static PRBool unwarned = PR_TRUE;
  3186.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
  3187.     PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
  3188.  
  3189.     set->harray[set->hsize++] = fh;
  3190. }
  3191.  
  3192. PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
  3193. {
  3194.     PRUint32 index, index2;
  3195.     static PRBool unwarned = PR_TRUE;
  3196.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
  3197.  
  3198.     for (index = 0; index<set->hsize; index++)
  3199.        if (set->harray[index] == fh) {
  3200.            for (index2=index; index2 < (set->hsize-1); index2++) {
  3201.                set->harray[index2] = set->harray[index2+1];
  3202.            }
  3203.            set->hsize--;
  3204.            break;
  3205.        }
  3206. }
  3207.  
  3208. PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
  3209. {
  3210.     PRUint32 index;
  3211.     static PRBool unwarned = PR_TRUE;
  3212.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
  3213.     for (index = 0; index<set->hsize; index++)
  3214.        if (set->harray[index] == fh) {
  3215.            return 1;
  3216.        }
  3217.     return 0;
  3218. }
  3219.  
  3220. PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
  3221. {
  3222.     static PRBool unwarned = PR_TRUE;
  3223.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
  3224.     PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
  3225.  
  3226.     set->narray[set->nsize++] = fd;
  3227. }
  3228.  
  3229. PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
  3230. {
  3231.     PRUint32 index, index2;
  3232.     static PRBool unwarned = PR_TRUE;
  3233.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
  3234.  
  3235.     for (index = 0; index<set->nsize; index++)
  3236.        if (set->narray[index] == fd) {
  3237.            for (index2=index; index2 < (set->nsize-1); index2++) {
  3238.                set->narray[index2] = set->narray[index2+1];
  3239.            }
  3240.            set->nsize--;
  3241.            break;
  3242.        }
  3243. }
  3244.  
  3245. PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
  3246. {
  3247.     PRUint32 index;
  3248.     static PRBool unwarned = PR_TRUE;
  3249.     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
  3250.     for (index = 0; index<set->nsize; index++)
  3251.        if (set->narray[index] == fd) {
  3252.            return 1;
  3253.        }
  3254.     return 0;
  3255. }
  3256.  
  3257. #include <sys/types.h>
  3258. #include <sys/time.h>
  3259. #if !defined(SUNOS4) && !defined(HPUX) && !defined(LINUX)
  3260. #include <sys/select.h>
  3261. #endif
  3262.  
  3263. static PRInt32
  3264. _PR_getset(PR_fd_set *pr_set, fd_set *set)
  3265. {
  3266.     PRUint32 index;
  3267.     PRInt32 max = 0;
  3268.  
  3269.     if (!pr_set)
  3270.         return 0;
  3271.    
  3272.     FD_ZERO(set);
  3273.  
  3274.     /* First set the pr file handle osfds */
  3275.     for (index=0; index<pr_set->hsize; index++) {
  3276.         FD_SET(pr_set->harray[index]->secret->md.osfd, set);
  3277.         if (pr_set->harray[index]->secret->md.osfd > max)
  3278.             max = pr_set->harray[index]->secret->md.osfd;
  3279.     }
  3280.     /* Second set the native osfds */
  3281.     for (index=0; index<pr_set->nsize; index++) {
  3282.         FD_SET(pr_set->narray[index], set);
  3283.         if (pr_set->narray[index] > max)
  3284.             max = pr_set->narray[index];
  3285.     }
  3286.     return max;
  3287. }
  3288.  
  3289. static void
  3290. _PR_setset(PR_fd_set *pr_set, fd_set *set)
  3291. {
  3292.     PRUint32 index, last_used;
  3293.  
  3294.     if (!pr_set)
  3295.         return;
  3296.  
  3297.     for (last_used=0, index=0; index<pr_set->hsize; index++) {
  3298.         if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
  3299.             pr_set->harray[last_used++] = pr_set->harray[index];
  3300.         }
  3301.     }
  3302.     pr_set->hsize = last_used;
  3303.  
  3304.     for (last_used=0, index=0; index<pr_set->nsize; index++) {
  3305.         if ( FD_ISSET(pr_set->narray[index], set) ) {
  3306.             pr_set->narray[last_used++] = pr_set->narray[index];
  3307.         }
  3308.     }
  3309.     pr_set->nsize = last_used;
  3310. }
  3311.  
  3312. PR_IMPLEMENT(PRInt32) PR_Select(
  3313.     PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
  3314.     PR_fd_set *pr_ex, PRIntervalTime timeout)
  3315. {
  3316.     fd_set rd, wr, ex;
  3317.     struct timeval tv, *tvp;
  3318.     PRInt32 max, max_fd;
  3319.     PRInt32 rv;
  3320.     /*
  3321.      * For restarting select() if it is interrupted by a Unix signal.
  3322.      * We use these variables to figure out how much time has elapsed
  3323.      * and how much of the timeout still remains.
  3324.      */
  3325.     PRIntervalTime start, elapsed, remaining;
  3326.  
  3327.     static PRBool unwarned = PR_TRUE;
  3328.     if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
  3329.  
  3330.     FD_ZERO(&rd);
  3331.     FD_ZERO(&wr);
  3332.     FD_ZERO(&ex);
  3333.  
  3334.     max_fd = _PR_getset(pr_rd, &rd);
  3335.     max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
  3336.     max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
  3337.  
  3338.     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  3339.         tvp = NULL;
  3340.     } else {
  3341.         tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
  3342.         tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
  3343.                 timeout - PR_SecondsToInterval(tv.tv_sec));
  3344.         tvp = &tv;
  3345.         start = PR_IntervalNow();
  3346.     }
  3347.  
  3348. retry:
  3349.     rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
  3350.         (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
  3351.  
  3352.     if (rv == -1 && errno == EINTR) {
  3353.         if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  3354.             goto retry;
  3355.         } else {
  3356.             elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
  3357.             if (elapsed > timeout) {
  3358.                 rv = 0;  /* timed out */
  3359.             } else {
  3360.                 remaining = timeout - elapsed;
  3361.                 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
  3362.                 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
  3363.                         remaining - PR_SecondsToInterval(tv.tv_sec));
  3364.                 goto retry;
  3365.             }
  3366.         }
  3367.     }
  3368.  
  3369.     if (rv > 0) {
  3370.         _PR_setset(pr_rd, &rd);
  3371.         _PR_setset(pr_wr, &wr);
  3372.         _PR_setset(pr_ex, &ex);
  3373.     } else if (rv == -1) {
  3374.         pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
  3375.     }
  3376.     return rv;
  3377. }
  3378.  
  3379. #endif /* defined(_PR_PTHREADS) */
  3380.  
  3381. /* ptio.c */
  3382.