Back to index

lightning-sunbird  0.9+nobinonly
unix.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 
00040 #include <string.h>
00041 #include <signal.h>
00042 #include <unistd.h>
00043 #include <fcntl.h>
00044 #include <sys/types.h>
00045 #include <sys/socket.h>
00046 #include <sys/time.h>
00047 #include <sys/ioctl.h>
00048 #include <sys/mman.h>
00049 #include <unistd.h>
00050 #include <sys/utsname.h>
00051 
00052 #ifdef _PR_POLL_AVAILABLE
00053 #include <poll.h>
00054 #endif
00055 
00056 /* To get FIONREAD */
00057 #if defined(NCR) || defined(UNIXWARE) || defined(NEC) || defined(SNI) \
00058         || defined(SONY)
00059 #include <sys/filio.h>
00060 #endif
00061 
00062 #if defined(NTO)
00063 #include <sys/statvfs.h>
00064 #endif
00065 
00066 /*
00067  * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
00068  * PRInt32* pointer to a _PRSockLen_t* pointer.
00069  */
00070 #if defined(HAVE_SOCKLEN_T) \
00071     || (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2)
00072 #define _PRSockLen_t socklen_t
00073 #elif defined(IRIX) || defined(HPUX) || defined(OSF1) || defined(SOLARIS) \
00074     || defined(AIX4_1) || defined(LINUX) || defined(SONY) \
00075     || defined(BSDI) || defined(SCO) || defined(NEC) || defined(SNI) \
00076     || defined(SUNOS4) || defined(NCR) || defined(DARWIN) \
00077     || defined(NEXTSTEP) || defined(QNX)
00078 #define _PRSockLen_t int
00079 #elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \
00080     || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \
00081     || defined(DGUX) || defined(VMS) || defined(NTO) || defined(RISCOS)
00082 #define _PRSockLen_t size_t
00083 #else
00084 #error "Cannot determine architecture"
00085 #endif
00086 
00087 /*
00088 ** Global lock variable used to bracket calls into rusty libraries that
00089 ** aren't thread safe (like libc, libX, etc).
00090 */
00091 static PRLock *_pr_rename_lock = NULL;
00092 static PRMonitor *_pr_Xfe_mon = NULL;
00093 
00094 static PRInt64 minus_one;
00095 
00096 sigset_t timer_set;
00097 
00098 #if !defined(_PR_PTHREADS)
00099 
00100 static sigset_t empty_set;
00101 
00102 #ifdef SOLARIS
00103 #include <sys/file.h>
00104 #include <sys/filio.h>
00105 #endif
00106 
00107 #ifndef PIPE_BUF
00108 #define PIPE_BUF 512
00109 #endif
00110 
00111 /*
00112  * _nspr_noclock - if set clock interrupts are disabled
00113  */
00114 int _nspr_noclock = 1;
00115 
00116 #ifdef IRIX
00117 extern PRInt32 _nspr_terminate_on_error;
00118 #endif
00119 
00120 /*
00121  * There is an assertion in this code that NSPR's definition of PRIOVec
00122  * is bit compatible with UNIX' definition of a struct iovec. This is
00123  * applicable to the 'writev()' operations where the types are casually
00124  * cast to avoid warnings.
00125  */
00126 
00127 int _pr_md_pipefd[2] = { -1, -1 };
00128 static char _pr_md_pipebuf[PIPE_BUF];
00129 static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag,
00130                                                  PRIntervalTime timeout);
00131 
00132 _PRInterruptTable _pr_interruptTable[] = {
00133     { 
00134         "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt,     },
00135     { 
00136         0     }
00137 };
00138 
00139 void _MD_unix_init_running_cpu(_PRCPU *cpu)
00140 {
00141     PR_INIT_CLIST(&(cpu->md.md_unix.ioQ));
00142     cpu->md.md_unix.ioq_max_osfd = -1;
00143     cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT;
00144 }
00145 
00146 PRStatus _MD_open_dir(_MDDir *d, const char *name)
00147 {
00148 int err;
00149 
00150     d->d = opendir(name);
00151     if (!d->d) {
00152         err = _MD_ERRNO();
00153         _PR_MD_MAP_OPENDIR_ERROR(err);
00154         return PR_FAILURE;
00155     }
00156     return PR_SUCCESS;
00157 }
00158 
00159 PRInt32 _MD_close_dir(_MDDir *d)
00160 {
00161 int rv = 0, err;
00162 
00163     if (d->d) {
00164         rv = closedir(d->d);
00165         if (rv == -1) {
00166                 err = _MD_ERRNO();
00167                 _PR_MD_MAP_CLOSEDIR_ERROR(err);
00168         }
00169     }
00170     return rv;
00171 }
00172 
00173 char * _MD_read_dir(_MDDir *d, PRIntn flags)
00174 {
00175 struct dirent *de;
00176 int err;
00177 
00178     for (;;) {
00179         /*
00180           * XXX: readdir() is not MT-safe. There is an MT-safe version
00181           * readdir_r() on some systems.
00182           */
00183         _MD_ERRNO() = 0;
00184         de = readdir(d->d);
00185         if (!de) {
00186             err = _MD_ERRNO();
00187             _PR_MD_MAP_READDIR_ERROR(err);
00188             return 0;
00189         }        
00190         if ((flags & PR_SKIP_DOT) &&
00191             (de->d_name[0] == '.') && (de->d_name[1] == 0))
00192             continue;
00193         if ((flags & PR_SKIP_DOT_DOT) &&
00194             (de->d_name[0] == '.') && (de->d_name[1] == '.') &&
00195             (de->d_name[2] == 0))
00196             continue;
00197         if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.'))
00198             continue;
00199         break;
00200     }
00201     return de->d_name;
00202 }
00203 
00204 PRInt32 _MD_delete(const char *name)
00205 {
00206 PRInt32 rv, err;
00207 #ifdef UNIXWARE
00208     sigset_t set, oset;
00209 #endif
00210 
00211 #ifdef UNIXWARE
00212     sigfillset(&set);
00213     sigprocmask(SIG_SETMASK, &set, &oset);
00214 #endif
00215     rv = unlink(name);
00216 #ifdef UNIXWARE
00217     sigprocmask(SIG_SETMASK, &oset, NULL);
00218 #endif
00219     if (rv == -1) {
00220             err = _MD_ERRNO();
00221             _PR_MD_MAP_UNLINK_ERROR(err);
00222     }
00223     return(rv);
00224 }
00225 
00226 PRInt32 _MD_rename(const char *from, const char *to)
00227 {
00228     PRInt32 rv = -1, err;
00229 
00230     /*
00231     ** This is trying to enforce the semantics of WINDOZE' rename
00232     ** operation. That means one is not allowed to rename over top
00233     ** of an existing file. Holding a lock across these two function
00234     ** and the open function is known to be a bad idea, but ....
00235     */
00236     if (NULL != _pr_rename_lock)
00237         PR_Lock(_pr_rename_lock);
00238     if (0 == access(to, F_OK))
00239         PR_SetError(PR_FILE_EXISTS_ERROR, 0);
00240     else
00241     {
00242         rv = rename(from, to);
00243         if (rv < 0) {
00244             err = _MD_ERRNO();
00245             _PR_MD_MAP_RENAME_ERROR(err);
00246         }
00247     }
00248     if (NULL != _pr_rename_lock)
00249         PR_Unlock(_pr_rename_lock);
00250     return rv;
00251 }
00252 
00253 PRInt32 _MD_access(const char *name, PRAccessHow how)
00254 {
00255 PRInt32 rv, err;
00256 int amode;
00257 
00258     switch (how) {
00259         case PR_ACCESS_WRITE_OK:
00260             amode = W_OK;
00261             break;
00262         case PR_ACCESS_READ_OK:
00263             amode = R_OK;
00264             break;
00265         case PR_ACCESS_EXISTS:
00266             amode = F_OK;
00267             break;
00268         default:
00269             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00270             rv = -1;
00271             goto done;
00272     }
00273     rv = access(name, amode);
00274 
00275     if (rv < 0) {
00276         err = _MD_ERRNO();
00277         _PR_MD_MAP_ACCESS_ERROR(err);
00278     }
00279 
00280 done:
00281     return(rv);
00282 }
00283 
00284 PRInt32 _MD_mkdir(const char *name, PRIntn mode)
00285 {
00286 int rv, err;
00287 
00288     /*
00289     ** This lock is used to enforce rename semantics as described
00290     ** in PR_Rename. Look there for more fun details.
00291     */
00292     if (NULL !=_pr_rename_lock)
00293         PR_Lock(_pr_rename_lock);
00294     rv = mkdir(name, mode);
00295     if (rv < 0) {
00296         err = _MD_ERRNO();
00297         _PR_MD_MAP_MKDIR_ERROR(err);
00298     }
00299     if (NULL !=_pr_rename_lock)
00300         PR_Unlock(_pr_rename_lock);
00301     return rv;
00302 }
00303 
00304 PRInt32 _MD_rmdir(const char *name)
00305 {
00306 int rv, err;
00307 
00308     rv = rmdir(name);
00309     if (rv == -1) {
00310             err = _MD_ERRNO();
00311             _PR_MD_MAP_RMDIR_ERROR(err);
00312     }
00313     return rv;
00314 }
00315 
00316 PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount)
00317 {
00318 PRThread *me = _PR_MD_CURRENT_THREAD();
00319 PRInt32 rv, err;
00320 #ifndef _PR_USE_POLL
00321 fd_set rd;
00322 #else
00323 struct pollfd pfd;
00324 #endif /* _PR_USE_POLL */
00325 PRInt32 osfd = fd->secret->md.osfd;
00326 
00327 #ifndef _PR_USE_POLL
00328     FD_ZERO(&rd);
00329     FD_SET(osfd, &rd);
00330 #else
00331     pfd.fd = osfd;
00332     pfd.events = POLLIN;
00333 #endif /* _PR_USE_POLL */
00334     while ((rv = read(osfd,buf,amount)) == -1) {
00335         err = _MD_ERRNO();
00336         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00337             if (fd->secret->nonblocking) {
00338                 break;
00339             }
00340             if (!_PR_IS_NATIVE_THREAD(me)) {
00341                 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ,
00342                                                                       PR_INTERVAL_NO_TIMEOUT)) < 0)
00343                                    goto done;                                                     
00344             } else {
00345 #ifndef _PR_USE_POLL
00346                 while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL))
00347                         == -1 && (err = _MD_ERRNO()) == EINTR) {
00348                     /* retry _MD_SELECT() if it is interrupted */
00349                 }
00350 #else /* _PR_USE_POLL */
00351                 while ((rv = _MD_POLL(&pfd, 1, -1))
00352                         == -1 && (err = _MD_ERRNO()) == EINTR) {
00353                     /* retry _MD_POLL() if it is interrupted */
00354                 }
00355 #endif /* _PR_USE_POLL */
00356                 if (rv == -1) {
00357                     break;
00358                 }
00359             }
00360             if (_PR_PENDING_INTERRUPT(me))
00361                 break;
00362         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00363             continue;
00364         } else {
00365             break;
00366         }
00367     }
00368     if (rv < 0) {
00369         if (_PR_PENDING_INTERRUPT(me)) {
00370             me->flags &= ~_PR_INTERRUPT;
00371             PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00372         } else {
00373             _PR_MD_MAP_READ_ERROR(err);
00374         }
00375     }
00376 done:
00377     return(rv);
00378 }
00379 
00380 PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
00381 {
00382 PRThread *me = _PR_MD_CURRENT_THREAD();
00383 PRInt32 rv, err;
00384 #ifndef _PR_USE_POLL
00385 fd_set wd;
00386 #else
00387 struct pollfd pfd;
00388 #endif /* _PR_USE_POLL */
00389 PRInt32 osfd = fd->secret->md.osfd;
00390 
00391 #ifndef _PR_USE_POLL
00392     FD_ZERO(&wd);
00393     FD_SET(osfd, &wd);
00394 #else
00395     pfd.fd = osfd;
00396     pfd.events = POLLOUT;
00397 #endif /* _PR_USE_POLL */
00398     while ((rv = write(osfd,buf,amount)) == -1) {
00399         err = _MD_ERRNO();
00400         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00401             if (fd->secret->nonblocking) {
00402                 break;
00403             }
00404             if (!_PR_IS_NATIVE_THREAD(me)) {
00405                 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE,
00406                                                                       PR_INTERVAL_NO_TIMEOUT)) < 0)
00407                     goto done;
00408             } else {
00409 #ifndef _PR_USE_POLL
00410                 while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL))
00411                         == -1 && (err = _MD_ERRNO()) == EINTR) {
00412                     /* retry _MD_SELECT() if it is interrupted */
00413                 }
00414 #else /* _PR_USE_POLL */
00415                 while ((rv = _MD_POLL(&pfd, 1, -1))
00416                         == -1 && (err = _MD_ERRNO()) == EINTR) {
00417                     /* retry _MD_POLL() if it is interrupted */
00418                 }
00419 #endif /* _PR_USE_POLL */
00420                 if (rv == -1) {
00421                     break;
00422                 }
00423             }
00424             if (_PR_PENDING_INTERRUPT(me))
00425                 break;
00426         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00427             continue;
00428         } else {
00429             break;
00430         }
00431     }
00432     if (rv < 0) {
00433         if (_PR_PENDING_INTERRUPT(me)) {
00434             me->flags &= ~_PR_INTERRUPT;
00435             PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00436         } else {
00437             _PR_MD_MAP_WRITE_ERROR(err);
00438         }
00439     }
00440 done:
00441     return(rv);
00442 }
00443 
00444 PRInt32 _MD_fsync(PRFileDesc *fd)
00445 {
00446 PRInt32 rv, err;
00447 
00448     rv = fsync(fd->secret->md.osfd);
00449     if (rv == -1) {
00450         err = _MD_ERRNO();
00451         _PR_MD_MAP_FSYNC_ERROR(err);
00452     }
00453     return(rv);
00454 }
00455 
00456 PRInt32 _MD_close(PRInt32 osfd)
00457 {
00458 PRInt32 rv, err;
00459 
00460     rv = close(osfd);
00461     if (rv == -1) {
00462         err = _MD_ERRNO();
00463         _PR_MD_MAP_CLOSE_ERROR(err);
00464     }
00465     return(rv);
00466 }
00467 
00468 PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
00469 {
00470     PRInt32 osfd, err;
00471 
00472     osfd = socket(domain, type, proto);
00473 
00474     if (osfd == -1) {
00475         err = _MD_ERRNO();
00476         _PR_MD_MAP_SOCKET_ERROR(err);
00477         return(osfd);
00478     }
00479 
00480     return(osfd);
00481 }
00482 
00483 PRInt32 _MD_socketavailable(PRFileDesc *fd)
00484 {
00485     PRInt32 result;
00486 
00487     if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) {
00488         _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO());
00489         return -1;
00490     }
00491     return result;
00492 }
00493 
00494 PRInt64 _MD_socketavailable64(PRFileDesc *fd)
00495 {
00496     PRInt64 result;
00497     LL_I2L(result, _MD_socketavailable(fd));
00498     return result;
00499 }  /* _MD_socketavailable64 */
00500 
00501 #define READ_FD        1
00502 #define WRITE_FD    2
00503 
00504 /*
00505  * socket_io_wait --
00506  *
00507  * wait for socket i/o, periodically checking for interrupt
00508  *
00509  * The first implementation uses select(), for platforms without
00510  * poll().  The second (preferred) implementation uses poll().
00511  */
00512 
00513 #ifndef _PR_USE_POLL
00514 
00515 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
00516     PRIntervalTime timeout)
00517 {
00518     PRInt32 rv = -1;
00519     struct timeval tv;
00520     PRThread *me = _PR_MD_CURRENT_THREAD();
00521     PRIntervalTime epoch, now, elapsed, remaining;
00522     PRBool wait_for_remaining;
00523     PRInt32 syserror;
00524     fd_set rd_wr;
00525 
00526     switch (timeout) {
00527         case PR_INTERVAL_NO_WAIT:
00528             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00529             break;
00530         case PR_INTERVAL_NO_TIMEOUT:
00531             /*
00532              * This is a special case of the 'default' case below.
00533              * Please see the comments there.
00534              */
00535             tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
00536             tv.tv_usec = 0;
00537             FD_ZERO(&rd_wr);
00538             do {
00539                 FD_SET(osfd, &rd_wr);
00540                 if (fd_type == READ_FD)
00541                     rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
00542                 else
00543                     rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
00544                 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
00545                     _PR_MD_MAP_SELECT_ERROR(syserror);
00546                     break;
00547                 }
00548                 if (_PR_PENDING_INTERRUPT(me)) {
00549                     me->flags &= ~_PR_INTERRUPT;
00550                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00551                     rv = -1;
00552                     break;
00553                 }
00554             } while (rv == 0 || (rv == -1 && syserror == EINTR));
00555             break;
00556         default:
00557             now = epoch = PR_IntervalNow();
00558             remaining = timeout;
00559             FD_ZERO(&rd_wr);
00560             do {
00561                 /*
00562                  * We block in _MD_SELECT for at most
00563                  * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
00564                  * so that there is an upper limit on the delay
00565                  * before the interrupt bit is checked.
00566                  */
00567                 wait_for_remaining = PR_TRUE;
00568                 tv.tv_sec = PR_IntervalToSeconds(remaining);
00569                 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
00570                     wait_for_remaining = PR_FALSE;
00571                     tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
00572                     tv.tv_usec = 0;
00573                 } else {
00574                     tv.tv_usec = PR_IntervalToMicroseconds(
00575                         remaining -
00576                         PR_SecondsToInterval(tv.tv_sec));
00577                 }
00578                 FD_SET(osfd, &rd_wr);
00579                 if (fd_type == READ_FD)
00580                     rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
00581                 else
00582                     rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
00583                 /*
00584                  * we don't consider EINTR a real error
00585                  */
00586                 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
00587                     _PR_MD_MAP_SELECT_ERROR(syserror);
00588                     break;
00589                 }
00590                 if (_PR_PENDING_INTERRUPT(me)) {
00591                     me->flags &= ~_PR_INTERRUPT;
00592                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00593                     rv = -1;
00594                     break;
00595                 }
00596                 /*
00597                  * We loop again if _MD_SELECT timed out or got interrupted
00598                  * by a signal, and the timeout deadline has not passed yet.
00599                  */
00600                 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
00601                     /*
00602                      * If _MD_SELECT timed out, we know how much time
00603                      * we spent in blocking, so we can avoid a
00604                      * PR_IntervalNow() call.
00605                      */
00606                     if (rv == 0) {
00607                         if (wait_for_remaining) {
00608                             now += remaining;
00609                         } else {
00610                             now += PR_SecondsToInterval(tv.tv_sec)
00611                                 + PR_MicrosecondsToInterval(tv.tv_usec);
00612                         }
00613                     } else {
00614                         now = PR_IntervalNow();
00615                     }
00616                     elapsed = (PRIntervalTime) (now - epoch);
00617                     if (elapsed >= timeout) {
00618                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00619                         rv = -1;
00620                         break;
00621                     } else {
00622                         remaining = timeout - elapsed;
00623                     }
00624                 }
00625             } while (rv == 0 || (rv == -1 && syserror == EINTR));
00626             break;
00627     }
00628     return(rv);
00629 }
00630 
00631 #else /* _PR_USE_POLL */
00632 
00633 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
00634     PRIntervalTime timeout)
00635 {
00636     PRInt32 rv = -1;
00637     int msecs;
00638     PRThread *me = _PR_MD_CURRENT_THREAD();
00639     PRIntervalTime epoch, now, elapsed, remaining;
00640     PRBool wait_for_remaining;
00641     PRInt32 syserror;
00642     struct pollfd pfd;
00643 
00644     switch (timeout) {
00645         case PR_INTERVAL_NO_WAIT:
00646             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00647             break;
00648         case PR_INTERVAL_NO_TIMEOUT:
00649             /*
00650              * This is a special case of the 'default' case below.
00651              * Please see the comments there.
00652              */
00653             msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
00654             pfd.fd = osfd;
00655             if (fd_type == READ_FD) {
00656                 pfd.events = POLLIN;
00657             } else {
00658                 pfd.events = POLLOUT;
00659             }
00660             do {
00661                 rv = _MD_POLL(&pfd, 1, msecs);
00662                 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
00663                     _PR_MD_MAP_POLL_ERROR(syserror);
00664                     break;
00665                 }
00666                             /*
00667                              * If POLLERR is set, don't process it; retry the operation
00668                              */
00669                 if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) {
00670                                    rv = -1;
00671                     _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents);
00672                     break;
00673                 }
00674                 if (_PR_PENDING_INTERRUPT(me)) {
00675                     me->flags &= ~_PR_INTERRUPT;
00676                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00677                     rv = -1;
00678                     break;
00679                 }
00680             } while (rv == 0 || (rv == -1 && syserror == EINTR));
00681             break;
00682         default:
00683             now = epoch = PR_IntervalNow();
00684             remaining = timeout;
00685             pfd.fd = osfd;
00686             if (fd_type == READ_FD) {
00687                 pfd.events = POLLIN;
00688             } else {
00689                 pfd.events = POLLOUT;
00690             }
00691             do {
00692                 /*
00693                  * We block in _MD_POLL for at most
00694                  * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
00695                  * so that there is an upper limit on the delay
00696                  * before the interrupt bit is checked.
00697                  */
00698                 wait_for_remaining = PR_TRUE;
00699                 msecs = PR_IntervalToMilliseconds(remaining);
00700                 if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
00701                     wait_for_remaining = PR_FALSE;
00702                     msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
00703                 }
00704                 rv = _MD_POLL(&pfd, 1, msecs);
00705                 /*
00706                  * we don't consider EINTR a real error
00707                  */
00708                 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
00709                     _PR_MD_MAP_POLL_ERROR(syserror);
00710                     break;
00711                 }
00712                 if (_PR_PENDING_INTERRUPT(me)) {
00713                     me->flags &= ~_PR_INTERRUPT;
00714                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00715                     rv = -1;
00716                     break;
00717                 }
00718                             /*
00719                              * If POLLERR is set, don't process it; retry the operation
00720                              */
00721                 if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) {
00722                                    rv = -1;
00723                     _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents);
00724                     break;
00725                 }
00726                 /*
00727                  * We loop again if _MD_POLL timed out or got interrupted
00728                  * by a signal, and the timeout deadline has not passed yet.
00729                  */
00730                 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
00731                     /*
00732                      * If _MD_POLL timed out, we know how much time
00733                      * we spent in blocking, so we can avoid a
00734                      * PR_IntervalNow() call.
00735                      */
00736                     if (rv == 0) {
00737                         if (wait_for_remaining) {
00738                             now += remaining;
00739                         } else {
00740                             now += PR_MillisecondsToInterval(msecs);
00741                         }
00742                     } else {
00743                         now = PR_IntervalNow();
00744                     }
00745                     elapsed = (PRIntervalTime) (now - epoch);
00746                     if (elapsed >= timeout) {
00747                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00748                         rv = -1;
00749                         break;
00750                     } else {
00751                         remaining = timeout - elapsed;
00752                     }
00753                 }
00754             } while (rv == 0 || (rv == -1 && syserror == EINTR));
00755             break;
00756     }
00757     return(rv);
00758 }
00759 
00760 #endif /* _PR_USE_POLL */
00761 
00762 static PRInt32 local_io_wait(
00763     PRInt32 osfd,
00764     PRInt32 wait_flag,
00765     PRIntervalTime timeout)
00766 {
00767     _PRUnixPollDesc pd;
00768     PRInt32 rv;
00769 
00770     PR_LOG(_pr_io_lm, PR_LOG_MIN,
00771        ("waiting to %s on osfd=%d",
00772         (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write",
00773         osfd));
00774 
00775     if (timeout == PR_INTERVAL_NO_WAIT) return 0;
00776 
00777     pd.osfd = osfd;
00778     pd.in_flags = wait_flag;
00779     pd.out_flags = 0;
00780 
00781     rv = _PR_WaitForMultipleFDs(&pd, 1, timeout);
00782 
00783     if (rv == 0) {
00784         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00785         rv = -1;
00786     }
00787     return rv;
00788 }
00789 
00790 
00791 PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
00792                                 PRInt32 flags, PRIntervalTime timeout)
00793 {
00794     PRInt32 osfd = fd->secret->md.osfd;
00795     PRInt32 rv, err;
00796     PRThread *me = _PR_MD_CURRENT_THREAD();
00797 
00798 /*
00799  * Many OS's (Solaris, Unixware) have a broken recv which won't read
00800  * from socketpairs.  As long as we don't use flags on socketpairs, this
00801  * is a decent fix. - mikep
00802  */
00803 #if defined(UNIXWARE) || defined(SOLARIS) || defined(NCR)
00804     while ((rv = read(osfd,buf,amount)) == -1) {
00805 #else
00806     while ((rv = recv(osfd,buf,amount,flags)) == -1) {
00807 #endif
00808         err = _MD_ERRNO();
00809         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00810             if (fd->secret->nonblocking) {
00811                 break;
00812             }
00813             if (!_PR_IS_NATIVE_THREAD(me)) {
00814                             if ((rv = local_io_wait(osfd,_PR_UNIX_POLL_READ,timeout)) < 0)
00815                                    goto done;
00816             } else {
00817                 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
00818                     goto done;
00819             }
00820         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00821             continue;
00822         } else {
00823             break;
00824         }
00825     }
00826     if (rv < 0) {
00827         _PR_MD_MAP_RECV_ERROR(err);
00828     }
00829 done:
00830     return(rv);
00831 }
00832 
00833 PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
00834                         PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
00835                         PRIntervalTime timeout)
00836 {
00837     PRInt32 osfd = fd->secret->md.osfd;
00838     PRInt32 rv, err;
00839     PRThread *me = _PR_MD_CURRENT_THREAD();
00840 
00841     while ((*addrlen = PR_NETADDR_SIZE(addr)),
00842                 ((rv = recvfrom(osfd, buf, amount, flags,
00843                         (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) {
00844         err = _MD_ERRNO();
00845         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00846             if (fd->secret->nonblocking) {
00847                 break;
00848             }
00849             if (!_PR_IS_NATIVE_THREAD(me)) {
00850                 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0)
00851                     goto done;
00852             } else {
00853                 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
00854                     goto done;
00855             }
00856         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00857             continue;
00858         } else {
00859             break;
00860         }
00861     }
00862     if (rv < 0) {
00863         _PR_MD_MAP_RECVFROM_ERROR(err);
00864     }
00865 done:
00866 #ifdef _PR_HAVE_SOCKADDR_LEN
00867     if (rv != -1) {
00868         /* ignore the sa_len field of struct sockaddr */
00869         if (addr) {
00870             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
00871         }
00872     }
00873 #endif /* _PR_HAVE_SOCKADDR_LEN */
00874     return(rv);
00875 }
00876 
00877 PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
00878                             PRInt32 flags, PRIntervalTime timeout)
00879 {
00880     PRInt32 osfd = fd->secret->md.osfd;
00881     PRInt32 rv, err;
00882     PRThread *me = _PR_MD_CURRENT_THREAD();
00883 #if defined(SOLARIS)
00884        PRInt32 tmp_amount = amount;
00885 #endif
00886 
00887     /*
00888      * On pre-2.6 Solaris, send() is much slower than write().
00889      * On 2.6 and beyond, with in-kernel sockets, send() and
00890      * write() are fairly equivalent in performance.
00891      */
00892 #if defined(SOLARIS)
00893     PR_ASSERT(0 == flags);
00894     while ((rv = write(osfd,buf,tmp_amount)) == -1) {
00895 #else
00896     while ((rv = send(osfd,buf,amount,flags)) == -1) {
00897 #endif
00898         err = _MD_ERRNO();
00899         if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
00900             if (fd->secret->nonblocking) {
00901                 break;
00902             }
00903             if (!_PR_IS_NATIVE_THREAD(me)) {
00904                 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
00905                     goto done;
00906             } else {
00907                 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
00908                     goto done;
00909             }
00910         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00911             continue;
00912         } else {
00913 #if defined(SOLARIS)
00914                      /*
00915                       * The write system call has been reported to return the ERANGE
00916                       * error on occasion. Try to write in smaller chunks to workaround
00917                       * this bug.
00918                       */
00919                      if (err == ERANGE) {
00920                             if (tmp_amount > 1) {
00921                                    tmp_amount = tmp_amount/2;  /* half the bytes */
00922                                    continue;
00923                             }
00924                      }
00925 #endif
00926             break;
00927         }
00928     }
00929         /*
00930          * optimization; if bytes sent is less than "amount" call
00931          * select before returning. This is because it is likely that
00932          * the next send() call will return EWOULDBLOCK.
00933          */
00934     if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
00935             && (timeout != PR_INTERVAL_NO_WAIT)) {
00936         if (_PR_IS_NATIVE_THREAD(me)) {
00937                      if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) {
00938                             rv = -1;
00939                             goto done;
00940                      }
00941         } else {
00942                      if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) {
00943                             rv = -1;
00944                             goto done;
00945                      }
00946         }
00947     }
00948     if (rv < 0) {
00949         _PR_MD_MAP_SEND_ERROR(err);
00950     }
00951 done:
00952     return(rv);
00953 }
00954 
00955 PRInt32 _MD_sendto(
00956     PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
00957     const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
00958 {
00959     PRInt32 osfd = fd->secret->md.osfd;
00960     PRInt32 rv, err;
00961     PRThread *me = _PR_MD_CURRENT_THREAD();
00962 #ifdef _PR_HAVE_SOCKADDR_LEN
00963     PRNetAddr addrCopy;
00964 
00965     addrCopy = *addr;
00966     ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
00967     ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
00968 
00969     while ((rv = sendto(osfd, buf, amount, flags,
00970             (struct sockaddr *) &addrCopy, addrlen)) == -1) {
00971 #else
00972     while ((rv = sendto(osfd, buf, amount, flags,
00973             (struct sockaddr *) addr, addrlen)) == -1) {
00974 #endif
00975         err = _MD_ERRNO();
00976         if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
00977             if (fd->secret->nonblocking) {
00978                 break;
00979             }
00980             if (!_PR_IS_NATIVE_THREAD(me)) {
00981                             if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
00982                                    goto done;
00983             } else {
00984                 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
00985                     goto done;
00986             }
00987         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00988             continue;
00989         } else {
00990             break;
00991         }
00992     }
00993     if (rv < 0) {
00994         _PR_MD_MAP_SENDTO_ERROR(err);
00995     }
00996 done:
00997     return(rv);
00998 }
00999 
01000 PRInt32 _MD_writev(
01001     PRFileDesc *fd, const PRIOVec *iov,
01002     PRInt32 iov_size, PRIntervalTime timeout)
01003 {
01004     PRInt32 rv, err;
01005     PRThread *me = _PR_MD_CURRENT_THREAD();
01006     PRInt32 index, amount = 0;
01007     PRInt32 osfd = fd->secret->md.osfd;
01008 
01009     /*
01010      * Calculate the total number of bytes to be sent; needed for
01011      * optimization later.
01012      * We could avoid this if this number was passed in; but it is
01013      * probably not a big deal because iov_size is usually small (less than
01014      * 3)
01015      */
01016     if (!fd->secret->nonblocking) {
01017         for (index=0; index<iov_size; index++) {
01018             amount += iov[index].iov_len;
01019         }
01020     }
01021 
01022     while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) {
01023         err = _MD_ERRNO();
01024         if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
01025             if (fd->secret->nonblocking) {
01026                 break;
01027             }
01028             if (!_PR_IS_NATIVE_THREAD(me)) {
01029                             if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
01030                                    goto done;
01031             } else {
01032                 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
01033                     goto done;
01034             }
01035         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
01036             continue;
01037         } else {
01038             break;
01039         }
01040     }
01041     /*
01042      * optimization; if bytes sent is less than "amount" call
01043      * select before returning. This is because it is likely that
01044      * the next writev() call will return EWOULDBLOCK.
01045      */
01046     if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
01047             && (timeout != PR_INTERVAL_NO_WAIT)) {
01048         if (_PR_IS_NATIVE_THREAD(me)) {
01049             if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
01050                             rv = -1;
01051                 goto done;
01052                      }
01053         } else {
01054                      if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) {
01055                             rv = -1;
01056                             goto done;
01057                      }
01058         }
01059     }
01060     if (rv < 0) {
01061         _PR_MD_MAP_WRITEV_ERROR(err);
01062     }
01063 done:
01064     return(rv);
01065 }
01066 
01067 PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr,
01068                             PRUint32 *addrlen, PRIntervalTime timeout)
01069 {
01070     PRInt32 osfd = fd->secret->md.osfd;
01071     PRInt32 rv, err;
01072     PRThread *me = _PR_MD_CURRENT_THREAD();
01073 
01074     while ((rv = accept(osfd, (struct sockaddr *) addr,
01075                                         (_PRSockLen_t *)addrlen)) == -1) {
01076         err = _MD_ERRNO();
01077         if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == ECONNABORTED)) {
01078             if (fd->secret->nonblocking) {
01079                 break;
01080             }
01081             if (!_PR_IS_NATIVE_THREAD(me)) {
01082                             if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0)
01083                                    goto done;
01084             } else {
01085                 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
01086                     goto done;
01087             }
01088         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
01089             continue;
01090         } else {
01091             break;
01092         }
01093     }
01094     if (rv < 0) {
01095         _PR_MD_MAP_ACCEPT_ERROR(err);
01096     }
01097 done:
01098 #ifdef _PR_HAVE_SOCKADDR_LEN
01099     if (rv != -1) {
01100         /* ignore the sa_len field of struct sockaddr */
01101         if (addr) {
01102             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
01103         }
01104     }
01105 #endif /* _PR_HAVE_SOCKADDR_LEN */
01106     return(rv);
01107 }
01108 
01109 extern int _connect (int s, const struct sockaddr *name, int namelen);
01110 PRInt32 _MD_connect(
01111     PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
01112 {
01113     PRInt32 rv, err;
01114     PRThread *me = _PR_MD_CURRENT_THREAD();
01115     PRInt32 osfd = fd->secret->md.osfd;
01116 #ifdef IRIX
01117 extern PRInt32 _MD_irix_connect(
01118         PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout);
01119 #endif
01120 #ifdef _PR_HAVE_SOCKADDR_LEN
01121     PRNetAddr addrCopy;
01122 
01123     addrCopy = *addr;
01124     ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
01125     ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
01126 #endif
01127 
01128     /*
01129      * We initiate the connection setup by making a nonblocking connect()
01130      * call.  If the connect() call fails, there are two cases we handle
01131      * specially:
01132      * 1. The connect() call was interrupted by a signal.  In this case
01133      *    we simply retry connect().
01134      * 2. The NSPR socket is nonblocking and connect() fails with
01135      *    EINPROGRESS.  We first wait until the socket becomes writable.
01136      *    Then we try to find out whether the connection setup succeeded
01137      *    or failed.
01138      */
01139 
01140 retry:
01141 #ifdef IRIX
01142     if ((rv = _MD_irix_connect(osfd, addr, addrlen, timeout)) == -1) {
01143 #else
01144 #ifdef _PR_HAVE_SOCKADDR_LEN
01145     if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) {
01146 #else
01147     if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
01148 #endif
01149 #endif
01150         err = _MD_ERRNO();
01151 
01152         if (err == EINTR) {
01153             if (_PR_PENDING_INTERRUPT(me)) {
01154                 me->flags &= ~_PR_INTERRUPT;
01155                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
01156                 return -1;
01157             }
01158             goto retry;
01159         }
01160 
01161         if (!fd->secret->nonblocking && (err == EINPROGRESS)) {
01162             if (!_PR_IS_NATIVE_THREAD(me)) {
01163 
01164                             if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0)
01165                     return -1;
01166             } else {
01167                 /*
01168                  * socket_io_wait() may return -1 or 1.
01169                  */
01170 
01171                 rv = socket_io_wait(osfd, WRITE_FD, timeout);
01172                 if (rv == -1) {
01173                     return -1;
01174                 }
01175             }
01176 
01177             PR_ASSERT(rv == 1);
01178             if (_PR_PENDING_INTERRUPT(me)) {
01179                 me->flags &= ~_PR_INTERRUPT;
01180                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
01181                 return -1;
01182             }
01183             err = _MD_unix_get_nonblocking_connect_error(osfd);
01184             if (err != 0) {
01185                 _PR_MD_MAP_CONNECT_ERROR(err);
01186                 return -1;
01187             }
01188             return 0;
01189         }
01190 
01191         _PR_MD_MAP_CONNECT_ERROR(err);
01192     }
01193 
01194     return rv;
01195 }  /* _MD_connect */
01196 
01197 PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
01198 {
01199     PRInt32 rv, err;
01200 #ifdef _PR_HAVE_SOCKADDR_LEN
01201     PRNetAddr addrCopy;
01202 
01203     addrCopy = *addr;
01204     ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
01205     ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
01206     rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen);
01207 #else
01208     rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
01209 #endif
01210     if (rv < 0) {
01211         err = _MD_ERRNO();
01212         _PR_MD_MAP_BIND_ERROR(err);
01213     }
01214     return(rv);
01215 }
01216 
01217 PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
01218 {
01219     PRInt32 rv, err;
01220 
01221     rv = listen(fd->secret->md.osfd, backlog);
01222     if (rv < 0) {
01223         err = _MD_ERRNO();
01224         _PR_MD_MAP_LISTEN_ERROR(err);
01225     }
01226     return(rv);
01227 }
01228 
01229 PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how)
01230 {
01231     PRInt32 rv, err;
01232 
01233     rv = shutdown(fd->secret->md.osfd, how);
01234     if (rv < 0) {
01235         err = _MD_ERRNO();
01236         _PR_MD_MAP_SHUTDOWN_ERROR(err);
01237     }
01238     return(rv);
01239 }
01240 
01241 PRInt32 _MD_socketpair(int af, int type, int flags,
01242                                                         PRInt32 *osfd)
01243 {
01244     PRInt32 rv, err;
01245 
01246     rv = socketpair(af, type, flags, osfd);
01247     if (rv < 0) {
01248         err = _MD_ERRNO();
01249         _PR_MD_MAP_SOCKETPAIR_ERROR(err);
01250     }
01251     return rv;
01252 }
01253 
01254 PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr,
01255                                                 PRUint32 *addrlen)
01256 {
01257     PRInt32 rv, err;
01258 
01259     rv = getsockname(fd->secret->md.osfd,
01260             (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
01261 #ifdef _PR_HAVE_SOCKADDR_LEN
01262     if (rv == 0) {
01263         /* ignore the sa_len field of struct sockaddr */
01264         if (addr) {
01265             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
01266         }
01267     }
01268 #endif /* _PR_HAVE_SOCKADDR_LEN */
01269     if (rv < 0) {
01270         err = _MD_ERRNO();
01271         _PR_MD_MAP_GETSOCKNAME_ERROR(err);
01272     }
01273     return rv==0?PR_SUCCESS:PR_FAILURE;
01274 }
01275 
01276 PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr,
01277                                         PRUint32 *addrlen)
01278 {
01279     PRInt32 rv, err;
01280 
01281     rv = getpeername(fd->secret->md.osfd,
01282             (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
01283 #ifdef _PR_HAVE_SOCKADDR_LEN
01284     if (rv == 0) {
01285         /* ignore the sa_len field of struct sockaddr */
01286         if (addr) {
01287             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
01288         }
01289     }
01290 #endif /* _PR_HAVE_SOCKADDR_LEN */
01291     if (rv < 0) {
01292         err = _MD_ERRNO();
01293         _PR_MD_MAP_GETPEERNAME_ERROR(err);
01294     }
01295     return rv==0?PR_SUCCESS:PR_FAILURE;
01296 }
01297 
01298 PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level,
01299                         PRInt32 optname, char* optval, PRInt32* optlen)
01300 {
01301     PRInt32 rv, err;
01302 
01303     rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *)optlen);
01304     if (rv < 0) {
01305         err = _MD_ERRNO();
01306         _PR_MD_MAP_GETSOCKOPT_ERROR(err);
01307     }
01308     return rv==0?PR_SUCCESS:PR_FAILURE;
01309 }
01310 
01311 PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level,   
01312                     PRInt32 optname, const char* optval, PRInt32 optlen)
01313 {
01314     PRInt32 rv, err;
01315 
01316     rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
01317     if (rv < 0) {
01318         err = _MD_ERRNO();
01319         _PR_MD_MAP_SETSOCKOPT_ERROR(err);
01320     }
01321     return rv==0?PR_SUCCESS:PR_FAILURE;
01322 }
01323 
01324 PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable)
01325 {
01326     int rv;
01327 
01328     rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC);
01329     if (-1 == rv) {
01330         PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
01331         return PR_FAILURE;
01332     }
01333     return PR_SUCCESS;
01334 }
01335 
01336 void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported)
01337 {
01338     if (imported) {
01339         fd->secret->inheritable = _PR_TRI_UNKNOWN;
01340     } else {
01341         /* By default, a Unix fd is not closed on exec. */
01342 #ifdef DEBUG
01343         {
01344             int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
01345             PR_ASSERT(0 == flags);
01346         }
01347 #endif
01348         fd->secret->inheritable = _PR_TRI_TRUE;
01349     }
01350 }
01351 
01352 /************************************************************************/
01353 #if !defined(_PR_USE_POLL)
01354 
01355 /*
01356 ** Scan through io queue and find any bad fd's that triggered the error
01357 ** from _MD_SELECT
01358 */
01359 static void FindBadFDs(void)
01360 {
01361     PRCList *q;
01362     PRThread *me = _MD_CURRENT_THREAD();
01363 
01364     PR_ASSERT(!_PR_IS_NATIVE_THREAD(me));
01365     q = (_PR_IOQ(me->cpu)).next;
01366     _PR_IOQ_MAX_OSFD(me->cpu) = -1;
01367     _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
01368     while (q != &_PR_IOQ(me->cpu)) {
01369         PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
01370         PRBool notify = PR_FALSE;
01371         _PRUnixPollDesc *pds = pq->pds;
01372         _PRUnixPollDesc *epds = pds + pq->npds;
01373         PRInt32 pq_max_osfd = -1;
01374 
01375         q = q->next;
01376         for (; pds < epds; pds++) {
01377             PRInt32 osfd = pds->osfd;
01378             pds->out_flags = 0;
01379             PR_ASSERT(osfd >= 0 || pds->in_flags == 0);
01380             if (pds->in_flags == 0) {
01381                 continue;  /* skip this fd */
01382             }
01383             if (fcntl(osfd, F_GETFL, 0) == -1) {
01384                 /* Found a bad descriptor, remove it from the fd_sets. */
01385                 PR_LOG(_pr_io_lm, PR_LOG_MAX,
01386                     ("file descriptor %d is bad", osfd));
01387                 pds->out_flags = _PR_UNIX_POLL_NVAL;
01388                 notify = PR_TRUE;
01389             }
01390             if (osfd > pq_max_osfd) {
01391                 pq_max_osfd = osfd;
01392             }
01393         }
01394 
01395         if (notify) {
01396             PRIntn pri;
01397             PR_REMOVE_LINK(&pq->links);
01398             pq->on_ioq = PR_FALSE;
01399 
01400             /*
01401          * Decrement the count of descriptors for each desciptor/event
01402          * because this I/O request is being removed from the
01403          * ioq
01404          */
01405             pds = pq->pds;
01406             for (; pds < epds; pds++) {
01407                 PRInt32 osfd = pds->osfd;
01408                 PRInt16 in_flags = pds->in_flags;
01409                 PR_ASSERT(osfd >= 0 || in_flags == 0);
01410                 if (in_flags & _PR_UNIX_POLL_READ) {
01411                     if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
01412                         FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
01413                 }
01414                 if (in_flags & _PR_UNIX_POLL_WRITE) {
01415                     if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
01416                         FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
01417                 }
01418                 if (in_flags & _PR_UNIX_POLL_EXCEPT) {
01419                     if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
01420                         FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
01421                 }
01422             }
01423 
01424             _PR_THREAD_LOCK(pq->thr);
01425             if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
01426                 _PRCPU *cpu = pq->thr->cpu;
01427                 _PR_SLEEPQ_LOCK(pq->thr->cpu);
01428                 _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
01429                 _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
01430 
01431                             if (pq->thr->flags & _PR_SUSPENDING) {
01432                                 /*
01433                                  * set thread state to SUSPENDED;
01434                                  * a Resume operation on the thread
01435                                  * will move it to the runQ
01436                                  */
01437                                 pq->thr->state = _PR_SUSPENDED;
01438                                 _PR_MISCQ_LOCK(pq->thr->cpu);
01439                                 _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
01440                                 _PR_MISCQ_UNLOCK(pq->thr->cpu);
01441                             } else {
01442                                 pri = pq->thr->priority;
01443                                 pq->thr->state = _PR_RUNNABLE;
01444 
01445                                 _PR_RUNQ_LOCK(cpu);
01446                                 _PR_ADD_RUNQ(pq->thr, cpu, pri);
01447                                 _PR_RUNQ_UNLOCK(cpu);
01448                             }
01449             }
01450             _PR_THREAD_UNLOCK(pq->thr);
01451         } else {
01452             if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
01453                 _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
01454             if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
01455                 _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
01456         }
01457     }
01458     if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
01459         if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0])
01460             _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
01461     }
01462 }
01463 #endif  /* !defined(_PR_USE_POLL) */
01464 
01465 /************************************************************************/
01466 
01467 /*
01468 ** Called by the scheduler when there is nothing to do. This means that
01469 ** all threads are blocked on some monitor somewhere.
01470 **
01471 ** Note: this code doesn't release the scheduler lock.
01472 */
01473 /*
01474 ** Pause the current CPU. longjmp to the cpu's pause stack
01475 **
01476 ** This must be called with the scheduler locked
01477 */
01478 void _MD_PauseCPU(PRIntervalTime ticks)
01479 {
01480     PRThread *me = _MD_CURRENT_THREAD();
01481 #ifdef _PR_USE_POLL
01482     int timeout;
01483     struct pollfd *pollfds;    /* an array of pollfd structures */
01484     struct pollfd *pollfdPtr;    /* a pointer that steps through the array */
01485     unsigned long npollfds;     /* number of pollfd structures in array */
01486     unsigned long pollfds_size;
01487     int nfd;                    /* to hold the return value of poll() */
01488 #else
01489     struct timeval timeout, *tvp;
01490     fd_set r, w, e;
01491     fd_set *rp, *wp, *ep;
01492     PRInt32 max_osfd, nfd;
01493 #endif  /* _PR_USE_POLL */
01494     PRInt32 rv;
01495     PRCList *q;
01496     PRUint32 min_timeout;
01497     sigset_t oldset;
01498 #ifdef IRIX
01499 extern sigset_t ints_off;
01500 #endif
01501 
01502     PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
01503 
01504     _PR_MD_IOQ_LOCK();
01505 
01506 #ifdef _PR_USE_POLL
01507     /* Build up the pollfd structure array to wait on */
01508 
01509     /* Find out how many pollfd structures are needed */
01510     npollfds = _PR_IOQ_OSFD_CNT(me->cpu);
01511     PR_ASSERT(npollfds >= 0);
01512 
01513     /*
01514      * We use a pipe to wake up a native thread.  An fd is needed
01515      * for the pipe and we poll it for reading.
01516      */
01517     if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
01518         npollfds++;
01519 #ifdef IRIX
01520               /*
01521                * On Irix, a second pipe is used to cause the primordial cpu to
01522                * wakeup and exit, when the process is exiting because of a call
01523                * to exit/PR_ProcessExit.
01524                */
01525               if (me->cpu->id == 0) {
01526               npollfds++;
01527               }
01528 #endif
01529        }
01530 
01531     /*
01532      * if the cpu's pollfd array is not big enough, release it and allocate a new one
01533      */
01534     if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) {
01535         if (_PR_IOQ_POLLFDS(me->cpu) != NULL)
01536             PR_DELETE(_PR_IOQ_POLLFDS(me->cpu));
01537         pollfds_size =  PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds);
01538         pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd));
01539         _PR_IOQ_POLLFDS(me->cpu) = pollfds;
01540         _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size;
01541     } else {
01542         pollfds = _PR_IOQ_POLLFDS(me->cpu);
01543     }
01544     pollfdPtr = pollfds;
01545 
01546     /*
01547      * If we need to poll the pipe for waking up a native thread,
01548      * the pipe's fd is the first element in the pollfds array.
01549      */
01550     if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
01551         pollfdPtr->fd = _pr_md_pipefd[0];
01552         pollfdPtr->events = POLLIN;
01553         pollfdPtr++;
01554 #ifdef IRIX
01555               /*
01556                * On Irix, the second element is the exit pipe
01557                */
01558               if (me->cpu->id == 0) {
01559                      pollfdPtr->fd = _pr_irix_primoridal_cpu_fd[0];
01560                      pollfdPtr->events = POLLIN;
01561                      pollfdPtr++;
01562               }
01563 #endif
01564     }
01565 
01566     min_timeout = PR_INTERVAL_NO_TIMEOUT;
01567     for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) {
01568         PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
01569         _PRUnixPollDesc *pds = pq->pds;
01570         _PRUnixPollDesc *epds = pds + pq->npds;
01571 
01572         if (pq->timeout < min_timeout) {
01573             min_timeout = pq->timeout;
01574         }
01575         for (; pds < epds; pds++, pollfdPtr++) {
01576             /*
01577          * Assert that the pollfdPtr pointer does not go
01578          * beyond the end of the pollfds array
01579          */
01580             PR_ASSERT(pollfdPtr < pollfds + npollfds);
01581             pollfdPtr->fd = pds->osfd;
01582             /* direct copy of poll flags */
01583             pollfdPtr->events = pds->in_flags;
01584         }
01585     }
01586     _PR_IOQ_TIMEOUT(me->cpu) = min_timeout;
01587 #else
01588     /*
01589      * assigment of fd_sets
01590      */
01591     r = _PR_FD_READ_SET(me->cpu);
01592     w = _PR_FD_WRITE_SET(me->cpu);
01593     e = _PR_FD_EXCEPTION_SET(me->cpu);
01594 
01595     rp = &r;
01596     wp = &w;
01597     ep = &e;
01598 
01599     max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1;
01600     min_timeout = _PR_IOQ_TIMEOUT(me->cpu);
01601 #endif  /* _PR_USE_POLL */
01602     /*
01603     ** Compute the minimum timeout value: make it the smaller of the
01604     ** timeouts specified by the i/o pollers or the timeout of the first
01605     ** sleeping thread.
01606     */
01607     q = _PR_SLEEPQ(me->cpu).next;
01608 
01609     if (q != &_PR_SLEEPQ(me->cpu)) {
01610         PRThread *t = _PR_THREAD_PTR(q);
01611 
01612         if (t->sleep < min_timeout) {
01613             min_timeout = t->sleep;
01614         }
01615     }
01616     if (min_timeout > ticks) {
01617         min_timeout = ticks;
01618     }
01619 
01620 #ifdef _PR_USE_POLL
01621     if (min_timeout == PR_INTERVAL_NO_TIMEOUT)
01622         timeout = -1;
01623     else
01624         timeout = PR_IntervalToMilliseconds(min_timeout);
01625 #else
01626     if (min_timeout == PR_INTERVAL_NO_TIMEOUT) {
01627         tvp = NULL;
01628     } else {
01629         timeout.tv_sec = PR_IntervalToSeconds(min_timeout);
01630         timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout)
01631             % PR_USEC_PER_SEC;
01632         tvp = &timeout;
01633     }
01634 #endif  /* _PR_USE_POLL */
01635 
01636     _PR_MD_IOQ_UNLOCK();
01637     _MD_CHECK_FOR_EXIT();
01638     /*
01639      * check for i/o operations
01640      */
01641 #ifndef _PR_NO_CLOCK_TIMER
01642     /*
01643      * Disable the clock interrupts while we are in select, if clock interrupts
01644      * are enabled. Otherwise, when the select/poll calls are interrupted, the
01645      * timer value starts ticking from zero again when the system call is restarted.
01646      */
01647 #ifdef IRIX
01648     /*
01649      * SIGCHLD signal is used on Irix to detect he termination of an
01650      * sproc by SIGSEGV, SIGBUS or SIGABRT signals when
01651      * _nspr_terminate_on_error is set.
01652      */
01653     if ((!_nspr_noclock) || (_nspr_terminate_on_error))
01654 #else
01655         if (!_nspr_noclock)
01656 #endif    /* IRIX */
01657 #ifdef IRIX
01658     sigprocmask(SIG_BLOCK, &ints_off, &oldset);
01659 #else
01660     PR_ASSERT(sigismember(&timer_set, SIGALRM));
01661     sigprocmask(SIG_BLOCK, &timer_set, &oldset);
01662 #endif    /* IRIX */
01663 #endif  /* !_PR_NO_CLOCK_TIMER */
01664 
01665 #ifndef _PR_USE_POLL
01666     PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp));
01667     nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp);
01668 #else
01669     nfd = _MD_POLL(pollfds, npollfds, timeout);
01670 #endif  /* !_PR_USE_POLL */
01671 
01672 #ifndef _PR_NO_CLOCK_TIMER
01673 #ifdef IRIX
01674     if ((!_nspr_noclock) || (_nspr_terminate_on_error))
01675 #else
01676         if (!_nspr_noclock)
01677 #endif    /* IRIX */
01678     sigprocmask(SIG_SETMASK, &oldset, 0);
01679 #endif  /* !_PR_NO_CLOCK_TIMER */
01680 
01681     _MD_CHECK_FOR_EXIT();
01682 
01683 #ifdef IRIX
01684        _PR_MD_primordial_cpu();
01685 #endif
01686 
01687     _PR_MD_IOQ_LOCK();
01688     /*
01689     ** Notify monitors that are associated with the selected descriptors.
01690     */
01691 #ifdef _PR_USE_POLL
01692     if (nfd > 0) {
01693         pollfdPtr = pollfds;
01694         if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
01695             /*
01696                       * Assert that the pipe is the first element in the
01697                       * pollfds array.
01698                       */
01699             PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]);
01700             if ((pollfds[0].revents & POLLIN) && (nfd == 1)) {
01701                 /*
01702                              * woken up by another thread; read all the data
01703                              * in the pipe to empty the pipe
01704                              */
01705                 while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf,
01706                     PIPE_BUF)) == PIPE_BUF){
01707                 }
01708                 PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN)));
01709             }
01710             pollfdPtr++;
01711 #ifdef IRIX
01712                      /*
01713                       * On Irix, check to see if the primordial cpu needs to exit
01714                       * to cause the process to terminate
01715                       */
01716                      if (me->cpu->id == 0) {
01717               PR_ASSERT(pollfds[1].fd == _pr_irix_primoridal_cpu_fd[0]);
01718                             if (pollfdPtr->revents & POLLIN) {
01719                                    if (_pr_irix_process_exit) {
01720                                           /*
01721                                            * process exit due to a call to PR_ProcessExit
01722                                            */
01723                                           prctl(PR_SETEXITSIG, SIGKILL);
01724                                           _exit(_pr_irix_process_exit_code);
01725                                    } else {
01726                                           while ((rv = read(_pr_irix_primoridal_cpu_fd[0],
01727                                                  _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) {
01728                                           }
01729                                           PR_ASSERT(rv > 0);
01730                                    }
01731                             }
01732                             pollfdPtr++;
01733                      }
01734 #endif
01735         }
01736         for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) {
01737             PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
01738             PRBool notify = PR_FALSE;
01739             _PRUnixPollDesc *pds = pq->pds;
01740             _PRUnixPollDesc *epds = pds + pq->npds;
01741 
01742             for (; pds < epds; pds++, pollfdPtr++) {
01743                 /*
01744                   * Assert that the pollfdPtr pointer does not go beyond
01745                   * the end of the pollfds array.
01746                   */
01747                 PR_ASSERT(pollfdPtr < pollfds + npollfds);
01748                 /*
01749                  * Assert that the fd's in the pollfds array (stepped
01750                  * through by pollfdPtr) are in the same order as
01751                  * the fd's in _PR_IOQ() (stepped through by q and pds).
01752                  * This is how the pollfds array was created earlier.
01753                  */
01754                 PR_ASSERT(pollfdPtr->fd == pds->osfd);
01755                 pds->out_flags = pollfdPtr->revents;
01756                 /* Negative fd's are ignored by poll() */
01757                 if (pds->osfd >= 0 && pds->out_flags) {
01758                     notify = PR_TRUE;
01759                 }
01760             }
01761             if (notify) {
01762                 PRIntn pri;
01763                 PRThread *thred;
01764 
01765                 PR_REMOVE_LINK(&pq->links);
01766                 pq->on_ioq = PR_FALSE;
01767 
01768                 thred = pq->thr;
01769                 _PR_THREAD_LOCK(thred);
01770                 if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
01771                     _PRCPU *cpu = pq->thr->cpu;
01772                     _PR_SLEEPQ_LOCK(pq->thr->cpu);
01773                     _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
01774                     _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
01775 
01776                                    if (pq->thr->flags & _PR_SUSPENDING) {
01777                                        /*
01778                                         * set thread state to SUSPENDED;
01779                                         * a Resume operation on the thread
01780                                         * will move it to the runQ
01781                                         */
01782                                        pq->thr->state = _PR_SUSPENDED;
01783                                        _PR_MISCQ_LOCK(pq->thr->cpu);
01784                                        _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
01785                                        _PR_MISCQ_UNLOCK(pq->thr->cpu);
01786                                    } else {
01787                                           pri = pq->thr->priority;
01788                                           pq->thr->state = _PR_RUNNABLE;
01789 
01790                                           _PR_RUNQ_LOCK(cpu);
01791                                           _PR_ADD_RUNQ(pq->thr, cpu, pri);
01792                                           _PR_RUNQ_UNLOCK(cpu);
01793                                           if (_pr_md_idle_cpus > 1)
01794                                                  _PR_MD_WAKEUP_WAITER(thred);
01795                                    }
01796                 }
01797                 _PR_THREAD_UNLOCK(thred);
01798                 _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds;
01799                 PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0);
01800             }
01801         }
01802     } else if (nfd == -1) {
01803         PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno));
01804     }
01805 
01806 #else
01807     if (nfd > 0) {
01808         q = _PR_IOQ(me->cpu).next;
01809         _PR_IOQ_MAX_OSFD(me->cpu) = -1;
01810         _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
01811         while (q != &_PR_IOQ(me->cpu)) {
01812             PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
01813             PRBool notify = PR_FALSE;
01814             _PRUnixPollDesc *pds = pq->pds;
01815             _PRUnixPollDesc *epds = pds + pq->npds;
01816             PRInt32 pq_max_osfd = -1;
01817 
01818             q = q->next;
01819             for (; pds < epds; pds++) {
01820                 PRInt32 osfd = pds->osfd;
01821                 PRInt16 in_flags = pds->in_flags;
01822                 PRInt16 out_flags = 0;
01823                 PR_ASSERT(osfd >= 0 || in_flags == 0);
01824                 if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) {
01825                     out_flags |= _PR_UNIX_POLL_READ;
01826                 }
01827                 if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) {
01828                     out_flags |= _PR_UNIX_POLL_WRITE;
01829                 }
01830                 if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) {
01831                     out_flags |= _PR_UNIX_POLL_EXCEPT;
01832                 }
01833                 pds->out_flags = out_flags;
01834                 if (out_flags) {
01835                     notify = PR_TRUE;
01836                 }
01837                 if (osfd > pq_max_osfd) {
01838                     pq_max_osfd = osfd;
01839                 }
01840             }
01841             if (notify == PR_TRUE) {
01842                 PRIntn pri;
01843                 PRThread *thred;
01844 
01845                 PR_REMOVE_LINK(&pq->links);
01846                 pq->on_ioq = PR_FALSE;
01847 
01848                 /*
01849                  * Decrement the count of descriptors for each desciptor/event
01850                  * because this I/O request is being removed from the
01851                  * ioq
01852                  */
01853                 pds = pq->pds;
01854                 for (; pds < epds; pds++) {
01855                     PRInt32 osfd = pds->osfd;
01856                     PRInt16 in_flags = pds->in_flags;
01857                     PR_ASSERT(osfd >= 0 || in_flags == 0);
01858                     if (in_flags & _PR_UNIX_POLL_READ) {
01859                         if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
01860                             FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
01861                     }
01862                     if (in_flags & _PR_UNIX_POLL_WRITE) {
01863                         if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
01864                             FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
01865                     }
01866                     if (in_flags & _PR_UNIX_POLL_EXCEPT) {
01867                         if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
01868                             FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
01869                     }
01870                 }
01871 
01872                 /*
01873                  * Because this thread can run on a different cpu right
01874                  * after being added to the run queue, do not dereference
01875                  * pq
01876                  */
01877                  thred = pq->thr;
01878                 _PR_THREAD_LOCK(thred);
01879                 if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
01880                     _PRCPU *cpu = thred->cpu;
01881                     _PR_SLEEPQ_LOCK(pq->thr->cpu);
01882                     _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
01883                     _PR_SLEEPQ_UNLOCK(pq->thr->cpu);
01884 
01885                                    if (pq->thr->flags & _PR_SUSPENDING) {
01886                                        /*
01887                                         * set thread state to SUSPENDED;
01888                                         * a Resume operation on the thread
01889                                         * will move it to the runQ
01890                                         */
01891                                        pq->thr->state = _PR_SUSPENDED;
01892                                        _PR_MISCQ_LOCK(pq->thr->cpu);
01893                                        _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
01894                                        _PR_MISCQ_UNLOCK(pq->thr->cpu);
01895                                    } else {
01896                                           pri = pq->thr->priority;
01897                                           pq->thr->state = _PR_RUNNABLE;
01898 
01899                                           pq->thr->cpu = cpu;
01900                                           _PR_RUNQ_LOCK(cpu);
01901                                           _PR_ADD_RUNQ(pq->thr, cpu, pri);
01902                                           _PR_RUNQ_UNLOCK(cpu);
01903                                           if (_pr_md_idle_cpus > 1)
01904                                                  _PR_MD_WAKEUP_WAITER(thred);
01905                                    }
01906                 }
01907                 _PR_THREAD_UNLOCK(thred);
01908             } else {
01909                 if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
01910                     _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
01911                 if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
01912                     _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
01913             }
01914         }
01915         if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
01916             if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) {
01917                 /*
01918              * woken up by another thread; read all the data
01919              * in the pipe to empty the pipe
01920              */
01921                 while ((rv =
01922                     read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF))
01923                     == PIPE_BUF){
01924                 }
01925                 PR_ASSERT((rv > 0) ||
01926                     ((rv == -1) && (errno == EAGAIN)));
01927             }
01928             if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0])
01929                 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
01930 #ifdef IRIX
01931                      if ((me->cpu->id == 0) && 
01932                                           (FD_ISSET(_pr_irix_primoridal_cpu_fd[0], rp))) {
01933                             if (_pr_irix_process_exit) {
01934                                    /*
01935                                     * process exit due to a call to PR_ProcessExit
01936                                     */
01937                                    prctl(PR_SETEXITSIG, SIGKILL);
01938                                    _exit(_pr_irix_process_exit_code);
01939                             } else {
01940                                           while ((rv = read(_pr_irix_primoridal_cpu_fd[0],
01941                                                  _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) {
01942                                           }
01943                                           PR_ASSERT(rv > 0);
01944                             }
01945                      }
01946                      if (me->cpu->id == 0) {
01947                             if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_irix_primoridal_cpu_fd[0])
01948                                    _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0];
01949                      }
01950 #endif
01951         }
01952     } else if (nfd < 0) {
01953         if (errno == EBADF) {
01954             FindBadFDs();
01955         } else {
01956             PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d",
01957                 errno));
01958         }
01959     } else {
01960         PR_ASSERT(nfd == 0);
01961         /*
01962          * compute the new value of _PR_IOQ_TIMEOUT
01963          */
01964         q = _PR_IOQ(me->cpu).next;
01965         _PR_IOQ_MAX_OSFD(me->cpu) = -1;
01966         _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
01967         while (q != &_PR_IOQ(me->cpu)) {
01968             PRPollQueue *pq = _PR_POLLQUEUE_PTR(q);
01969             _PRUnixPollDesc *pds = pq->pds;
01970             _PRUnixPollDesc *epds = pds + pq->npds;
01971             PRInt32 pq_max_osfd = -1;
01972 
01973             q = q->next;
01974             for (; pds < epds; pds++) {
01975                 if (pds->osfd > pq_max_osfd) {
01976                     pq_max_osfd = pds->osfd;
01977                 }
01978             }
01979             if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu))
01980                 _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
01981             if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd)
01982                 _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
01983         }
01984         if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
01985             if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0])
01986                 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
01987         }
01988     }
01989 #endif  /* _PR_USE_POLL */
01990     _PR_MD_IOQ_UNLOCK();
01991 }
01992 
01993 void _MD_Wakeup_CPUs()
01994 {
01995     PRInt32 rv, data;
01996 
01997     data = 0;
01998     rv = write(_pr_md_pipefd[1], &data, 1);
01999 
02000     while ((rv < 0) && (errno == EAGAIN)) {
02001         /*
02002          * pipe full, read all data in pipe to empty it
02003          */
02004         while ((rv =
02005             read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF))
02006             == PIPE_BUF) {
02007         }
02008         PR_ASSERT((rv > 0) ||
02009             ((rv == -1) && (errno == EAGAIN)));
02010         rv = write(_pr_md_pipefd[1], &data, 1);
02011     }
02012 }
02013 
02014 
02015 void _MD_InitCPUS()
02016 {
02017     PRInt32 rv, flags;
02018     PRThread *me = _MD_CURRENT_THREAD();
02019 
02020     rv = pipe(_pr_md_pipefd);
02021     PR_ASSERT(rv == 0);
02022     _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
02023 #ifndef _PR_USE_POLL
02024     FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu));
02025 #endif
02026 
02027     flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0);
02028     fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK);
02029     flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0);
02030     fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK);
02031 }
02032 
02033 /*
02034 ** Unix SIGALRM (clock) signal handler
02035 */
02036 static void ClockInterruptHandler()
02037 {
02038     int olderrno;
02039     PRUintn pri;
02040     _PRCPU *cpu = _PR_MD_CURRENT_CPU();
02041     PRThread *me = _MD_CURRENT_THREAD();
02042 
02043 #ifdef SOLARIS
02044     if (!me || _PR_IS_NATIVE_THREAD(me)) {
02045         _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK;
02046         return;
02047     }
02048 #endif
02049 
02050     if (_PR_MD_GET_INTSOFF() != 0) {
02051         cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK;
02052         return;
02053     }
02054     _PR_MD_SET_INTSOFF(1);
02055 
02056     olderrno = errno;
02057     _PR_ClockInterrupt();
02058     errno = olderrno;
02059 
02060     /*
02061     ** If the interrupt wants a resched or if some other thread at
02062     ** the same priority needs the cpu, reschedule.
02063     */
02064     pri = me->priority;
02065     if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) {
02066 #ifdef _PR_NO_PREEMPT
02067         cpu->resched = PR_TRUE;
02068         if (pr_interruptSwitchHook) {
02069             (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg);
02070         }
02071 #else /* _PR_NO_PREEMPT */
02072         /*
02073     ** Re-enable unix interrupts (so that we can use
02074     ** setjmp/longjmp for context switching without having to
02075     ** worry about the signal state)
02076     */
02077         sigprocmask(SIG_SETMASK, &empty_set, 0);
02078         PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch"));
02079 
02080         if(!(me->flags & _PR_IDLE_THREAD)) {
02081             _PR_THREAD_LOCK(me);
02082             me->state = _PR_RUNNABLE;
02083             me->cpu = cpu;
02084             _PR_RUNQ_LOCK(cpu);
02085             _PR_ADD_RUNQ(me, cpu, pri);
02086             _PR_RUNQ_UNLOCK(cpu);
02087             _PR_THREAD_UNLOCK(me);
02088         } else
02089             me->state = _PR_RUNNABLE;
02090         _MD_SWITCH_CONTEXT(me);
02091         PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch"));
02092 #endif /* _PR_NO_PREEMPT */
02093     }
02094     /*
02095      * Because this thread could be running on a different cpu after
02096      * a context switch the current cpu should be accessed and the
02097      * value of the 'cpu' variable should not be used.
02098      */
02099     _PR_MD_SET_INTSOFF(0);
02100 }
02101 
02102 /*
02103  * On HP-UX 9, we have to use the sigvector() interface to restart
02104  * interrupted system calls, because sigaction() does not have the
02105  * SA_RESTART flag.
02106  */
02107 
02108 #ifdef HPUX9
02109 static void HPUX9_ClockInterruptHandler(
02110     int sig,
02111     int code,
02112     struct sigcontext *scp)
02113 {
02114     ClockInterruptHandler();
02115     scp->sc_syscall_action = SIG_RESTART;
02116 }
02117 #endif /* HPUX9 */
02118 
02119 /* # of milliseconds per clock tick that we will use */
02120 #define MSEC_PER_TICK    50
02121 
02122 
02123 void _MD_StartInterrupts()
02124 {
02125     char *eval;
02126 
02127     if ((eval = getenv("NSPR_NOCLOCK")) != NULL) {
02128         if (atoi(eval) == 0)
02129             _nspr_noclock = 0;
02130         else
02131             _nspr_noclock = 1;
02132     }
02133 
02134 #ifndef _PR_NO_CLOCK_TIMER
02135     if (!_nspr_noclock) {
02136         _MD_EnableClockInterrupts();
02137     }
02138 #endif
02139 }
02140 
02141 void _MD_StopInterrupts()
02142 {
02143     sigprocmask(SIG_BLOCK, &timer_set, 0);
02144 }
02145 
02146 void _MD_EnableClockInterrupts()
02147 {
02148     struct itimerval itval;
02149     extern PRUintn _pr_numCPU;
02150 #ifdef HPUX9
02151     struct sigvec vec;
02152 
02153     vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler;
02154     vec.sv_mask = 0;
02155     vec.sv_flags = 0;
02156     sigvector(SIGALRM, &vec, 0);
02157 #else
02158     struct sigaction vtact;
02159 
02160     vtact.sa_handler = (void (*)()) ClockInterruptHandler;
02161     sigemptyset(&vtact.sa_mask);
02162     vtact.sa_flags = SA_RESTART;
02163     sigaction(SIGALRM, &vtact, 0);
02164 #endif /* HPUX9 */
02165 
02166     PR_ASSERT(_pr_numCPU == 1);
02167        itval.it_interval.tv_sec = 0;
02168        itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC;
02169        itval.it_value = itval.it_interval;
02170        setitimer(ITIMER_REAL, &itval, 0);
02171 }
02172 
02173 void _MD_DisableClockInterrupts()
02174 {
02175     struct itimerval itval;
02176     extern PRUintn _pr_numCPU;
02177 
02178     PR_ASSERT(_pr_numCPU == 1);
02179        itval.it_interval.tv_sec = 0;
02180        itval.it_interval.tv_usec = 0;
02181        itval.it_value = itval.it_interval;
02182        setitimer(ITIMER_REAL, &itval, 0);
02183 }
02184 
02185 void _MD_BlockClockInterrupts()
02186 {
02187     sigprocmask(SIG_BLOCK, &timer_set, 0);
02188 }
02189 
02190 void _MD_UnblockClockInterrupts()
02191 {
02192     sigprocmask(SIG_UNBLOCK, &timer_set, 0);
02193 }
02194 
02195 void _MD_MakeNonblock(PRFileDesc *fd)
02196 {
02197     PRInt32 osfd = fd->secret->md.osfd;
02198     int flags;
02199 
02200     if (osfd <= 2) {
02201         /* Don't mess around with stdin, stdout or stderr */
02202         return;
02203     }
02204     flags = fcntl(osfd, F_GETFL, 0);
02205 
02206     /*
02207      * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible.
02208      * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O),
02209      * otherwise connect() still blocks and can be interrupted by SIGALRM.
02210      */
02211 
02212 #ifdef SUNOS4
02213     fcntl(osfd, F_SETFL, flags | FNDELAY);
02214 #else
02215     fcntl(osfd, F_SETFL, flags | O_NONBLOCK);
02216 #endif
02217     }
02218 
02219 PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode)
02220 {
02221     PRInt32 osflags;
02222     PRInt32 rv, err;
02223 
02224     if (flags & PR_RDWR) {
02225         osflags = O_RDWR;
02226     } else if (flags & PR_WRONLY) {
02227         osflags = O_WRONLY;
02228     } else {
02229         osflags = O_RDONLY;
02230     }
02231 
02232     if (flags & PR_EXCL)
02233         osflags |= O_EXCL;
02234     if (flags & PR_APPEND)
02235         osflags |= O_APPEND;
02236     if (flags & PR_TRUNCATE)
02237         osflags |= O_TRUNC;
02238     if (flags & PR_SYNC) {
02239 #if defined(O_SYNC)
02240         osflags |= O_SYNC;
02241 #elif defined(O_FSYNC)
02242         osflags |= O_FSYNC;
02243 #else
02244 #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
02245 #endif
02246     }
02247 
02248     /*
02249     ** On creations we hold the 'create' lock in order to enforce
02250     ** the semantics of PR_Rename. (see the latter for more details)
02251     */
02252     if (flags & PR_CREATE_FILE)
02253     {
02254         osflags |= O_CREAT;
02255         if (NULL !=_pr_rename_lock)
02256             PR_Lock(_pr_rename_lock);
02257     }
02258 
02259     rv = _md_iovector._open64(name, osflags, mode);
02260 
02261     if (rv < 0) {
02262         err = _MD_ERRNO();
02263         _PR_MD_MAP_OPEN_ERROR(err);
02264     }
02265 
02266     if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
02267         PR_Unlock(_pr_rename_lock);
02268     return rv;
02269 }
02270 
02271 PRIntervalTime intr_timeout_ticks;
02272 
02273 #if defined(SOLARIS) || defined(IRIX)
02274 static void sigsegvhandler() {
02275     fprintf(stderr,"Received SIGSEGV\n");
02276     fflush(stderr);
02277     pause();
02278 }
02279 
02280 static void sigaborthandler() {
02281     fprintf(stderr,"Received SIGABRT\n");
02282     fflush(stderr);
02283     pause();
02284 }
02285 
02286 static void sigbushandler() {
02287     fprintf(stderr,"Received SIGBUS\n");
02288     fflush(stderr);
02289     pause();
02290 }
02291 #endif /* SOLARIS, IRIX */
02292 
02293 #endif  /* !defined(_PR_PTHREADS) */
02294 
02295 void _MD_query_fd_inheritable(PRFileDesc *fd)
02296 {
02297     int flags;
02298 
02299     PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
02300     flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
02301     PR_ASSERT(-1 != flags);
02302     fd->secret->inheritable = (flags & FD_CLOEXEC) ?
02303         _PR_TRI_FALSE : _PR_TRI_TRUE;
02304 }
02305 
02306 PROffset32 _MD_lseek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
02307 {
02308     PROffset32 rv, where;
02309 
02310     switch (whence) {
02311         case PR_SEEK_SET:
02312             where = SEEK_SET;
02313             break;
02314         case PR_SEEK_CUR:
02315             where = SEEK_CUR;
02316             break;
02317         case PR_SEEK_END:
02318             where = SEEK_END;
02319             break;
02320         default:
02321             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
02322             rv = -1;
02323             goto done;
02324     }
02325     rv = lseek(fd->secret->md.osfd,offset,where);
02326     if (rv == -1)
02327     {
02328         PRInt32 syserr = _MD_ERRNO();
02329         _PR_MD_MAP_LSEEK_ERROR(syserr);
02330     }
02331 done:
02332     return(rv);
02333 }
02334 
02335 PROffset64 _MD_lseek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
02336 {
02337     PRInt32 where;
02338     PROffset64 rv;
02339 
02340     switch (whence)
02341     {
02342         case PR_SEEK_SET:
02343             where = SEEK_SET;
02344             break;
02345         case PR_SEEK_CUR:
02346             where = SEEK_CUR;
02347             break;
02348         case PR_SEEK_END:
02349             where = SEEK_END;
02350             break;
02351         default:
02352             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
02353             rv = minus_one;
02354             goto done;
02355     }
02356     rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where);
02357     if (LL_EQ(rv, minus_one))
02358     {
02359         PRInt32 syserr = _MD_ERRNO();
02360         _PR_MD_MAP_LSEEK_ERROR(syserr);
02361     }
02362 done:
02363     return rv;
02364 }  /* _MD_lseek64 */
02365 
02366 /*
02367 ** _MD_set_fileinfo_times --
02368 **     Set the modifyTime and creationTime of the PRFileInfo
02369 **     structure using the values in struct stat.
02370 **
02371 ** _MD_set_fileinfo64_times --
02372 **     Set the modifyTime and creationTime of the PRFileInfo64
02373 **     structure using the values in _MDStat64.
02374 */
02375 
02376 #if defined(_PR_STAT_HAS_ST_ATIM)
02377 /*
02378 ** struct stat has st_atim, st_mtim, and st_ctim fields of
02379 ** type timestruc_t.
02380 */
02381 static void _MD_set_fileinfo_times(
02382     const struct stat *sb,
02383     PRFileInfo *info)
02384 {
02385     PRInt64 us, s2us;
02386 
02387     LL_I2L(s2us, PR_USEC_PER_SEC);
02388     LL_I2L(info->modifyTime, sb->st_mtim.tv_sec);
02389     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02390     LL_I2L(us, sb->st_mtim.tv_nsec / 1000);
02391     LL_ADD(info->modifyTime, info->modifyTime, us);
02392     LL_I2L(info->creationTime, sb->st_ctim.tv_sec);
02393     LL_MUL(info->creationTime, info->creationTime, s2us);
02394     LL_I2L(us, sb->st_ctim.tv_nsec / 1000);
02395     LL_ADD(info->creationTime, info->creationTime, us);
02396 }
02397 
02398 static void _MD_set_fileinfo64_times(
02399     const _MDStat64 *sb,
02400     PRFileInfo64 *info)
02401 {
02402     PRInt64 us, s2us;
02403 
02404     LL_I2L(s2us, PR_USEC_PER_SEC);
02405     LL_I2L(info->modifyTime, sb->st_mtim.tv_sec);
02406     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02407     LL_I2L(us, sb->st_mtim.tv_nsec / 1000);
02408     LL_ADD(info->modifyTime, info->modifyTime, us);
02409     LL_I2L(info->creationTime, sb->st_ctim.tv_sec);
02410     LL_MUL(info->creationTime, info->creationTime, s2us);
02411     LL_I2L(us, sb->st_ctim.tv_nsec / 1000);
02412     LL_ADD(info->creationTime, info->creationTime, us);
02413 }
02414 #elif defined(_PR_STAT_HAS_ST_ATIM_UNION)
02415 /*
02416 ** The st_atim, st_mtim, and st_ctim fields in struct stat are
02417 ** unions with a st__tim union member of type timestruc_t.
02418 */
02419 static void _MD_set_fileinfo_times(
02420     const struct stat *sb,
02421     PRFileInfo *info)
02422 {
02423     PRInt64 us, s2us;
02424 
02425     LL_I2L(s2us, PR_USEC_PER_SEC);
02426     LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec);
02427     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02428     LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000);
02429     LL_ADD(info->modifyTime, info->modifyTime, us);
02430     LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec);
02431     LL_MUL(info->creationTime, info->creationTime, s2us);
02432     LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000);
02433     LL_ADD(info->creationTime, info->creationTime, us);
02434 }
02435 
02436 static void _MD_set_fileinfo64_times(
02437     const _MDStat64 *sb,
02438     PRFileInfo64 *info)
02439 {
02440     PRInt64 us, s2us;
02441 
02442     LL_I2L(s2us, PR_USEC_PER_SEC);
02443     LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec);
02444     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02445     LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000);
02446     LL_ADD(info->modifyTime, info->modifyTime, us);
02447     LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec);
02448     LL_MUL(info->creationTime, info->creationTime, s2us);
02449     LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000);
02450     LL_ADD(info->creationTime, info->creationTime, us);
02451 }
02452 #elif defined(_PR_STAT_HAS_ST_ATIMESPEC)
02453 /*
02454 ** struct stat has st_atimespec, st_mtimespec, and st_ctimespec
02455 ** fields of type struct timespec.
02456 */
02457 #if defined(_PR_TIMESPEC_HAS_TS_SEC)
02458 static void _MD_set_fileinfo_times(
02459     const struct stat *sb,
02460     PRFileInfo *info)
02461 {
02462     PRInt64 us, s2us;
02463 
02464     LL_I2L(s2us, PR_USEC_PER_SEC);
02465     LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec);
02466     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02467     LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000);
02468     LL_ADD(info->modifyTime, info->modifyTime, us);
02469     LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec);
02470     LL_MUL(info->creationTime, info->creationTime, s2us);
02471     LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000);
02472     LL_ADD(info->creationTime, info->creationTime, us);
02473 }
02474 
02475 static void _MD_set_fileinfo64_times(
02476     const _MDStat64 *sb,
02477     PRFileInfo64 *info)
02478 {
02479     PRInt64 us, s2us;
02480 
02481     LL_I2L(s2us, PR_USEC_PER_SEC);
02482     LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec);
02483     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02484     LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000);
02485     LL_ADD(info->modifyTime, info->modifyTime, us);
02486     LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec);
02487     LL_MUL(info->creationTime, info->creationTime, s2us);
02488     LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000);
02489     LL_ADD(info->creationTime, info->creationTime, us);
02490 }
02491 #else /* _PR_TIMESPEC_HAS_TS_SEC */
02492 /*
02493 ** The POSIX timespec structure has tv_sec and tv_nsec.
02494 */
02495 static void _MD_set_fileinfo_times(
02496     const struct stat *sb,
02497     PRFileInfo *info)
02498 {
02499     PRInt64 us, s2us;
02500 
02501     LL_I2L(s2us, PR_USEC_PER_SEC);
02502     LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec);
02503     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02504     LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000);
02505     LL_ADD(info->modifyTime, info->modifyTime, us);
02506     LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec);
02507     LL_MUL(info->creationTime, info->creationTime, s2us);
02508     LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000);
02509     LL_ADD(info->creationTime, info->creationTime, us);
02510 }
02511 
02512 static void _MD_set_fileinfo64_times(
02513     const _MDStat64 *sb,
02514     PRFileInfo64 *info)
02515 {
02516     PRInt64 us, s2us;
02517 
02518     LL_I2L(s2us, PR_USEC_PER_SEC);
02519     LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec);
02520     LL_MUL(info->modifyTime, info->modifyTime, s2us);
02521     LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000);
02522     LL_ADD(info->modifyTime, info->modifyTime, us);
02523     LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec);
02524     LL_MUL(info->creationTime, info->creationTime, s2us);
02525     LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000);
02526     LL_ADD(info->creationTime, info->creationTime, us);
02527 }
02528 #endif /* _PR_TIMESPEC_HAS_TS_SEC */
02529 #elif defined(_PR_STAT_HAS_ONLY_ST_ATIME)
02530 /*
02531 ** struct stat only has st_atime, st_mtime, and st_ctime fields
02532 ** of type time_t.
02533 */
02534 static void _MD_set_fileinfo_times(
02535     const struct stat *sb,
02536     PRFileInfo *info)
02537 {
02538     PRInt64 s, s2us;
02539     LL_I2L(s2us, PR_USEC_PER_SEC);
02540     LL_I2L(s, sb->st_mtime);
02541     LL_MUL(s, s, s2us);
02542     info->modifyTime = s;
02543     LL_I2L(s, sb->st_ctime);
02544     LL_MUL(s, s, s2us);
02545     info->creationTime = s;
02546 }
02547 
02548 static void _MD_set_fileinfo64_times(
02549     const _MDStat64 *sb,
02550     PRFileInfo64 *info)
02551 {
02552     PRInt64 s, s2us;
02553     LL_I2L(s2us, PR_USEC_PER_SEC);
02554     LL_I2L(s, sb->st_mtime);
02555     LL_MUL(s, s, s2us);
02556     info->modifyTime = s;
02557     LL_I2L(s, sb->st_ctime);
02558     LL_MUL(s, s, s2us);
02559     info->creationTime = s;
02560 }
02561 #else
02562 #error "I don't know yet"
02563 #endif
02564 
02565 static int _MD_convert_stat_to_fileinfo(
02566     const struct stat *sb,
02567     PRFileInfo *info)
02568 {
02569     if (S_IFREG & sb->st_mode)
02570         info->type = PR_FILE_FILE;
02571     else if (S_IFDIR & sb->st_mode)
02572         info->type = PR_FILE_DIRECTORY;
02573     else
02574         info->type = PR_FILE_OTHER;
02575 
02576 #if defined(_PR_HAVE_LARGE_OFF_T)
02577     if (0x7fffffffL < sb->st_size)
02578     {
02579         PR_SetError(PR_FILE_TOO_BIG_ERROR, 0);
02580         return -1;
02581     }
02582 #endif /* defined(_PR_HAVE_LARGE_OFF_T) */
02583     info->size = sb->st_size;
02584 
02585     _MD_set_fileinfo_times(sb, info);
02586     return 0;
02587 }  /* _MD_convert_stat_to_fileinfo */
02588 
02589 static int _MD_convert_stat64_to_fileinfo64(
02590     const _MDStat64 *sb,
02591     PRFileInfo64 *info)
02592 {
02593     if (S_IFREG & sb->st_mode)
02594         info->type = PR_FILE_FILE;
02595     else if (S_IFDIR & sb->st_mode)
02596         info->type = PR_FILE_DIRECTORY;
02597     else
02598         info->type = PR_FILE_OTHER;
02599 
02600     LL_I2L(info->size, sb->st_size);
02601 
02602     _MD_set_fileinfo64_times(sb, info);
02603     return 0;
02604 }  /* _MD_convert_stat64_to_fileinfo64 */
02605 
02606 PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info)
02607 {
02608     PRInt32 rv;
02609     struct stat sb;
02610 
02611     rv = stat(fn, &sb);
02612     if (rv < 0)
02613         _PR_MD_MAP_STAT_ERROR(_MD_ERRNO());
02614     else if (NULL != info)
02615         rv = _MD_convert_stat_to_fileinfo(&sb, info);
02616     return rv;
02617 }
02618 
02619 PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info)
02620 {
02621     _MDStat64 sb;
02622     PRInt32 rv = _md_iovector._stat64(fn, &sb);
02623     if (rv < 0)
02624         _PR_MD_MAP_STAT_ERROR(_MD_ERRNO());
02625     else if (NULL != info)
02626         rv = _MD_convert_stat64_to_fileinfo64(&sb, info);
02627     return rv;
02628 }
02629 
02630 PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info)
02631 {
02632     struct stat sb;
02633     PRInt32 rv = fstat(fd->secret->md.osfd, &sb);
02634     if (rv < 0)
02635         _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO());
02636     else if (NULL != info)
02637         rv = _MD_convert_stat_to_fileinfo(&sb, info);
02638     return rv;
02639 }
02640 
02641 PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info)
02642 {
02643     _MDStat64 sb;
02644     PRInt32 rv = _md_iovector._fstat64(fd->secret->md.osfd, &sb);
02645     if (rv < 0)
02646         _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO());
02647     else if (NULL != info)
02648         rv = _MD_convert_stat64_to_fileinfo64(&sb, info);
02649     return rv;
02650 }
02651 
02652 struct _MD_IOVector _md_iovector = { open };
02653 
02654 /*
02655 ** These implementations are to emulate large file routines on systems that
02656 ** don't have them. Their goal is to check in case overflow occurs. Otherwise
02657 ** they will just operate as normal using 32-bit file routines.
02658 **
02659 ** The checking might be pre- or post-op, depending on the semantics.
02660 */
02661 
02662 #if defined(SOLARIS2_5)
02663 
02664 static PRIntn _MD_solaris25_fstat64(PRIntn osfd, _MDStat64 *buf)
02665 {
02666     PRInt32 rv;
02667     struct stat sb;
02668 
02669     rv = fstat(osfd, &sb);
02670     if (rv >= 0)
02671     {
02672         /*
02673         ** I'm only copying the fields that are immediately needed.
02674         ** If somebody else calls this function, some of the fields
02675         ** may not be defined.
02676         */
02677         (void)memset(buf, 0, sizeof(_MDStat64));
02678         buf->st_mode = sb.st_mode;
02679         buf->st_ctim = sb.st_ctim;
02680         buf->st_mtim = sb.st_mtim;
02681         buf->st_size = sb.st_size;
02682     }
02683     return rv;
02684 }  /* _MD_solaris25_fstat64 */
02685 
02686 static PRIntn _MD_solaris25_stat64(const char *fn, _MDStat64 *buf)
02687 {
02688     PRInt32 rv;
02689     struct stat sb;
02690 
02691     rv = stat(fn, &sb);
02692     if (rv >= 0)
02693     {
02694         /*
02695         ** I'm only copying the fields that are immediately needed.
02696         ** If somebody else calls this function, some of the fields
02697         ** may not be defined.
02698         */
02699         (void)memset(buf, 0, sizeof(_MDStat64));
02700         buf->st_mode = sb.st_mode;
02701         buf->st_ctim = sb.st_ctim;
02702         buf->st_mtim = sb.st_mtim;
02703         buf->st_size = sb.st_size;
02704     }
02705     return rv;
02706 }  /* _MD_solaris25_stat64 */
02707 #endif /* defined(SOLARIS2_5) */
02708 
02709 #if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5)
02710 
02711 static PROffset64 _MD_Unix_lseek64(PRIntn osfd, PROffset64 offset, PRIntn whence)
02712 {
02713     PRUint64 maxoff;
02714     PROffset64 rv = minus_one;
02715     LL_I2L(maxoff, 0x7fffffff);
02716     if (LL_CMP(offset, <=, maxoff))
02717     {
02718         off_t off;
02719         LL_L2I(off, offset);
02720         LL_I2L(rv, lseek(osfd, off, whence));
02721     }
02722     else errno = EFBIG;  /* we can't go there */
02723     return rv;
02724 }  /* _MD_Unix_lseek64 */
02725 
02726 static void* _MD_Unix_mmap64(
02727     void *addr, PRSize len, PRIntn prot, PRIntn flags,
02728     PRIntn fildes, PRInt64 offset)
02729 {
02730     PR_SetError(PR_FILE_TOO_BIG_ERROR, 0);
02731     return NULL;
02732 }  /* _MD_Unix_mmap64 */
02733 #endif /* defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) */
02734 
02735 #if defined(OSF1) && defined(__GNUC__)
02736 
02737 /*
02738  * On OSF1 V5.0A, <sys/stat.h> defines stat and fstat as
02739  * macros when compiled under gcc, so it is rather tricky to
02740  * take the addresses of the real functions the macros expend
02741  * to.  A simple solution is to define forwarder functions
02742  * and take the addresses of the forwarder functions instead.
02743  */
02744 
02745 static int stat_forwarder(const char *path, struct stat *buffer)
02746 {
02747     return stat(path, buffer);
02748 }
02749 
02750 static int fstat_forwarder(int filedes, struct stat *buffer)
02751 {
02752     return fstat(filedes, buffer);
02753 }
02754 
02755 #endif
02756 
02757 static void _PR_InitIOV(void)
02758 {
02759 #if defined(SOLARIS2_5)
02760     PRLibrary *lib;
02761     void *open64_func;
02762 
02763     open64_func = PR_FindSymbolAndLibrary("open64", &lib);
02764     if (NULL != open64_func)
02765     {
02766         PR_ASSERT(NULL != lib);
02767         _md_iovector._open64 = (_MD_Open64)open64_func;
02768         _md_iovector._mmap64 = (_MD_Mmap64)PR_FindSymbol(lib, "mmap64");
02769         _md_iovector._fstat64 = (_MD_Fstat64)PR_FindSymbol(lib, "fstat64");
02770         _md_iovector._stat64 = (_MD_Stat64)PR_FindSymbol(lib, "stat64");
02771         _md_iovector._lseek64 = (_MD_Lseek64)PR_FindSymbol(lib, "lseek64");
02772         (void)PR_UnloadLibrary(lib);
02773     }
02774     else
02775     {
02776         _md_iovector._open64 = open;
02777         _md_iovector._mmap64 = _MD_Unix_mmap64;
02778         _md_iovector._fstat64 = _MD_solaris25_fstat64;
02779         _md_iovector._stat64 = _MD_solaris25_stat64;
02780         _md_iovector._lseek64 = _MD_Unix_lseek64;
02781     }
02782 #elif defined(_PR_NO_LARGE_FILES)
02783     _md_iovector._open64 = open;
02784     _md_iovector._mmap64 = _MD_Unix_mmap64;
02785     _md_iovector._fstat64 = fstat;
02786     _md_iovector._stat64 = stat;
02787     _md_iovector._lseek64 = _MD_Unix_lseek64;
02788 #elif defined(_PR_HAVE_OFF64_T)
02789 #if defined(IRIX5_3)
02790     _md_iovector._open64 = open;
02791 #else
02792     _md_iovector._open64 = open64;
02793 #endif
02794     _md_iovector._mmap64 = mmap64;
02795     _md_iovector._fstat64 = fstat64;
02796     _md_iovector._stat64 = stat64;
02797     _md_iovector._lseek64 = lseek64;
02798 #elif defined(_PR_HAVE_LARGE_OFF_T)
02799     _md_iovector._open64 = open;
02800     _md_iovector._mmap64 = mmap;
02801 #if defined(OSF1) && defined(__GNUC__)
02802     _md_iovector._fstat64 = fstat_forwarder;
02803     _md_iovector._stat64 = stat_forwarder;
02804 #else
02805     _md_iovector._fstat64 = fstat;
02806     _md_iovector._stat64 = stat;
02807 #endif
02808     _md_iovector._lseek64 = lseek;
02809 #else
02810 #error "I don't know yet"
02811 #endif
02812     LL_I2L(minus_one, -1);
02813 }  /* _PR_InitIOV */
02814 
02815 void _PR_UnixInit(void)
02816 {
02817     struct sigaction sigact;
02818     int rv;
02819 
02820     sigemptyset(&timer_set);
02821 
02822 #if !defined(_PR_PTHREADS)
02823 
02824     sigaddset(&timer_set, SIGALRM);
02825     sigemptyset(&empty_set);
02826     intr_timeout_ticks =
02827             PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS);
02828 
02829 #if defined(SOLARIS) || defined(IRIX)
02830 
02831     if (getenv("NSPR_SIGSEGV_HANDLE")) {
02832         sigact.sa_handler = sigsegvhandler;
02833         sigact.sa_flags = 0;
02834         sigact.sa_mask = timer_set;
02835         sigaction(SIGSEGV, &sigact, 0);
02836     }
02837 
02838     if (getenv("NSPR_SIGABRT_HANDLE")) {
02839         sigact.sa_handler = sigaborthandler;
02840         sigact.sa_flags = 0;
02841         sigact.sa_mask = timer_set;
02842         sigaction(SIGABRT, &sigact, 0);
02843     }
02844 
02845     if (getenv("NSPR_SIGBUS_HANDLE")) {
02846         sigact.sa_handler = sigbushandler;
02847         sigact.sa_flags = 0;
02848         sigact.sa_mask = timer_set;
02849         sigaction(SIGBUS, &sigact, 0);
02850     }
02851 
02852 #endif
02853 #endif  /* !defined(_PR_PTHREADS) */
02854 
02855     /*
02856      * Under HP-UX DCE threads, sigaction() installs a per-thread
02857      * handler, so we use sigvector() to install a process-wide
02858      * handler.
02859      */
02860 #if defined(HPUX) && defined(_PR_DCETHREADS)
02861     {
02862         struct sigvec vec;
02863 
02864         vec.sv_handler = SIG_IGN;
02865         vec.sv_mask = 0;
02866         vec.sv_flags = 0;
02867         rv = sigvector(SIGPIPE, &vec, NULL);
02868         PR_ASSERT(0 == rv);
02869     }
02870 #else
02871     sigact.sa_handler = SIG_IGN;
02872     sigemptyset(&sigact.sa_mask);
02873     sigact.sa_flags = 0;
02874     rv = sigaction(SIGPIPE, &sigact, 0);
02875     PR_ASSERT(0 == rv);
02876 #endif /* HPUX && _PR_DCETHREADS */
02877 
02878     _pr_rename_lock = PR_NewLock();
02879     PR_ASSERT(NULL != _pr_rename_lock);
02880     _pr_Xfe_mon = PR_NewMonitor();
02881     PR_ASSERT(NULL != _pr_Xfe_mon);
02882 
02883     _PR_InitIOV();  /* one last hack */
02884 }
02885 
02886 #if !defined(_PR_PTHREADS)
02887 
02888 /*
02889  * Variables used by the GC code, initialized in _MD_InitSegs().
02890  */
02891 static PRInt32 _pr_zero_fd = -1;
02892 static PRLock *_pr_md_lock = NULL;
02893 
02894 /*
02895  * _MD_InitSegs --
02896  *
02897  * This is Unix's version of _PR_MD_INIT_SEGS(), which is
02898  * called by _PR_InitSegs(), which in turn is called by
02899  * PR_Init().
02900  */
02901 void _MD_InitSegs(void)
02902 {
02903 #ifdef DEBUG
02904     /*
02905     ** Disable using mmap(2) if NSPR_NO_MMAP is set
02906     */
02907     if (getenv("NSPR_NO_MMAP")) {
02908         _pr_zero_fd = -2;
02909         return;
02910     }
02911 #endif
02912     _pr_zero_fd = open("/dev/zero",O_RDWR , 0);
02913     /* Prevent the fd from being inherited by child processes */
02914     fcntl(_pr_zero_fd, F_SETFD, FD_CLOEXEC);
02915     _pr_md_lock = PR_NewLock();
02916 }
02917 
02918 PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr)
02919 {
02920     static char *lastaddr = (char*) _PR_STACK_VMBASE;
02921     PRStatus retval = PR_SUCCESS;
02922     int prot;
02923     void *rv;
02924 
02925     PR_ASSERT(seg != 0);
02926     PR_ASSERT(size != 0);
02927 
02928     PR_Lock(_pr_md_lock);
02929     if (_pr_zero_fd < 0) {
02930 from_heap:
02931         seg->vaddr = PR_MALLOC(size);
02932         if (!seg->vaddr) {
02933             retval = PR_FAILURE;
02934         }
02935         else {
02936             seg->size = size;
02937         }
02938         goto exit;
02939     }
02940 
02941     prot = PROT_READ|PROT_WRITE;
02942     /*
02943      * On Alpha Linux, the user-level thread stack needs
02944      * to be made executable because longjmp/signal seem
02945      * to put machine instructions on the stack.
02946      */
02947 #if defined(LINUX) && defined(__alpha)
02948     prot |= PROT_EXEC;
02949 #endif
02950     rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot,
02951         _MD_MMAP_FLAGS,
02952         _pr_zero_fd, 0);
02953     if (rv == (void*)-1) {
02954         goto from_heap;
02955     }
02956     lastaddr += size;
02957     seg->vaddr = rv;
02958     seg->size = size;
02959     seg->flags = _PR_SEG_VM;
02960 
02961 exit:
02962     PR_Unlock(_pr_md_lock);
02963     return retval;
02964 }
02965 
02966 void _MD_FreeSegment(PRSegment *seg)
02967 {
02968     if (seg->flags & _PR_SEG_VM)
02969         (void) munmap(seg->vaddr, seg->size);
02970     else
02971         PR_DELETE(seg->vaddr);
02972 }
02973 
02974 #endif /* _PR_PTHREADS */
02975 
02976 /*
02977  *-----------------------------------------------------------------------
02978  *
02979  * PR_Now --
02980  *
02981  *     Returns the current time in microseconds since the epoch.
02982  *     The epoch is midnight January 1, 1970 GMT.
02983  *     The implementation is machine dependent.  This is the Unix
02984  *     implementation.
02985  *     Cf. time_t time(time_t *tp)
02986  *
02987  *-----------------------------------------------------------------------
02988  */
02989 
02990 PR_IMPLEMENT(PRTime)
02991 PR_Now(void)
02992 {
02993     struct timeval tv;
02994     PRInt64 s, us, s2us;
02995 
02996     GETTIMEOFDAY(&tv);
02997     LL_I2L(s2us, PR_USEC_PER_SEC);
02998     LL_I2L(s, tv.tv_sec);
02999     LL_I2L(us, tv.tv_usec);
03000     LL_MUL(s, s, s2us);
03001     LL_ADD(s, s, us);
03002     return s;
03003 }
03004 
03005 PRIntervalTime _PR_UNIX_GetInterval()
03006 {
03007     struct timeval time;
03008     PRIntervalTime ticks;
03009 
03010     (void)GETTIMEOFDAY(&time);  /* fallicy of course */
03011     ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC;  /* that's in milliseconds */
03012     ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC;  /* so's that */
03013     return ticks;
03014 }  /* _PR_SUNOS_GetInterval */
03015 
03016 PRIntervalTime _PR_UNIX_TicksPerSecond()
03017 {
03018     return 1000;  /* this needs some work :) */
03019 }
03020 
03021 #if !defined(_PR_PTHREADS)
03022 /*
03023  * Wait for I/O on multiple descriptors.
03024  *
03025  * Return 0 if timed out, return -1 if interrupted,
03026  * else return the number of ready descriptors.
03027  */
03028 PRInt32 _PR_WaitForMultipleFDs(
03029     _PRUnixPollDesc *unixpds,
03030     PRInt32 pdcnt,
03031     PRIntervalTime timeout)
03032 {
03033     PRPollQueue pq;
03034     PRIntn is;
03035     PRInt32 rv;
03036     _PRCPU *io_cpu;
03037     _PRUnixPollDesc *unixpd, *eunixpd;
03038     PRThread *me = _PR_MD_CURRENT_THREAD();
03039 
03040     PR_ASSERT(!(me->flags & _PR_IDLE_THREAD));
03041 
03042     if (_PR_PENDING_INTERRUPT(me)) {
03043         me->flags &= ~_PR_INTERRUPT;
03044         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
03045         return -1;
03046     }
03047 
03048     pq.pds = unixpds;
03049     pq.npds = pdcnt;
03050 
03051     _PR_INTSOFF(is);
03052     _PR_MD_IOQ_LOCK();
03053     _PR_THREAD_LOCK(me);
03054 
03055     pq.thr = me;
03056     io_cpu = me->cpu;
03057     pq.on_ioq = PR_TRUE;
03058     pq.timeout = timeout;
03059     _PR_ADD_TO_IOQ(pq, me->cpu);
03060 
03061 #if !defined(_PR_USE_POLL)
03062     eunixpd = unixpds + pdcnt;
03063     for (unixpd = unixpds; unixpd < eunixpd; unixpd++) {
03064         PRInt32 osfd = unixpd->osfd;
03065         if (unixpd->in_flags & _PR_UNIX_POLL_READ) {
03066             FD_SET(osfd, &_PR_FD_READ_SET(me->cpu));
03067             _PR_FD_READ_CNT(me->cpu)[osfd]++;
03068         }
03069         if (unixpd->in_flags & _PR_UNIX_POLL_WRITE) {
03070             FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu));
03071             (_PR_FD_WRITE_CNT(me->cpu))[osfd]++;
03072         }
03073         if (unixpd->in_flags & _PR_UNIX_POLL_EXCEPT) {
03074             FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
03075             (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++;
03076         }
03077         if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) {
03078             _PR_IOQ_MAX_OSFD(me->cpu) = osfd;
03079         }
03080     }
03081 #endif  /* !defined(_PR_USE_POLL) */
03082 
03083     if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) {
03084         _PR_IOQ_TIMEOUT(me->cpu) = timeout;
03085     }
03086 
03087     _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt;
03088         
03089     _PR_SLEEPQ_LOCK(me->cpu);
03090     _PR_ADD_SLEEPQ(me, timeout);
03091     me->state = _PR_IO_WAIT;
03092     me->io_pending = PR_TRUE;
03093     me->io_suspended = PR_FALSE;
03094     _PR_SLEEPQ_UNLOCK(me->cpu);
03095     _PR_THREAD_UNLOCK(me);
03096     _PR_MD_IOQ_UNLOCK();
03097 
03098     _PR_MD_WAIT(me, timeout);
03099 
03100     me->io_pending = PR_FALSE;
03101     me->io_suspended = PR_FALSE;
03102 
03103     /*
03104      * This thread should run on the same cpu on which it was blocked; when 
03105      * the IO request times out the fd sets and fd counts for the
03106      * cpu are updated below.
03107      */
03108     PR_ASSERT(me->cpu == io_cpu);
03109 
03110     /*
03111     ** If we timed out the pollq might still be on the ioq. Remove it
03112     ** before continuing.
03113     */
03114     if (pq.on_ioq) {
03115         _PR_MD_IOQ_LOCK();
03116         /*
03117          * Need to check pq.on_ioq again
03118          */
03119         if (pq.on_ioq) {
03120             PR_REMOVE_LINK(&pq.links);
03121 #ifndef _PR_USE_POLL
03122             eunixpd = unixpds + pdcnt;
03123             for (unixpd = unixpds; unixpd < eunixpd; unixpd++) {
03124                 PRInt32 osfd = unixpd->osfd;
03125                 PRInt16 in_flags = unixpd->in_flags;
03126 
03127                 if (in_flags & _PR_UNIX_POLL_READ) {
03128                     if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0)
03129                         FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
03130                 }
03131                 if (in_flags & _PR_UNIX_POLL_WRITE) {
03132                     if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0)
03133                         FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
03134                 }
03135                 if (in_flags & _PR_UNIX_POLL_EXCEPT) {
03136                     if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0)
03137                         FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
03138                 }
03139             }
03140 #endif  /* _PR_USE_POLL */
03141             PR_ASSERT(pq.npds == pdcnt);
03142             _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt;
03143             PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0);
03144         }
03145         _PR_MD_IOQ_UNLOCK();
03146     }
03147     /* XXX Should we use _PR_FAST_INTSON or _PR_INTSON? */
03148     if (1 == pdcnt) {
03149         _PR_FAST_INTSON(is);
03150     } else {
03151         _PR_INTSON(is);
03152     }
03153 
03154     if (_PR_PENDING_INTERRUPT(me)) {
03155         me->flags &= ~_PR_INTERRUPT;
03156         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
03157         return -1;
03158     }
03159 
03160     rv = 0;
03161     if (pq.on_ioq == PR_FALSE) {
03162         /* Count the number of ready descriptors */
03163         while (--pdcnt >= 0) {
03164             if (unixpds->out_flags != 0) {
03165                 rv++;
03166             }
03167             unixpds++;
03168         }
03169     }
03170 
03171     return rv;
03172 }
03173 
03174 /*
03175  * Unblock threads waiting for I/O
03176  *    used when interrupting threads
03177  *
03178  * NOTE: The thread lock should held when this function is called.
03179  * On return, the thread lock is released.
03180  */
03181 void _PR_Unblock_IO_Wait(PRThread *thr)
03182 {
03183     int pri = thr->priority;
03184     _PRCPU *cpu = thr->cpu;
03185  
03186     /*
03187      * GLOBAL threads wakeup periodically to check for interrupt
03188      */
03189     if (_PR_IS_NATIVE_THREAD(thr)) {
03190         _PR_THREAD_UNLOCK(thr); 
03191         return;
03192     }
03193 
03194     PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ));
03195     _PR_SLEEPQ_LOCK(cpu);
03196     _PR_DEL_SLEEPQ(thr, PR_TRUE);
03197     _PR_SLEEPQ_UNLOCK(cpu);
03198 
03199     PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD));
03200     thr->state = _PR_RUNNABLE;
03201     _PR_RUNQ_LOCK(cpu);
03202     _PR_ADD_RUNQ(thr, cpu, pri);
03203     _PR_RUNQ_UNLOCK(cpu);
03204     _PR_THREAD_UNLOCK(thr);
03205     _PR_MD_WAKEUP_WAITER(thr);
03206 }
03207 #endif  /* !defined(_PR_PTHREADS) */
03208 
03209 /*
03210  * When a nonblocking connect has completed, determine whether it
03211  * succeeded or failed, and if it failed, what the error code is.
03212  *
03213  * The function returns the error code.  An error code of 0 means
03214  * that the nonblocking connect succeeded.
03215  */
03216 
03217 int _MD_unix_get_nonblocking_connect_error(int osfd)
03218 {
03219 #if defined(NTO)
03220     /* Neutrino does not support the SO_ERROR socket option */
03221     PRInt32      rv;
03222     PRNetAddr    addr;
03223     _PRSockLen_t addrlen = sizeof(addr);
03224 
03225     /* Test to see if we are using the Tiny TCP/IP Stack or the Full one. */
03226     struct statvfs superblock;
03227     rv = fstatvfs(osfd, &superblock);
03228     if (rv == 0) {
03229         if (strcmp(superblock.f_basetype, "ttcpip") == 0) {
03230             /* Using the Tiny Stack! */
03231             rv = getpeername(osfd, (struct sockaddr *) &addr,
03232                     (_PRSockLen_t *) &addrlen);
03233             if (rv == -1) {
03234                 int errno_copy = errno;    /* make a copy so I don't
03235                                             * accidentally reset */
03236 
03237                 if (errno_copy == ENOTCONN) {
03238                     struct stat StatInfo;
03239                     rv = fstat(osfd, &StatInfo);
03240                     if (rv == 0) {
03241                         time_t current_time = time(NULL);
03242 
03243                         /*
03244                          * this is a real hack, can't explain why it
03245                          * works it just does
03246                          */
03247                         if (abs(current_time - StatInfo.st_atime) < 5) {
03248                             return ECONNREFUSED;
03249                         } else {
03250                             return ETIMEDOUT;
03251                         }
03252                     } else {
03253                         return ECONNREFUSED;
03254                     }
03255                 } else {
03256                     return errno_copy;
03257                 }
03258             } else {
03259                 /* No Error */
03260                 return 0;
03261             }
03262         } else {
03263             /* Have the FULL Stack which supports SO_ERROR */
03264             /* Hasn't been written yet, never been tested! */
03265             /* Jerry.Kirk@Nexwarecorp.com */
03266 
03267             int err;
03268             _PRSockLen_t optlen = sizeof(err);
03269 
03270             if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
03271                     (char *) &err, &optlen) == -1) {
03272                 return errno;
03273             } else {
03274                 return err;
03275             }        
03276         }
03277     } else {
03278         return ECONNREFUSED;
03279     }  
03280 #elif defined(NCR) || defined(UNIXWARE) || defined(SNI) || defined(NEC)
03281     /*
03282      * getsockopt() fails with EPIPE, so use getmsg() instead.
03283      */
03284 
03285     int rv;
03286     int flags = 0;
03287     rv = getmsg(osfd, NULL, NULL, &flags);
03288     PR_ASSERT(-1 == rv || 0 == rv);
03289     if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) {
03290         return errno;
03291     }
03292     return 0;  /* no error */
03293 #else
03294     int err;
03295     _PRSockLen_t optlen = sizeof(err);
03296     if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) {
03297         return errno;
03298     } else {
03299         return err;
03300     }
03301 #endif
03302 }
03303 
03304 /************************************************************************/
03305 
03306 /*
03307 ** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread
03308 ** safe.  Unfortunately, neither is mozilla. To make these programs work
03309 ** in a pre-emptive threaded environment, we need to use a lock.
03310 */
03311 
03312 void PR_XLock(void)
03313 {
03314     PR_EnterMonitor(_pr_Xfe_mon);
03315 }
03316 
03317 void PR_XUnlock(void)
03318 {
03319     PR_ExitMonitor(_pr_Xfe_mon);
03320 }
03321 
03322 PRBool PR_XIsLocked(void)
03323 {
03324     return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE;
03325 }
03326 
03327 void PR_XWait(int ms)
03328 {
03329     PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms));
03330 }
03331 
03332 void PR_XNotify(void)
03333 {
03334     PR_Notify(_pr_Xfe_mon);
03335 }
03336 
03337 void PR_XNotifyAll(void)
03338 {
03339     PR_NotifyAll(_pr_Xfe_mon);
03340 }
03341 
03342 #if defined(HAVE_FCNTL_FILE_LOCKING)
03343 
03344 PRStatus
03345 _MD_LockFile(PRInt32 f)
03346 {
03347     PRInt32 rv;
03348     struct flock arg;
03349 
03350     arg.l_type = F_WRLCK;
03351     arg.l_whence = SEEK_SET;
03352     arg.l_start = 0;
03353     arg.l_len = 0;  /* until EOF */
03354     rv = fcntl(f, F_SETLKW, &arg);
03355     if (rv == 0)
03356         return PR_SUCCESS;
03357     _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
03358     return PR_FAILURE;
03359 }
03360 
03361 PRStatus
03362 _MD_TLockFile(PRInt32 f)
03363 {
03364     PRInt32 rv;
03365     struct flock arg;
03366 
03367     arg.l_type = F_WRLCK;
03368     arg.l_whence = SEEK_SET;
03369     arg.l_start = 0;
03370     arg.l_len = 0;  /* until EOF */
03371     rv = fcntl(f, F_SETLK, &arg);
03372     if (rv == 0)
03373         return PR_SUCCESS;
03374     _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
03375     return PR_FAILURE;
03376 }
03377 
03378 PRStatus
03379 _MD_UnlockFile(PRInt32 f)
03380 {
03381     PRInt32 rv;
03382     struct flock arg;
03383 
03384     arg.l_type = F_UNLCK;
03385     arg.l_whence = SEEK_SET;
03386     arg.l_start = 0;
03387     arg.l_len = 0;  /* until EOF */
03388     rv = fcntl(f, F_SETLK, &arg);
03389     if (rv == 0)
03390         return PR_SUCCESS;
03391     _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
03392     return PR_FAILURE;
03393 }
03394 
03395 #elif defined(HAVE_BSD_FLOCK)
03396 
03397 #include <sys/file.h>
03398 
03399 PRStatus
03400 _MD_LockFile(PRInt32 f)
03401 {
03402     PRInt32 rv;
03403     rv = flock(f, LOCK_EX);
03404     if (rv == 0)
03405         return PR_SUCCESS;
03406     _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
03407     return PR_FAILURE;
03408 }
03409 
03410 PRStatus
03411 _MD_TLockFile(PRInt32 f)
03412 {
03413     PRInt32 rv;
03414     rv = flock(f, LOCK_EX|LOCK_NB);
03415     if (rv == 0)
03416         return PR_SUCCESS;
03417     _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
03418     return PR_FAILURE;
03419 }
03420 
03421 PRStatus
03422 _MD_UnlockFile(PRInt32 f)
03423 {
03424     PRInt32 rv;
03425     rv = flock(f, LOCK_UN);
03426     if (rv == 0)
03427         return PR_SUCCESS;
03428     _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
03429     return PR_FAILURE;
03430 }
03431 #else
03432 
03433 PRStatus
03434 _MD_LockFile(PRInt32 f)
03435 {
03436     PRInt32 rv;
03437     rv = lockf(f, F_LOCK, 0);
03438     if (rv == 0)
03439         return PR_SUCCESS;
03440     _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
03441     return PR_FAILURE;
03442 }
03443 
03444 PRStatus
03445 _MD_TLockFile(PRInt32 f)
03446 {
03447     PRInt32 rv;
03448     rv = lockf(f, F_TLOCK, 0);
03449     if (rv == 0)
03450         return PR_SUCCESS;
03451     _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
03452     return PR_FAILURE;
03453 }
03454 
03455 PRStatus
03456 _MD_UnlockFile(PRInt32 f)
03457 {
03458     PRInt32 rv;
03459     rv = lockf(f, F_ULOCK, 0);
03460     if (rv == 0)
03461         return PR_SUCCESS;
03462     _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
03463     return PR_FAILURE;
03464 }
03465 #endif
03466 
03467 PRStatus _MD_gethostname(char *name, PRUint32 namelen)
03468 {
03469     PRIntn rv;
03470 
03471     rv = gethostname(name, namelen);
03472     if (0 == rv) {
03473         return PR_SUCCESS;
03474     }
03475     _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO());
03476     return PR_FAILURE;
03477 }
03478 
03479 PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen)
03480 {
03481        struct utsname info;
03482 
03483        PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE));
03484 
03485        if (uname(&info) == -1) {
03486               _PR_MD_MAP_DEFAULT_ERROR(errno);
03487        return PR_FAILURE;
03488        }
03489        if (PR_SI_SYSNAME == cmd)
03490               (void)PR_snprintf(name, namelen, info.sysname);
03491        else if (PR_SI_RELEASE == cmd)
03492               (void)PR_snprintf(name, namelen, info.release);
03493        else
03494               return PR_FAILURE;
03495     return PR_SUCCESS;
03496 }
03497 
03498 /*
03499  *******************************************************************
03500  *
03501  * Memory-mapped files
03502  *
03503  *******************************************************************
03504  */
03505 
03506 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
03507 {
03508     PRFileInfo info;
03509     PRUint32 sz;
03510 
03511     LL_L2UI(sz, size);
03512     if (sz) {
03513         if (PR_GetOpenFileInfo(fmap->fd, &info) == PR_FAILURE) {
03514             return PR_FAILURE;
03515         }
03516         if (sz > info.size) {
03517             /*
03518              * Need to extend the file
03519              */
03520             if (fmap->prot != PR_PROT_READWRITE) {
03521                 PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
03522                 return PR_FAILURE;
03523             }
03524             if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) {
03525                 return PR_FAILURE;
03526             }
03527             if (PR_Write(fmap->fd, "", 1) != 1) {
03528                 return PR_FAILURE;
03529             }
03530         }
03531     }
03532     if (fmap->prot == PR_PROT_READONLY) {
03533         fmap->md.prot = PROT_READ;
03534 #ifdef OSF1V4_MAP_PRIVATE_BUG
03535         /*
03536          * Use MAP_SHARED to work around a bug in OSF1 V4.0D
03537          * (QAR 70220 in the OSF_QAR database) that results in
03538          * corrupted data in the memory-mapped region.  This
03539          * bug is fixed in V5.0.
03540          */
03541         fmap->md.flags = MAP_SHARED;
03542 #else
03543         fmap->md.flags = MAP_PRIVATE;
03544 #endif
03545     } else if (fmap->prot == PR_PROT_READWRITE) {
03546         fmap->md.prot = PROT_READ | PROT_WRITE;
03547         fmap->md.flags = MAP_SHARED;
03548     } else {
03549         PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
03550         fmap->md.prot = PROT_READ | PROT_WRITE;
03551         fmap->md.flags = MAP_PRIVATE;
03552     }
03553     return PR_SUCCESS;
03554 }
03555 
03556 void * _MD_MemMap(
03557     PRFileMap *fmap,
03558     PRInt64 offset,
03559     PRUint32 len)
03560 {
03561     PRInt32 off;
03562     void *addr;
03563 
03564     LL_L2I(off, offset);
03565     if ((addr = mmap(0, len, fmap->md.prot, fmap->md.flags,
03566         fmap->fd->secret->md.osfd, off)) == (void *) -1) {
03567             _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
03568         addr = NULL;
03569     }
03570     return addr;
03571 }
03572 
03573 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
03574 {
03575     if (munmap(addr, len) == 0) {
03576         return PR_SUCCESS;
03577     } else {
03578     if (errno == EINVAL) {
03579             PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno);
03580     } else {
03581         PR_SetError(PR_UNKNOWN_ERROR, errno);
03582     }
03583         return PR_FAILURE;
03584     }
03585 }
03586 
03587 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
03588 {
03589     if ( PR_TRUE == fmap->md.isAnonFM ) {
03590         PRStatus rc = PR_Close( fmap->fd );
03591         if ( PR_FAILURE == rc ) {
03592             PR_LOG( _pr_io_lm, PR_LOG_DEBUG,
03593                 ("_MD_CloseFileMap(): error closing anonymnous file map osfd"));
03594             return PR_FAILURE;
03595         }
03596     }
03597     PR_DELETE(fmap);
03598     return PR_SUCCESS;
03599 }
03600 
03601 #if defined(_PR_NEED_FAKE_POLL)
03602 
03603 /*
03604  * Some platforms don't have poll().  For easier porting of code
03605  * that calls poll(), we emulate poll() using select().
03606  */
03607 
03608 int poll(struct pollfd *filedes, unsigned long nfds, int timeout)
03609 {
03610     int i;
03611     int rv;
03612     int maxfd;
03613     fd_set rd, wr, ex;
03614     struct timeval tv, *tvp;
03615 
03616     if (timeout < 0 && timeout != -1) {
03617         errno = EINVAL;
03618         return -1;
03619     }
03620 
03621     if (timeout == -1) {
03622         tvp = NULL;
03623     } else {
03624         tv.tv_sec = timeout / 1000;
03625         tv.tv_usec = (timeout % 1000) * 1000;
03626         tvp = &tv;
03627     }
03628 
03629     maxfd = -1;
03630     FD_ZERO(&rd);
03631     FD_ZERO(&wr);
03632     FD_ZERO(&ex);
03633 
03634     for (i = 0; i < nfds; i++) {
03635         int osfd = filedes[i].fd;
03636         int events = filedes[i].events;
03637         PRBool fdHasEvent = PR_FALSE;
03638 
03639         if (osfd < 0) {
03640             continue;  /* Skip this osfd. */
03641         }
03642 
03643         /*
03644          * Map the poll events to the select fd_sets.
03645          *     POLLIN, POLLRDNORM  ===> readable
03646          *     POLLOUT, POLLWRNORM ===> writable
03647          *     POLLPRI, POLLRDBAND ===> exception
03648          *     POLLNORM, POLLWRBAND (and POLLMSG on some platforms)
03649          *     are ignored.
03650          *
03651          * The output events POLLERR and POLLHUP are never turned on.
03652          * POLLNVAL may be turned on.
03653          */
03654 
03655         if (events & (POLLIN | POLLRDNORM)) {
03656             FD_SET(osfd, &rd);
03657             fdHasEvent = PR_TRUE;
03658         }
03659         if (events & (POLLOUT | POLLWRNORM)) {
03660             FD_SET(osfd, &wr);
03661             fdHasEvent = PR_TRUE;
03662         }
03663         if (events & (POLLPRI | POLLRDBAND)) {
03664             FD_SET(osfd, &ex);
03665             fdHasEvent = PR_TRUE;
03666         }
03667         if (fdHasEvent && osfd > maxfd) {
03668             maxfd = osfd;
03669         }
03670     }
03671 
03672     rv = select(maxfd + 1, &rd, &wr, &ex, tvp);
03673 
03674     /* Compute poll results */
03675     if (rv > 0) {
03676         rv = 0;
03677         for (i = 0; i < nfds; i++) {
03678             PRBool fdHasEvent = PR_FALSE;
03679 
03680             filedes[i].revents = 0;
03681             if (filedes[i].fd < 0) {
03682                 continue;
03683             }
03684             if (FD_ISSET(filedes[i].fd, &rd)) {
03685                 if (filedes[i].events & POLLIN) {
03686                     filedes[i].revents |= POLLIN;
03687                 }
03688                 if (filedes[i].events & POLLRDNORM) {
03689                     filedes[i].revents |= POLLRDNORM;
03690                 }
03691                 fdHasEvent = PR_TRUE;
03692             }
03693             if (FD_ISSET(filedes[i].fd, &wr)) {
03694                 if (filedes[i].events & POLLOUT) {
03695                     filedes[i].revents |= POLLOUT;
03696                 }
03697                 if (filedes[i].events & POLLWRNORM) {
03698                     filedes[i].revents |= POLLWRNORM;
03699                 }
03700                 fdHasEvent = PR_TRUE;
03701             }
03702             if (FD_ISSET(filedes[i].fd, &ex)) {
03703                 if (filedes[i].events & POLLPRI) {
03704                     filedes[i].revents |= POLLPRI;
03705                 }
03706                 if (filedes[i].events & POLLRDBAND) {
03707                     filedes[i].revents |= POLLRDBAND;
03708                 }
03709                 fdHasEvent = PR_TRUE;
03710             }
03711             if (fdHasEvent) {
03712                 rv++;
03713             }
03714         }
03715         PR_ASSERT(rv > 0);
03716     } else if (rv == -1 && errno == EBADF) {
03717         rv = 0;
03718         for (i = 0; i < nfds; i++) {
03719             filedes[i].revents = 0;
03720             if (filedes[i].fd < 0) {
03721                 continue;
03722             }
03723             if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) {
03724                 filedes[i].revents = POLLNVAL;
03725                 rv++;
03726             }
03727         }
03728         PR_ASSERT(rv > 0);
03729     }
03730     PR_ASSERT(-1 != timeout || rv != 0);
03731 
03732     return rv;
03733 }
03734 #endif /* _PR_NEED_FAKE_POLL */