andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: #include "primpl.h" andre@0: andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: andre@0: #ifdef _PR_POLL_AVAILABLE andre@0: #include andre@0: #endif andre@0: andre@0: /* To get FIONREAD */ andre@0: #if defined(UNIXWARE) andre@0: #include andre@0: #endif andre@0: andre@0: #if defined(NTO) andre@0: #include andre@0: #endif andre@0: andre@0: /* andre@0: * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or andre@0: * PRInt32* pointer to a _PRSockLen_t* pointer. andre@0: */ andre@0: #if defined(HAVE_SOCKLEN_T) \ andre@0: || (defined(__GLIBC__) && __GLIBC__ >= 2) andre@0: #define _PRSockLen_t socklen_t andre@0: #elif defined(IRIX) || defined(HPUX) || defined(OSF1) || defined(SOLARIS) \ andre@0: || defined(AIX4_1) || defined(LINUX) \ andre@0: || defined(BSDI) || defined(SCO) \ andre@0: || defined(DARWIN) \ andre@0: || defined(QNX) andre@0: #define _PRSockLen_t int andre@0: #elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \ andre@0: || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \ andre@0: || defined(DGUX) || defined(NTO) || defined(RISCOS) andre@0: #define _PRSockLen_t size_t andre@0: #else andre@0: #error "Cannot determine architecture" andre@0: #endif andre@0: andre@0: /* andre@0: ** Global lock variable used to bracket calls into rusty libraries that andre@0: ** aren't thread safe (like libc, libX, etc). andre@0: */ andre@0: static PRLock *_pr_rename_lock = NULL; andre@0: static PRMonitor *_pr_Xfe_mon = NULL; andre@0: andre@0: static PRInt64 minus_one; andre@0: andre@0: sigset_t timer_set; andre@0: andre@0: #if !defined(_PR_PTHREADS) andre@0: andre@0: static sigset_t empty_set; andre@0: andre@0: #ifdef SOLARIS andre@0: #include andre@0: #include andre@0: #endif andre@0: andre@0: #ifndef PIPE_BUF andre@0: #define PIPE_BUF 512 andre@0: #endif andre@0: andre@0: /* andre@0: * _nspr_noclock - if set clock interrupts are disabled andre@0: */ andre@0: int _nspr_noclock = 1; andre@0: andre@0: #ifdef IRIX andre@0: extern PRInt32 _nspr_terminate_on_error; andre@0: #endif andre@0: andre@0: /* andre@0: * There is an assertion in this code that NSPR's definition of PRIOVec andre@0: * is bit compatible with UNIX' definition of a struct iovec. This is andre@0: * applicable to the 'writev()' operations where the types are casually andre@0: * cast to avoid warnings. andre@0: */ andre@0: andre@0: int _pr_md_pipefd[2] = { -1, -1 }; andre@0: static char _pr_md_pipebuf[PIPE_BUF]; andre@0: static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag, andre@0: PRIntervalTime timeout); andre@0: andre@0: _PRInterruptTable _pr_interruptTable[] = { andre@0: { andre@0: "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, andre@0: { andre@0: 0 } andre@0: }; andre@0: andre@0: void _MD_unix_init_running_cpu(_PRCPU *cpu) andre@0: { andre@0: PR_INIT_CLIST(&(cpu->md.md_unix.ioQ)); andre@0: cpu->md.md_unix.ioq_max_osfd = -1; andre@0: cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; andre@0: } andre@0: andre@0: PRStatus _MD_open_dir(_MDDir *d, const char *name) andre@0: { andre@0: int err; andre@0: andre@0: d->d = opendir(name); andre@0: if (!d->d) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_OPENDIR_ERROR(err); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PRInt32 _MD_close_dir(_MDDir *d) andre@0: { andre@0: int rv = 0, err; andre@0: andre@0: if (d->d) { andre@0: rv = closedir(d->d); andre@0: if (rv == -1) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_CLOSEDIR_ERROR(err); andre@0: } andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: char * _MD_read_dir(_MDDir *d, PRIntn flags) andre@0: { andre@0: struct dirent *de; andre@0: int err; andre@0: andre@0: for (;;) { andre@0: /* andre@0: * XXX: readdir() is not MT-safe. There is an MT-safe version andre@0: * readdir_r() on some systems. andre@0: */ andre@0: _MD_ERRNO() = 0; andre@0: de = readdir(d->d); andre@0: if (!de) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_READDIR_ERROR(err); andre@0: return 0; andre@0: } andre@0: if ((flags & PR_SKIP_DOT) && andre@0: (de->d_name[0] == '.') && (de->d_name[1] == 0)) andre@0: continue; andre@0: if ((flags & PR_SKIP_DOT_DOT) && andre@0: (de->d_name[0] == '.') && (de->d_name[1] == '.') && andre@0: (de->d_name[2] == 0)) andre@0: continue; andre@0: if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.')) andre@0: continue; andre@0: break; andre@0: } andre@0: return de->d_name; andre@0: } andre@0: andre@0: PRInt32 _MD_delete(const char *name) andre@0: { andre@0: PRInt32 rv, err; andre@0: #ifdef UNIXWARE andre@0: sigset_t set, oset; andre@0: #endif andre@0: andre@0: #ifdef UNIXWARE andre@0: sigfillset(&set); andre@0: sigprocmask(SIG_SETMASK, &set, &oset); andre@0: #endif andre@0: rv = unlink(name); andre@0: #ifdef UNIXWARE andre@0: sigprocmask(SIG_SETMASK, &oset, NULL); andre@0: #endif andre@0: if (rv == -1) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_UNLINK_ERROR(err); andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_rename(const char *from, const char *to) andre@0: { andre@0: PRInt32 rv = -1, err; andre@0: andre@0: /* andre@0: ** This is trying to enforce the semantics of WINDOZE' rename andre@0: ** operation. That means one is not allowed to rename over top andre@0: ** of an existing file. Holding a lock across these two function andre@0: ** and the open function is known to be a bad idea, but .... andre@0: */ andre@0: if (NULL != _pr_rename_lock) andre@0: PR_Lock(_pr_rename_lock); andre@0: if (0 == access(to, F_OK)) andre@0: PR_SetError(PR_FILE_EXISTS_ERROR, 0); andre@0: else andre@0: { andre@0: rv = rename(from, to); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_RENAME_ERROR(err); andre@0: } andre@0: } andre@0: if (NULL != _pr_rename_lock) andre@0: PR_Unlock(_pr_rename_lock); andre@0: return rv; andre@0: } andre@0: andre@0: PRInt32 _MD_access(const char *name, PRAccessHow how) andre@0: { andre@0: PRInt32 rv, err; andre@0: int amode; andre@0: andre@0: switch (how) { andre@0: case PR_ACCESS_WRITE_OK: andre@0: amode = W_OK; andre@0: break; andre@0: case PR_ACCESS_READ_OK: andre@0: amode = R_OK; andre@0: break; andre@0: case PR_ACCESS_EXISTS: andre@0: amode = F_OK; andre@0: break; andre@0: default: andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: rv = -1; andre@0: goto done; andre@0: } andre@0: rv = access(name, amode); andre@0: andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_ACCESS_ERROR(err); andre@0: } andre@0: andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_mkdir(const char *name, PRIntn mode) andre@0: { andre@0: int rv, err; andre@0: andre@0: /* andre@0: ** This lock is used to enforce rename semantics as described andre@0: ** in PR_Rename. Look there for more fun details. andre@0: */ andre@0: if (NULL !=_pr_rename_lock) andre@0: PR_Lock(_pr_rename_lock); andre@0: rv = mkdir(name, mode); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_MKDIR_ERROR(err); andre@0: } andre@0: if (NULL !=_pr_rename_lock) andre@0: PR_Unlock(_pr_rename_lock); andre@0: return rv; andre@0: } andre@0: andre@0: PRInt32 _MD_rmdir(const char *name) andre@0: { andre@0: int rv, err; andre@0: andre@0: rv = rmdir(name); andre@0: if (rv == -1) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_RMDIR_ERROR(err); andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRInt32 rv, err; andre@0: #ifndef _PR_USE_POLL andre@0: fd_set rd; andre@0: #else andre@0: struct pollfd pfd; andre@0: #endif /* _PR_USE_POLL */ andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: andre@0: #ifndef _PR_USE_POLL andre@0: FD_ZERO(&rd); andre@0: FD_SET(osfd, &rd); andre@0: #else andre@0: pfd.fd = osfd; andre@0: pfd.events = POLLIN; andre@0: #endif /* _PR_USE_POLL */ andre@0: while ((rv = read(osfd,buf,amount)) == -1) { andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, andre@0: PR_INTERVAL_NO_TIMEOUT)) < 0) andre@0: goto done; andre@0: } else { andre@0: #ifndef _PR_USE_POLL andre@0: while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL)) andre@0: == -1 && (err = _MD_ERRNO()) == EINTR) { andre@0: /* retry _MD_SELECT() if it is interrupted */ andre@0: } andre@0: #else /* _PR_USE_POLL */ andre@0: while ((rv = _MD_POLL(&pfd, 1, -1)) andre@0: == -1 && (err = _MD_ERRNO()) == EINTR) { andre@0: /* retry _MD_POLL() if it is interrupted */ andre@0: } andre@0: #endif /* _PR_USE_POLL */ andre@0: if (rv == -1) { andre@0: break; andre@0: } andre@0: } andre@0: if (_PR_PENDING_INTERRUPT(me)) andre@0: break; andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: } else { andre@0: _PR_MD_MAP_READ_ERROR(err); andre@0: } andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRInt32 rv, err; andre@0: #ifndef _PR_USE_POLL andre@0: fd_set wd; andre@0: #else andre@0: struct pollfd pfd; andre@0: #endif /* _PR_USE_POLL */ andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: andre@0: #ifndef _PR_USE_POLL andre@0: FD_ZERO(&wd); andre@0: FD_SET(osfd, &wd); andre@0: #else andre@0: pfd.fd = osfd; andre@0: pfd.events = POLLOUT; andre@0: #endif /* _PR_USE_POLL */ andre@0: while ((rv = write(osfd,buf,amount)) == -1) { andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, andre@0: PR_INTERVAL_NO_TIMEOUT)) < 0) andre@0: goto done; andre@0: } else { andre@0: #ifndef _PR_USE_POLL andre@0: while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL)) andre@0: == -1 && (err = _MD_ERRNO()) == EINTR) { andre@0: /* retry _MD_SELECT() if it is interrupted */ andre@0: } andre@0: #else /* _PR_USE_POLL */ andre@0: while ((rv = _MD_POLL(&pfd, 1, -1)) andre@0: == -1 && (err = _MD_ERRNO()) == EINTR) { andre@0: /* retry _MD_POLL() if it is interrupted */ andre@0: } andre@0: #endif /* _PR_USE_POLL */ andre@0: if (rv == -1) { andre@0: break; andre@0: } andre@0: } andre@0: if (_PR_PENDING_INTERRUPT(me)) andre@0: break; andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: } else { andre@0: _PR_MD_MAP_WRITE_ERROR(err); andre@0: } andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_fsync(PRFileDesc *fd) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = fsync(fd->secret->md.osfd); andre@0: if (rv == -1) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_FSYNC_ERROR(err); andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_close(PRInt32 osfd) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = close(osfd); andre@0: if (rv == -1) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_CLOSE_ERROR(err); andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) andre@0: { andre@0: PRInt32 osfd, err; andre@0: andre@0: osfd = socket(domain, type, proto); andre@0: andre@0: if (osfd == -1) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_SOCKET_ERROR(err); andre@0: return(osfd); andre@0: } andre@0: andre@0: return(osfd); andre@0: } andre@0: andre@0: PRInt32 _MD_socketavailable(PRFileDesc *fd) andre@0: { andre@0: PRInt32 result; andre@0: andre@0: if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { andre@0: _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); andre@0: return -1; andre@0: } andre@0: return result; andre@0: } andre@0: andre@0: PRInt64 _MD_socketavailable64(PRFileDesc *fd) andre@0: { andre@0: PRInt64 result; andre@0: LL_I2L(result, _MD_socketavailable(fd)); andre@0: return result; andre@0: } /* _MD_socketavailable64 */ andre@0: andre@0: #define READ_FD 1 andre@0: #define WRITE_FD 2 andre@0: andre@0: /* andre@0: * socket_io_wait -- andre@0: * andre@0: * wait for socket i/o, periodically checking for interrupt andre@0: * andre@0: * The first implementation uses select(), for platforms without andre@0: * poll(). The second (preferred) implementation uses poll(). andre@0: */ andre@0: andre@0: #ifndef _PR_USE_POLL andre@0: andre@0: static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, andre@0: PRIntervalTime timeout) andre@0: { andre@0: PRInt32 rv = -1; andre@0: struct timeval tv; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRIntervalTime epoch, now, elapsed, remaining; andre@0: PRBool wait_for_remaining; andre@0: PRInt32 syserror; andre@0: fd_set rd_wr; andre@0: andre@0: switch (timeout) { andre@0: case PR_INTERVAL_NO_WAIT: andre@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); andre@0: break; andre@0: case PR_INTERVAL_NO_TIMEOUT: andre@0: /* andre@0: * This is a special case of the 'default' case below. andre@0: * Please see the comments there. andre@0: */ andre@0: tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; andre@0: tv.tv_usec = 0; andre@0: FD_ZERO(&rd_wr); andre@0: do { andre@0: FD_SET(osfd, &rd_wr); andre@0: if (fd_type == READ_FD) andre@0: rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); andre@0: else andre@0: rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); andre@0: if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { andre@0: _PR_MD_MAP_SELECT_ERROR(syserror); andre@0: break; andre@0: } andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: rv = -1; andre@0: break; andre@0: } andre@0: } while (rv == 0 || (rv == -1 && syserror == EINTR)); andre@0: break; andre@0: default: andre@0: now = epoch = PR_IntervalNow(); andre@0: remaining = timeout; andre@0: FD_ZERO(&rd_wr); andre@0: do { andre@0: /* andre@0: * We block in _MD_SELECT for at most andre@0: * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, andre@0: * so that there is an upper limit on the delay andre@0: * before the interrupt bit is checked. andre@0: */ andre@0: wait_for_remaining = PR_TRUE; andre@0: tv.tv_sec = PR_IntervalToSeconds(remaining); andre@0: if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { andre@0: wait_for_remaining = PR_FALSE; andre@0: tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; andre@0: tv.tv_usec = 0; andre@0: } else { andre@0: tv.tv_usec = PR_IntervalToMicroseconds( andre@0: remaining - andre@0: PR_SecondsToInterval(tv.tv_sec)); andre@0: } andre@0: FD_SET(osfd, &rd_wr); andre@0: if (fd_type == READ_FD) andre@0: rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); andre@0: else andre@0: rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); andre@0: /* andre@0: * we don't consider EINTR a real error andre@0: */ andre@0: if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { andre@0: _PR_MD_MAP_SELECT_ERROR(syserror); andre@0: break; andre@0: } andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: rv = -1; andre@0: break; andre@0: } andre@0: /* andre@0: * We loop again if _MD_SELECT timed out or got interrupted andre@0: * by a signal, and the timeout deadline has not passed yet. andre@0: */ andre@0: if (rv == 0 || (rv == -1 && syserror == EINTR)) { andre@0: /* andre@0: * If _MD_SELECT timed out, we know how much time andre@0: * we spent in blocking, so we can avoid a andre@0: * PR_IntervalNow() call. andre@0: */ andre@0: if (rv == 0) { andre@0: if (wait_for_remaining) { andre@0: now += remaining; andre@0: } else { andre@0: now += PR_SecondsToInterval(tv.tv_sec) andre@0: + PR_MicrosecondsToInterval(tv.tv_usec); andre@0: } andre@0: } else { andre@0: now = PR_IntervalNow(); andre@0: } andre@0: elapsed = (PRIntervalTime) (now - epoch); andre@0: if (elapsed >= timeout) { andre@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); andre@0: rv = -1; andre@0: break; andre@0: } else { andre@0: remaining = timeout - elapsed; andre@0: } andre@0: } andre@0: } while (rv == 0 || (rv == -1 && syserror == EINTR)); andre@0: break; andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: #else /* _PR_USE_POLL */ andre@0: andre@0: static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, andre@0: PRIntervalTime timeout) andre@0: { andre@0: PRInt32 rv = -1; andre@0: int msecs; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRIntervalTime epoch, now, elapsed, remaining; andre@0: PRBool wait_for_remaining; andre@0: PRInt32 syserror; andre@0: struct pollfd pfd; andre@0: andre@0: switch (timeout) { andre@0: case PR_INTERVAL_NO_WAIT: andre@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); andre@0: break; andre@0: case PR_INTERVAL_NO_TIMEOUT: andre@0: /* andre@0: * This is a special case of the 'default' case below. andre@0: * Please see the comments there. andre@0: */ andre@0: msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; andre@0: pfd.fd = osfd; andre@0: if (fd_type == READ_FD) { andre@0: pfd.events = POLLIN; andre@0: } else { andre@0: pfd.events = POLLOUT; andre@0: } andre@0: do { andre@0: rv = _MD_POLL(&pfd, 1, msecs); andre@0: if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { andre@0: _PR_MD_MAP_POLL_ERROR(syserror); andre@0: break; andre@0: } andre@0: /* andre@0: * If POLLERR is set, don't process it; retry the operation andre@0: */ andre@0: if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { andre@0: rv = -1; andre@0: _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); andre@0: break; andre@0: } andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: rv = -1; andre@0: break; andre@0: } andre@0: } while (rv == 0 || (rv == -1 && syserror == EINTR)); andre@0: break; andre@0: default: andre@0: now = epoch = PR_IntervalNow(); andre@0: remaining = timeout; andre@0: pfd.fd = osfd; andre@0: if (fd_type == READ_FD) { andre@0: pfd.events = POLLIN; andre@0: } else { andre@0: pfd.events = POLLOUT; andre@0: } andre@0: do { andre@0: /* andre@0: * We block in _MD_POLL for at most andre@0: * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, andre@0: * so that there is an upper limit on the delay andre@0: * before the interrupt bit is checked. andre@0: */ andre@0: wait_for_remaining = PR_TRUE; andre@0: msecs = PR_IntervalToMilliseconds(remaining); andre@0: if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { andre@0: wait_for_remaining = PR_FALSE; andre@0: msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; andre@0: } andre@0: rv = _MD_POLL(&pfd, 1, msecs); andre@0: /* andre@0: * we don't consider EINTR a real error andre@0: */ andre@0: if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { andre@0: _PR_MD_MAP_POLL_ERROR(syserror); andre@0: break; andre@0: } andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: rv = -1; andre@0: break; andre@0: } andre@0: /* andre@0: * If POLLERR is set, don't process it; retry the operation andre@0: */ andre@0: if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { andre@0: rv = -1; andre@0: _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); andre@0: break; andre@0: } andre@0: /* andre@0: * We loop again if _MD_POLL timed out or got interrupted andre@0: * by a signal, and the timeout deadline has not passed yet. andre@0: */ andre@0: if (rv == 0 || (rv == -1 && syserror == EINTR)) { andre@0: /* andre@0: * If _MD_POLL timed out, we know how much time andre@0: * we spent in blocking, so we can avoid a andre@0: * PR_IntervalNow() call. andre@0: */ andre@0: if (rv == 0) { andre@0: if (wait_for_remaining) { andre@0: now += remaining; andre@0: } else { andre@0: now += PR_MillisecondsToInterval(msecs); andre@0: } andre@0: } else { andre@0: now = PR_IntervalNow(); andre@0: } andre@0: elapsed = (PRIntervalTime) (now - epoch); andre@0: if (elapsed >= timeout) { andre@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); andre@0: rv = -1; andre@0: break; andre@0: } else { andre@0: remaining = timeout - elapsed; andre@0: } andre@0: } andre@0: } while (rv == 0 || (rv == -1 && syserror == EINTR)); andre@0: break; andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: #endif /* _PR_USE_POLL */ andre@0: andre@0: static PRInt32 local_io_wait( andre@0: PRInt32 osfd, andre@0: PRInt32 wait_flag, andre@0: PRIntervalTime timeout) andre@0: { andre@0: _PRUnixPollDesc pd; andre@0: PRInt32 rv; andre@0: andre@0: PR_LOG(_pr_io_lm, PR_LOG_MIN, andre@0: ("waiting to %s on osfd=%d", andre@0: (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write", andre@0: osfd)); andre@0: andre@0: if (timeout == PR_INTERVAL_NO_WAIT) return 0; andre@0: andre@0: pd.osfd = osfd; andre@0: pd.in_flags = wait_flag; andre@0: pd.out_flags = 0; andre@0: andre@0: rv = _PR_WaitForMultipleFDs(&pd, 1, timeout); andre@0: andre@0: if (rv == 0) { andre@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); andre@0: rv = -1; andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: andre@0: PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, andre@0: PRInt32 flags, PRIntervalTime timeout) andre@0: { andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: /* andre@0: * Many OS's (Solaris, Unixware) have a broken recv which won't read andre@0: * from socketpairs. As long as we don't use flags on socketpairs, this andre@0: * is a decent fix. - mikep andre@0: */ andre@0: #if defined(UNIXWARE) || defined(SOLARIS) andre@0: while ((rv = read(osfd,buf,amount)) == -1) { andre@0: #else andre@0: while ((rv = recv(osfd,buf,amount,flags)) == -1) { andre@0: #endif andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd,_PR_UNIX_POLL_READ,timeout)) < 0) andre@0: goto done; andre@0: } else { andre@0: if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) andre@0: goto done; andre@0: } andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: _PR_MD_MAP_RECV_ERROR(err); andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, andre@0: PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, andre@0: PRIntervalTime timeout) andre@0: { andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: while ((*addrlen = PR_NETADDR_SIZE(addr)), andre@0: ((rv = recvfrom(osfd, buf, amount, flags, andre@0: (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) { andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) andre@0: goto done; andre@0: } else { andre@0: if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) andre@0: goto done; andre@0: } andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: _PR_MD_MAP_RECVFROM_ERROR(err); andre@0: } andre@0: done: andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: if (rv != -1) { andre@0: /* ignore the sa_len field of struct sockaddr */ andre@0: if (addr) { andre@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; andre@0: } andre@0: } andre@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, andre@0: PRInt32 flags, PRIntervalTime timeout) andre@0: { andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: #if defined(SOLARIS) andre@0: PRInt32 tmp_amount = amount; andre@0: #endif andre@0: andre@0: /* andre@0: * On pre-2.6 Solaris, send() is much slower than write(). andre@0: * On 2.6 and beyond, with in-kernel sockets, send() and andre@0: * write() are fairly equivalent in performance. andre@0: */ andre@0: #if defined(SOLARIS) andre@0: PR_ASSERT(0 == flags); andre@0: while ((rv = write(osfd,buf,tmp_amount)) == -1) { andre@0: #else andre@0: while ((rv = send(osfd,buf,amount,flags)) == -1) { andre@0: #endif andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) andre@0: goto done; andre@0: } else { andre@0: if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) andre@0: goto done; andre@0: } andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: #if defined(SOLARIS) andre@0: /* andre@0: * The write system call has been reported to return the ERANGE andre@0: * error on occasion. Try to write in smaller chunks to workaround andre@0: * this bug. andre@0: */ andre@0: if (err == ERANGE) { andre@0: if (tmp_amount > 1) { andre@0: tmp_amount = tmp_amount/2; /* half the bytes */ andre@0: continue; andre@0: } andre@0: } andre@0: #endif andre@0: break; andre@0: } andre@0: } andre@0: /* andre@0: * optimization; if bytes sent is less than "amount" call andre@0: * select before returning. This is because it is likely that andre@0: * the next send() call will return EWOULDBLOCK. andre@0: */ andre@0: if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) andre@0: && (timeout != PR_INTERVAL_NO_WAIT)) { andre@0: if (_PR_IS_NATIVE_THREAD(me)) { andre@0: if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { andre@0: rv = -1; andre@0: goto done; andre@0: } andre@0: } else { andre@0: if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { andre@0: rv = -1; andre@0: goto done; andre@0: } andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: _PR_MD_MAP_SEND_ERROR(err); andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_sendto( andre@0: PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, andre@0: const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) andre@0: { andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: PRNetAddr addrCopy; andre@0: andre@0: addrCopy = *addr; andre@0: ((struct sockaddr *) &addrCopy)->sa_len = addrlen; andre@0: ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; andre@0: andre@0: while ((rv = sendto(osfd, buf, amount, flags, andre@0: (struct sockaddr *) &addrCopy, addrlen)) == -1) { andre@0: #else andre@0: while ((rv = sendto(osfd, buf, amount, flags, andre@0: (struct sockaddr *) addr, addrlen)) == -1) { andre@0: #endif andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) andre@0: goto done; andre@0: } else { andre@0: if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) andre@0: goto done; andre@0: } andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: _PR_MD_MAP_SENDTO_ERROR(err); andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_writev( andre@0: PRFileDesc *fd, const PRIOVec *iov, andre@0: PRInt32 iov_size, PRIntervalTime timeout) andre@0: { andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRInt32 index, amount = 0; andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: andre@0: /* andre@0: * Calculate the total number of bytes to be sent; needed for andre@0: * optimization later. andre@0: * We could avoid this if this number was passed in; but it is andre@0: * probably not a big deal because iov_size is usually small (less than andre@0: * 3) andre@0: */ andre@0: if (!fd->secret->nonblocking) { andre@0: for (index=0; indexsecret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) andre@0: goto done; andre@0: } else { andre@0: if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) andre@0: goto done; andre@0: } andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: /* andre@0: * optimization; if bytes sent is less than "amount" call andre@0: * select before returning. This is because it is likely that andre@0: * the next writev() call will return EWOULDBLOCK. andre@0: */ andre@0: if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) andre@0: && (timeout != PR_INTERVAL_NO_WAIT)) { andre@0: if (_PR_IS_NATIVE_THREAD(me)) { andre@0: if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { andre@0: rv = -1; andre@0: goto done; andre@0: } andre@0: } else { andre@0: if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { andre@0: rv = -1; andre@0: goto done; andre@0: } andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: _PR_MD_MAP_WRITEV_ERROR(err); andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, andre@0: PRUint32 *addrlen, PRIntervalTime timeout) andre@0: { andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: while ((rv = accept(osfd, (struct sockaddr *) addr, andre@0: (_PRSockLen_t *)addrlen)) == -1) { andre@0: err = _MD_ERRNO(); andre@0: if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == ECONNABORTED)) { andre@0: if (fd->secret->nonblocking) { andre@0: break; andre@0: } andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) andre@0: goto done; andre@0: } else { andre@0: if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) andre@0: goto done; andre@0: } andre@0: } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ andre@0: continue; andre@0: } else { andre@0: break; andre@0: } andre@0: } andre@0: if (rv < 0) { andre@0: _PR_MD_MAP_ACCEPT_ERROR(err); andre@0: } andre@0: done: andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: if (rv != -1) { andre@0: /* ignore the sa_len field of struct sockaddr */ andre@0: if (addr) { andre@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; andre@0: } andre@0: } andre@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ andre@0: return(rv); andre@0: } andre@0: andre@0: extern int _connect (int s, const struct sockaddr *name, int namelen); andre@0: PRInt32 _MD_connect( andre@0: PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) andre@0: { andre@0: PRInt32 rv, err; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: #ifdef IRIX andre@0: extern PRInt32 _MD_irix_connect( andre@0: PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout); andre@0: #endif andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: PRNetAddr addrCopy; andre@0: andre@0: addrCopy = *addr; andre@0: ((struct sockaddr *) &addrCopy)->sa_len = addrlen; andre@0: ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; andre@0: #endif andre@0: andre@0: /* andre@0: * We initiate the connection setup by making a nonblocking connect() andre@0: * call. If the connect() call fails, there are two cases we handle andre@0: * specially: andre@0: * 1. The connect() call was interrupted by a signal. In this case andre@0: * we simply retry connect(). andre@0: * 2. The NSPR socket is nonblocking and connect() fails with andre@0: * EINPROGRESS. We first wait until the socket becomes writable. andre@0: * Then we try to find out whether the connection setup succeeded andre@0: * or failed. andre@0: */ andre@0: andre@0: retry: andre@0: #ifdef IRIX andre@0: if ((rv = _MD_irix_connect(osfd, addr, addrlen, timeout)) == -1) { andre@0: #else andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { andre@0: #else andre@0: if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { andre@0: #endif andre@0: #endif andre@0: err = _MD_ERRNO(); andre@0: andre@0: if (err == EINTR) { andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); andre@0: return -1; andre@0: } andre@0: goto retry; andre@0: } andre@0: andre@0: if (!fd->secret->nonblocking && (err == EINPROGRESS)) { andre@0: if (!_PR_IS_NATIVE_THREAD(me)) { andre@0: andre@0: if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) andre@0: return -1; andre@0: } else { andre@0: /* andre@0: * socket_io_wait() may return -1 or 1. andre@0: */ andre@0: andre@0: rv = socket_io_wait(osfd, WRITE_FD, timeout); andre@0: if (rv == -1) { andre@0: return -1; andre@0: } andre@0: } andre@0: andre@0: PR_ASSERT(rv == 1); andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); andre@0: return -1; andre@0: } andre@0: err = _MD_unix_get_nonblocking_connect_error(osfd); andre@0: if (err != 0) { andre@0: _PR_MD_MAP_CONNECT_ERROR(err); andre@0: return -1; andre@0: } andre@0: return 0; andre@0: } andre@0: andre@0: _PR_MD_MAP_CONNECT_ERROR(err); andre@0: } andre@0: andre@0: return rv; andre@0: } /* _MD_connect */ andre@0: andre@0: PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) andre@0: { andre@0: PRInt32 rv, err; andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: PRNetAddr addrCopy; andre@0: andre@0: addrCopy = *addr; andre@0: ((struct sockaddr *) &addrCopy)->sa_len = addrlen; andre@0: ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; andre@0: rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen); andre@0: #else andre@0: rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); andre@0: #endif andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_BIND_ERROR(err); andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = listen(fd->secret->md.osfd, backlog); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_LISTEN_ERROR(err); andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = shutdown(fd->secret->md.osfd, how); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_SHUTDOWN_ERROR(err); andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: PRInt32 _MD_socketpair(int af, int type, int flags, andre@0: PRInt32 *osfd) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = socketpair(af, type, flags, osfd); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_SOCKETPAIR_ERROR(err); andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, andre@0: PRUint32 *addrlen) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = getsockname(fd->secret->md.osfd, andre@0: (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: if (rv == 0) { andre@0: /* ignore the sa_len field of struct sockaddr */ andre@0: if (addr) { andre@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; andre@0: } andre@0: } andre@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_GETSOCKNAME_ERROR(err); andre@0: } andre@0: return rv==0?PR_SUCCESS:PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, andre@0: PRUint32 *addrlen) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = getpeername(fd->secret->md.osfd, andre@0: (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); andre@0: #ifdef _PR_HAVE_SOCKADDR_LEN andre@0: if (rv == 0) { andre@0: /* ignore the sa_len field of struct sockaddr */ andre@0: if (addr) { andre@0: addr->raw.family = ((struct sockaddr *) addr)->sa_family; andre@0: } andre@0: } andre@0: #endif /* _PR_HAVE_SOCKADDR_LEN */ andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_GETPEERNAME_ERROR(err); andre@0: } andre@0: return rv==0?PR_SUCCESS:PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, andre@0: PRInt32 optname, char* optval, PRInt32* optlen) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *)optlen); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_GETSOCKOPT_ERROR(err); andre@0: } andre@0: return rv==0?PR_SUCCESS:PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, andre@0: PRInt32 optname, const char* optval, PRInt32 optlen) andre@0: { andre@0: PRInt32 rv, err; andre@0: andre@0: rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_SETSOCKOPT_ERROR(err); andre@0: } andre@0: return rv==0?PR_SUCCESS:PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable) andre@0: { andre@0: int rv; andre@0: andre@0: rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); andre@0: if (-1 == rv) { andre@0: PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported) andre@0: { andre@0: if (imported) { andre@0: fd->secret->inheritable = _PR_TRI_UNKNOWN; andre@0: } else { andre@0: /* By default, a Unix fd is not closed on exec. */ andre@0: #ifdef DEBUG andre@0: { andre@0: int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); andre@0: PR_ASSERT(0 == flags); andre@0: } andre@0: #endif andre@0: fd->secret->inheritable = _PR_TRI_TRUE; andre@0: } andre@0: } andre@0: andre@0: /************************************************************************/ andre@0: #if !defined(_PR_USE_POLL) andre@0: andre@0: /* andre@0: ** Scan through io queue and find any bad fd's that triggered the error andre@0: ** from _MD_SELECT andre@0: */ andre@0: static void FindBadFDs(void) andre@0: { andre@0: PRCList *q; andre@0: PRThread *me = _MD_CURRENT_THREAD(); andre@0: andre@0: PR_ASSERT(!_PR_IS_NATIVE_THREAD(me)); andre@0: q = (_PR_IOQ(me->cpu)).next; andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = -1; andre@0: _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; andre@0: while (q != &_PR_IOQ(me->cpu)) { andre@0: PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); andre@0: PRBool notify = PR_FALSE; andre@0: _PRUnixPollDesc *pds = pq->pds; andre@0: _PRUnixPollDesc *epds = pds + pq->npds; andre@0: PRInt32 pq_max_osfd = -1; andre@0: andre@0: q = q->next; andre@0: for (; pds < epds; pds++) { andre@0: PRInt32 osfd = pds->osfd; andre@0: pds->out_flags = 0; andre@0: PR_ASSERT(osfd >= 0 || pds->in_flags == 0); andre@0: if (pds->in_flags == 0) { andre@0: continue; /* skip this fd */ andre@0: } andre@0: if (fcntl(osfd, F_GETFL, 0) == -1) { andre@0: /* Found a bad descriptor, remove it from the fd_sets. */ andre@0: PR_LOG(_pr_io_lm, PR_LOG_MAX, andre@0: ("file descriptor %d is bad", osfd)); andre@0: pds->out_flags = _PR_UNIX_POLL_NVAL; andre@0: notify = PR_TRUE; andre@0: } andre@0: if (osfd > pq_max_osfd) { andre@0: pq_max_osfd = osfd; andre@0: } andre@0: } andre@0: andre@0: if (notify) { andre@0: PRIntn pri; andre@0: PR_REMOVE_LINK(&pq->links); andre@0: pq->on_ioq = PR_FALSE; andre@0: andre@0: /* andre@0: * Decrement the count of descriptors for each desciptor/event andre@0: * because this I/O request is being removed from the andre@0: * ioq andre@0: */ andre@0: pds = pq->pds; andre@0: for (; pds < epds; pds++) { andre@0: PRInt32 osfd = pds->osfd; andre@0: PRInt16 in_flags = pds->in_flags; andre@0: PR_ASSERT(osfd >= 0 || in_flags == 0); andre@0: if (in_flags & _PR_UNIX_POLL_READ) { andre@0: if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); andre@0: } andre@0: if (in_flags & _PR_UNIX_POLL_WRITE) { andre@0: if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); andre@0: } andre@0: if (in_flags & _PR_UNIX_POLL_EXCEPT) { andre@0: if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); andre@0: } andre@0: } andre@0: andre@0: _PR_THREAD_LOCK(pq->thr); andre@0: if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { andre@0: _PRCPU *cpu = pq->thr->cpu; andre@0: _PR_SLEEPQ_LOCK(pq->thr->cpu); andre@0: _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); andre@0: _PR_SLEEPQ_UNLOCK(pq->thr->cpu); andre@0: andre@0: if (pq->thr->flags & _PR_SUSPENDING) { andre@0: /* andre@0: * set thread state to SUSPENDED; andre@0: * a Resume operation on the thread andre@0: * will move it to the runQ andre@0: */ andre@0: pq->thr->state = _PR_SUSPENDED; andre@0: _PR_MISCQ_LOCK(pq->thr->cpu); andre@0: _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); andre@0: _PR_MISCQ_UNLOCK(pq->thr->cpu); andre@0: } else { andre@0: pri = pq->thr->priority; andre@0: pq->thr->state = _PR_RUNNABLE; andre@0: andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(pq->thr, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: } andre@0: } andre@0: _PR_THREAD_UNLOCK(pq->thr); andre@0: } else { andre@0: if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) andre@0: _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; andre@0: } andre@0: } andre@0: if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; andre@0: } andre@0: } andre@0: #endif /* !defined(_PR_USE_POLL) */ andre@0: andre@0: /************************************************************************/ andre@0: andre@0: /* andre@0: ** Called by the scheduler when there is nothing to do. This means that andre@0: ** all threads are blocked on some monitor somewhere. andre@0: ** andre@0: ** Note: this code doesn't release the scheduler lock. andre@0: */ andre@0: /* andre@0: ** Pause the current CPU. longjmp to the cpu's pause stack andre@0: ** andre@0: ** This must be called with the scheduler locked andre@0: */ andre@0: void _MD_PauseCPU(PRIntervalTime ticks) andre@0: { andre@0: PRThread *me = _MD_CURRENT_THREAD(); andre@0: #ifdef _PR_USE_POLL andre@0: int timeout; andre@0: struct pollfd *pollfds; /* an array of pollfd structures */ andre@0: struct pollfd *pollfdPtr; /* a pointer that steps through the array */ andre@0: unsigned long npollfds; /* number of pollfd structures in array */ andre@0: unsigned long pollfds_size; andre@0: int nfd; /* to hold the return value of poll() */ andre@0: #else andre@0: struct timeval timeout, *tvp; andre@0: fd_set r, w, e; andre@0: fd_set *rp, *wp, *ep; andre@0: PRInt32 max_osfd, nfd; andre@0: #endif /* _PR_USE_POLL */ andre@0: PRInt32 rv; andre@0: PRCList *q; andre@0: PRUint32 min_timeout; andre@0: sigset_t oldset; andre@0: #ifdef IRIX andre@0: extern sigset_t ints_off; andre@0: #endif andre@0: andre@0: PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); andre@0: andre@0: _PR_MD_IOQ_LOCK(); andre@0: andre@0: #ifdef _PR_USE_POLL andre@0: /* Build up the pollfd structure array to wait on */ andre@0: andre@0: /* Find out how many pollfd structures are needed */ andre@0: npollfds = _PR_IOQ_OSFD_CNT(me->cpu); andre@0: PR_ASSERT(npollfds >= 0); andre@0: andre@0: /* andre@0: * We use a pipe to wake up a native thread. An fd is needed andre@0: * for the pipe and we poll it for reading. andre@0: */ andre@0: if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { andre@0: npollfds++; andre@0: #ifdef IRIX andre@0: /* andre@0: * On Irix, a second pipe is used to cause the primordial cpu to andre@0: * wakeup and exit, when the process is exiting because of a call andre@0: * to exit/PR_ProcessExit. andre@0: */ andre@0: if (me->cpu->id == 0) { andre@0: npollfds++; andre@0: } andre@0: #endif andre@0: } andre@0: andre@0: /* andre@0: * if the cpu's pollfd array is not big enough, release it and allocate a new one andre@0: */ andre@0: if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) { andre@0: if (_PR_IOQ_POLLFDS(me->cpu) != NULL) andre@0: PR_DELETE(_PR_IOQ_POLLFDS(me->cpu)); andre@0: pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds); andre@0: pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd)); andre@0: _PR_IOQ_POLLFDS(me->cpu) = pollfds; andre@0: _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size; andre@0: } else { andre@0: pollfds = _PR_IOQ_POLLFDS(me->cpu); andre@0: } andre@0: pollfdPtr = pollfds; andre@0: andre@0: /* andre@0: * If we need to poll the pipe for waking up a native thread, andre@0: * the pipe's fd is the first element in the pollfds array. andre@0: */ andre@0: if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { andre@0: pollfdPtr->fd = _pr_md_pipefd[0]; andre@0: pollfdPtr->events = POLLIN; andre@0: pollfdPtr++; andre@0: #ifdef IRIX andre@0: /* andre@0: * On Irix, the second element is the exit pipe andre@0: */ andre@0: if (me->cpu->id == 0) { andre@0: pollfdPtr->fd = _pr_irix_primoridal_cpu_fd[0]; andre@0: pollfdPtr->events = POLLIN; andre@0: pollfdPtr++; andre@0: } andre@0: #endif andre@0: } andre@0: andre@0: min_timeout = PR_INTERVAL_NO_TIMEOUT; andre@0: for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { andre@0: PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); andre@0: _PRUnixPollDesc *pds = pq->pds; andre@0: _PRUnixPollDesc *epds = pds + pq->npds; andre@0: andre@0: if (pq->timeout < min_timeout) { andre@0: min_timeout = pq->timeout; andre@0: } andre@0: for (; pds < epds; pds++, pollfdPtr++) { andre@0: /* andre@0: * Assert that the pollfdPtr pointer does not go andre@0: * beyond the end of the pollfds array andre@0: */ andre@0: PR_ASSERT(pollfdPtr < pollfds + npollfds); andre@0: pollfdPtr->fd = pds->osfd; andre@0: /* direct copy of poll flags */ andre@0: pollfdPtr->events = pds->in_flags; andre@0: } andre@0: } andre@0: _PR_IOQ_TIMEOUT(me->cpu) = min_timeout; andre@0: #else andre@0: /* andre@0: * assigment of fd_sets andre@0: */ andre@0: r = _PR_FD_READ_SET(me->cpu); andre@0: w = _PR_FD_WRITE_SET(me->cpu); andre@0: e = _PR_FD_EXCEPTION_SET(me->cpu); andre@0: andre@0: rp = &r; andre@0: wp = &w; andre@0: ep = &e; andre@0: andre@0: max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; andre@0: min_timeout = _PR_IOQ_TIMEOUT(me->cpu); andre@0: #endif /* _PR_USE_POLL */ andre@0: /* andre@0: ** Compute the minimum timeout value: make it the smaller of the andre@0: ** timeouts specified by the i/o pollers or the timeout of the first andre@0: ** sleeping thread. andre@0: */ andre@0: q = _PR_SLEEPQ(me->cpu).next; andre@0: andre@0: if (q != &_PR_SLEEPQ(me->cpu)) { andre@0: PRThread *t = _PR_THREAD_PTR(q); andre@0: andre@0: if (t->sleep < min_timeout) { andre@0: min_timeout = t->sleep; andre@0: } andre@0: } andre@0: if (min_timeout > ticks) { andre@0: min_timeout = ticks; andre@0: } andre@0: andre@0: #ifdef _PR_USE_POLL andre@0: if (min_timeout == PR_INTERVAL_NO_TIMEOUT) andre@0: timeout = -1; andre@0: else andre@0: timeout = PR_IntervalToMilliseconds(min_timeout); andre@0: #else andre@0: if (min_timeout == PR_INTERVAL_NO_TIMEOUT) { andre@0: tvp = NULL; andre@0: } else { andre@0: timeout.tv_sec = PR_IntervalToSeconds(min_timeout); andre@0: timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) andre@0: % PR_USEC_PER_SEC; andre@0: tvp = &timeout; andre@0: } andre@0: #endif /* _PR_USE_POLL */ andre@0: andre@0: _PR_MD_IOQ_UNLOCK(); andre@0: _MD_CHECK_FOR_EXIT(); andre@0: /* andre@0: * check for i/o operations andre@0: */ andre@0: #ifndef _PR_NO_CLOCK_TIMER andre@0: /* andre@0: * Disable the clock interrupts while we are in select, if clock interrupts andre@0: * are enabled. Otherwise, when the select/poll calls are interrupted, the andre@0: * timer value starts ticking from zero again when the system call is restarted. andre@0: */ andre@0: #ifdef IRIX andre@0: /* andre@0: * SIGCHLD signal is used on Irix to detect he termination of an andre@0: * sproc by SIGSEGV, SIGBUS or SIGABRT signals when andre@0: * _nspr_terminate_on_error is set. andre@0: */ andre@0: if ((!_nspr_noclock) || (_nspr_terminate_on_error)) andre@0: #else andre@0: if (!_nspr_noclock) andre@0: #endif /* IRIX */ andre@0: #ifdef IRIX andre@0: sigprocmask(SIG_BLOCK, &ints_off, &oldset); andre@0: #else andre@0: PR_ASSERT(sigismember(&timer_set, SIGALRM)); andre@0: sigprocmask(SIG_BLOCK, &timer_set, &oldset); andre@0: #endif /* IRIX */ andre@0: #endif /* !_PR_NO_CLOCK_TIMER */ andre@0: andre@0: #ifndef _PR_USE_POLL andre@0: PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp)); andre@0: nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); andre@0: #else andre@0: nfd = _MD_POLL(pollfds, npollfds, timeout); andre@0: #endif /* !_PR_USE_POLL */ andre@0: andre@0: #ifndef _PR_NO_CLOCK_TIMER andre@0: #ifdef IRIX andre@0: if ((!_nspr_noclock) || (_nspr_terminate_on_error)) andre@0: #else andre@0: if (!_nspr_noclock) andre@0: #endif /* IRIX */ andre@0: sigprocmask(SIG_SETMASK, &oldset, 0); andre@0: #endif /* !_PR_NO_CLOCK_TIMER */ andre@0: andre@0: _MD_CHECK_FOR_EXIT(); andre@0: andre@0: #ifdef IRIX andre@0: _PR_MD_primordial_cpu(); andre@0: #endif andre@0: andre@0: _PR_MD_IOQ_LOCK(); andre@0: /* andre@0: ** Notify monitors that are associated with the selected descriptors. andre@0: */ andre@0: #ifdef _PR_USE_POLL andre@0: if (nfd > 0) { andre@0: pollfdPtr = pollfds; andre@0: if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { andre@0: /* andre@0: * Assert that the pipe is the first element in the andre@0: * pollfds array. andre@0: */ andre@0: PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]); andre@0: if ((pollfds[0].revents & POLLIN) && (nfd == 1)) { andre@0: /* andre@0: * woken up by another thread; read all the data andre@0: * in the pipe to empty the pipe andre@0: */ andre@0: while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, andre@0: PIPE_BUF)) == PIPE_BUF){ andre@0: } andre@0: PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN))); andre@0: } andre@0: pollfdPtr++; andre@0: #ifdef IRIX andre@0: /* andre@0: * On Irix, check to see if the primordial cpu needs to exit andre@0: * to cause the process to terminate andre@0: */ andre@0: if (me->cpu->id == 0) { andre@0: PR_ASSERT(pollfds[1].fd == _pr_irix_primoridal_cpu_fd[0]); andre@0: if (pollfdPtr->revents & POLLIN) { andre@0: if (_pr_irix_process_exit) { andre@0: /* andre@0: * process exit due to a call to PR_ProcessExit andre@0: */ andre@0: prctl(PR_SETEXITSIG, SIGKILL); andre@0: _exit(_pr_irix_process_exit_code); andre@0: } else { andre@0: while ((rv = read(_pr_irix_primoridal_cpu_fd[0], andre@0: _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) { andre@0: } andre@0: PR_ASSERT(rv > 0); andre@0: } andre@0: } andre@0: pollfdPtr++; andre@0: } andre@0: #endif andre@0: } andre@0: for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { andre@0: PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); andre@0: PRBool notify = PR_FALSE; andre@0: _PRUnixPollDesc *pds = pq->pds; andre@0: _PRUnixPollDesc *epds = pds + pq->npds; andre@0: andre@0: for (; pds < epds; pds++, pollfdPtr++) { andre@0: /* andre@0: * Assert that the pollfdPtr pointer does not go beyond andre@0: * the end of the pollfds array. andre@0: */ andre@0: PR_ASSERT(pollfdPtr < pollfds + npollfds); andre@0: /* andre@0: * Assert that the fd's in the pollfds array (stepped andre@0: * through by pollfdPtr) are in the same order as andre@0: * the fd's in _PR_IOQ() (stepped through by q and pds). andre@0: * This is how the pollfds array was created earlier. andre@0: */ andre@0: PR_ASSERT(pollfdPtr->fd == pds->osfd); andre@0: pds->out_flags = pollfdPtr->revents; andre@0: /* Negative fd's are ignored by poll() */ andre@0: if (pds->osfd >= 0 && pds->out_flags) { andre@0: notify = PR_TRUE; andre@0: } andre@0: } andre@0: if (notify) { andre@0: PRIntn pri; andre@0: PRThread *thred; andre@0: andre@0: PR_REMOVE_LINK(&pq->links); andre@0: pq->on_ioq = PR_FALSE; andre@0: andre@0: thred = pq->thr; andre@0: _PR_THREAD_LOCK(thred); andre@0: if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { andre@0: _PRCPU *cpu = pq->thr->cpu; andre@0: _PR_SLEEPQ_LOCK(pq->thr->cpu); andre@0: _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); andre@0: _PR_SLEEPQ_UNLOCK(pq->thr->cpu); andre@0: andre@0: if (pq->thr->flags & _PR_SUSPENDING) { andre@0: /* andre@0: * set thread state to SUSPENDED; andre@0: * a Resume operation on the thread andre@0: * will move it to the runQ andre@0: */ andre@0: pq->thr->state = _PR_SUSPENDED; andre@0: _PR_MISCQ_LOCK(pq->thr->cpu); andre@0: _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); andre@0: _PR_MISCQ_UNLOCK(pq->thr->cpu); andre@0: } else { andre@0: pri = pq->thr->priority; andre@0: pq->thr->state = _PR_RUNNABLE; andre@0: andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(pq->thr, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: if (_pr_md_idle_cpus > 1) andre@0: _PR_MD_WAKEUP_WAITER(thred); andre@0: } andre@0: } andre@0: _PR_THREAD_UNLOCK(thred); andre@0: _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds; andre@0: PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); andre@0: } andre@0: } andre@0: } else if (nfd == -1) { andre@0: PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno)); andre@0: } andre@0: andre@0: #else andre@0: if (nfd > 0) { andre@0: q = _PR_IOQ(me->cpu).next; andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = -1; andre@0: _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; andre@0: while (q != &_PR_IOQ(me->cpu)) { andre@0: PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); andre@0: PRBool notify = PR_FALSE; andre@0: _PRUnixPollDesc *pds = pq->pds; andre@0: _PRUnixPollDesc *epds = pds + pq->npds; andre@0: PRInt32 pq_max_osfd = -1; andre@0: andre@0: q = q->next; andre@0: for (; pds < epds; pds++) { andre@0: PRInt32 osfd = pds->osfd; andre@0: PRInt16 in_flags = pds->in_flags; andre@0: PRInt16 out_flags = 0; andre@0: PR_ASSERT(osfd >= 0 || in_flags == 0); andre@0: if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) { andre@0: out_flags |= _PR_UNIX_POLL_READ; andre@0: } andre@0: if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) { andre@0: out_flags |= _PR_UNIX_POLL_WRITE; andre@0: } andre@0: if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) { andre@0: out_flags |= _PR_UNIX_POLL_EXCEPT; andre@0: } andre@0: pds->out_flags = out_flags; andre@0: if (out_flags) { andre@0: notify = PR_TRUE; andre@0: } andre@0: if (osfd > pq_max_osfd) { andre@0: pq_max_osfd = osfd; andre@0: } andre@0: } andre@0: if (notify == PR_TRUE) { andre@0: PRIntn pri; andre@0: PRThread *thred; andre@0: andre@0: PR_REMOVE_LINK(&pq->links); andre@0: pq->on_ioq = PR_FALSE; andre@0: andre@0: /* andre@0: * Decrement the count of descriptors for each desciptor/event andre@0: * because this I/O request is being removed from the andre@0: * ioq andre@0: */ andre@0: pds = pq->pds; andre@0: for (; pds < epds; pds++) { andre@0: PRInt32 osfd = pds->osfd; andre@0: PRInt16 in_flags = pds->in_flags; andre@0: PR_ASSERT(osfd >= 0 || in_flags == 0); andre@0: if (in_flags & _PR_UNIX_POLL_READ) { andre@0: if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); andre@0: } andre@0: if (in_flags & _PR_UNIX_POLL_WRITE) { andre@0: if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); andre@0: } andre@0: if (in_flags & _PR_UNIX_POLL_EXCEPT) { andre@0: if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); andre@0: } andre@0: } andre@0: andre@0: /* andre@0: * Because this thread can run on a different cpu right andre@0: * after being added to the run queue, do not dereference andre@0: * pq andre@0: */ andre@0: thred = pq->thr; andre@0: _PR_THREAD_LOCK(thred); andre@0: if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { andre@0: _PRCPU *cpu = thred->cpu; andre@0: _PR_SLEEPQ_LOCK(pq->thr->cpu); andre@0: _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); andre@0: _PR_SLEEPQ_UNLOCK(pq->thr->cpu); andre@0: andre@0: if (pq->thr->flags & _PR_SUSPENDING) { andre@0: /* andre@0: * set thread state to SUSPENDED; andre@0: * a Resume operation on the thread andre@0: * will move it to the runQ andre@0: */ andre@0: pq->thr->state = _PR_SUSPENDED; andre@0: _PR_MISCQ_LOCK(pq->thr->cpu); andre@0: _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); andre@0: _PR_MISCQ_UNLOCK(pq->thr->cpu); andre@0: } else { andre@0: pri = pq->thr->priority; andre@0: pq->thr->state = _PR_RUNNABLE; andre@0: andre@0: pq->thr->cpu = cpu; andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(pq->thr, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: if (_pr_md_idle_cpus > 1) andre@0: _PR_MD_WAKEUP_WAITER(thred); andre@0: } andre@0: } andre@0: _PR_THREAD_UNLOCK(thred); andre@0: } else { andre@0: if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) andre@0: _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; andre@0: } andre@0: } andre@0: if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { andre@0: if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) { andre@0: /* andre@0: * woken up by another thread; read all the data andre@0: * in the pipe to empty the pipe andre@0: */ andre@0: while ((rv = andre@0: read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) andre@0: == PIPE_BUF){ andre@0: } andre@0: PR_ASSERT((rv > 0) || andre@0: ((rv == -1) && (errno == EAGAIN))); andre@0: } andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; andre@0: #ifdef IRIX andre@0: if ((me->cpu->id == 0) && andre@0: (FD_ISSET(_pr_irix_primoridal_cpu_fd[0], rp))) { andre@0: if (_pr_irix_process_exit) { andre@0: /* andre@0: * process exit due to a call to PR_ProcessExit andre@0: */ andre@0: prctl(PR_SETEXITSIG, SIGKILL); andre@0: _exit(_pr_irix_process_exit_code); andre@0: } else { andre@0: while ((rv = read(_pr_irix_primoridal_cpu_fd[0], andre@0: _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) { andre@0: } andre@0: PR_ASSERT(rv > 0); andre@0: } andre@0: } andre@0: if (me->cpu->id == 0) { andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_irix_primoridal_cpu_fd[0]) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0]; andre@0: } andre@0: #endif andre@0: } andre@0: } else if (nfd < 0) { andre@0: if (errno == EBADF) { andre@0: FindBadFDs(); andre@0: } else { andre@0: PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", andre@0: errno)); andre@0: } andre@0: } else { andre@0: PR_ASSERT(nfd == 0); andre@0: /* andre@0: * compute the new value of _PR_IOQ_TIMEOUT andre@0: */ andre@0: q = _PR_IOQ(me->cpu).next; andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = -1; andre@0: _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; andre@0: while (q != &_PR_IOQ(me->cpu)) { andre@0: PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); andre@0: _PRUnixPollDesc *pds = pq->pds; andre@0: _PRUnixPollDesc *epds = pds + pq->npds; andre@0: PRInt32 pq_max_osfd = -1; andre@0: andre@0: q = q->next; andre@0: for (; pds < epds; pds++) { andre@0: if (pds->osfd > pq_max_osfd) { andre@0: pq_max_osfd = pds->osfd; andre@0: } andre@0: } andre@0: if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) andre@0: _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; andre@0: } andre@0: if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { andre@0: if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; andre@0: } andre@0: } andre@0: #endif /* _PR_USE_POLL */ andre@0: _PR_MD_IOQ_UNLOCK(); andre@0: } andre@0: andre@0: void _MD_Wakeup_CPUs() andre@0: { andre@0: PRInt32 rv, data; andre@0: andre@0: data = 0; andre@0: rv = write(_pr_md_pipefd[1], &data, 1); andre@0: andre@0: while ((rv < 0) && (errno == EAGAIN)) { andre@0: /* andre@0: * pipe full, read all data in pipe to empty it andre@0: */ andre@0: while ((rv = andre@0: read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) andre@0: == PIPE_BUF) { andre@0: } andre@0: PR_ASSERT((rv > 0) || andre@0: ((rv == -1) && (errno == EAGAIN))); andre@0: rv = write(_pr_md_pipefd[1], &data, 1); andre@0: } andre@0: } andre@0: andre@0: andre@0: void _MD_InitCPUS() andre@0: { andre@0: PRInt32 rv, flags; andre@0: PRThread *me = _MD_CURRENT_THREAD(); andre@0: andre@0: rv = pipe(_pr_md_pipefd); andre@0: PR_ASSERT(rv == 0); andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; andre@0: #ifndef _PR_USE_POLL andre@0: FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu)); andre@0: #endif andre@0: andre@0: flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0); andre@0: fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK); andre@0: flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0); andre@0: fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK); andre@0: } andre@0: andre@0: /* andre@0: ** Unix SIGALRM (clock) signal handler andre@0: */ andre@0: static void ClockInterruptHandler() andre@0: { andre@0: int olderrno; andre@0: PRUintn pri; andre@0: _PRCPU *cpu = _PR_MD_CURRENT_CPU(); andre@0: PRThread *me = _MD_CURRENT_THREAD(); andre@0: andre@0: #ifdef SOLARIS andre@0: if (!me || _PR_IS_NATIVE_THREAD(me)) { andre@0: _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK; andre@0: return; andre@0: } andre@0: #endif andre@0: andre@0: if (_PR_MD_GET_INTSOFF() != 0) { andre@0: cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; andre@0: return; andre@0: } andre@0: _PR_MD_SET_INTSOFF(1); andre@0: andre@0: olderrno = errno; andre@0: _PR_ClockInterrupt(); andre@0: errno = olderrno; andre@0: andre@0: /* andre@0: ** If the interrupt wants a resched or if some other thread at andre@0: ** the same priority needs the cpu, reschedule. andre@0: */ andre@0: pri = me->priority; andre@0: if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) { andre@0: #ifdef _PR_NO_PREEMPT andre@0: cpu->resched = PR_TRUE; andre@0: if (pr_interruptSwitchHook) { andre@0: (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg); andre@0: } andre@0: #else /* _PR_NO_PREEMPT */ andre@0: /* andre@0: ** Re-enable unix interrupts (so that we can use andre@0: ** setjmp/longjmp for context switching without having to andre@0: ** worry about the signal state) andre@0: */ andre@0: sigprocmask(SIG_SETMASK, &empty_set, 0); andre@0: PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch")); andre@0: andre@0: if(!(me->flags & _PR_IDLE_THREAD)) { andre@0: _PR_THREAD_LOCK(me); andre@0: me->state = _PR_RUNNABLE; andre@0: me->cpu = cpu; andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(me, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: _PR_THREAD_UNLOCK(me); andre@0: } else andre@0: me->state = _PR_RUNNABLE; andre@0: _MD_SWITCH_CONTEXT(me); andre@0: PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch")); andre@0: #endif /* _PR_NO_PREEMPT */ andre@0: } andre@0: /* andre@0: * Because this thread could be running on a different cpu after andre@0: * a context switch the current cpu should be accessed and the andre@0: * value of the 'cpu' variable should not be used. andre@0: */ andre@0: _PR_MD_SET_INTSOFF(0); andre@0: } andre@0: andre@0: /* andre@0: * On HP-UX 9, we have to use the sigvector() interface to restart andre@0: * interrupted system calls, because sigaction() does not have the andre@0: * SA_RESTART flag. andre@0: */ andre@0: andre@0: #ifdef HPUX9 andre@0: static void HPUX9_ClockInterruptHandler( andre@0: int sig, andre@0: int code, andre@0: struct sigcontext *scp) andre@0: { andre@0: ClockInterruptHandler(); andre@0: scp->sc_syscall_action = SIG_RESTART; andre@0: } andre@0: #endif /* HPUX9 */ andre@0: andre@0: /* # of milliseconds per clock tick that we will use */ andre@0: #define MSEC_PER_TICK 50 andre@0: andre@0: andre@0: void _MD_StartInterrupts() andre@0: { andre@0: char *eval; andre@0: andre@0: if ((eval = getenv("NSPR_NOCLOCK")) != NULL) { andre@0: if (atoi(eval) == 0) andre@0: _nspr_noclock = 0; andre@0: else andre@0: _nspr_noclock = 1; andre@0: } andre@0: andre@0: #ifndef _PR_NO_CLOCK_TIMER andre@0: if (!_nspr_noclock) { andre@0: _MD_EnableClockInterrupts(); andre@0: } andre@0: #endif andre@0: } andre@0: andre@0: void _MD_StopInterrupts() andre@0: { andre@0: sigprocmask(SIG_BLOCK, &timer_set, 0); andre@0: } andre@0: andre@0: void _MD_EnableClockInterrupts() andre@0: { andre@0: struct itimerval itval; andre@0: extern PRUintn _pr_numCPU; andre@0: #ifdef HPUX9 andre@0: struct sigvec vec; andre@0: andre@0: vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler; andre@0: vec.sv_mask = 0; andre@0: vec.sv_flags = 0; andre@0: sigvector(SIGALRM, &vec, 0); andre@0: #else andre@0: struct sigaction vtact; andre@0: andre@0: vtact.sa_handler = (void (*)()) ClockInterruptHandler; andre@0: sigemptyset(&vtact.sa_mask); andre@0: vtact.sa_flags = SA_RESTART; andre@0: sigaction(SIGALRM, &vtact, 0); andre@0: #endif /* HPUX9 */ andre@0: andre@0: PR_ASSERT(_pr_numCPU == 1); andre@0: itval.it_interval.tv_sec = 0; andre@0: itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC; andre@0: itval.it_value = itval.it_interval; andre@0: setitimer(ITIMER_REAL, &itval, 0); andre@0: } andre@0: andre@0: void _MD_DisableClockInterrupts() andre@0: { andre@0: struct itimerval itval; andre@0: extern PRUintn _pr_numCPU; andre@0: andre@0: PR_ASSERT(_pr_numCPU == 1); andre@0: itval.it_interval.tv_sec = 0; andre@0: itval.it_interval.tv_usec = 0; andre@0: itval.it_value = itval.it_interval; andre@0: setitimer(ITIMER_REAL, &itval, 0); andre@0: } andre@0: andre@0: void _MD_BlockClockInterrupts() andre@0: { andre@0: sigprocmask(SIG_BLOCK, &timer_set, 0); andre@0: } andre@0: andre@0: void _MD_UnblockClockInterrupts() andre@0: { andre@0: sigprocmask(SIG_UNBLOCK, &timer_set, 0); andre@0: } andre@0: andre@0: void _MD_MakeNonblock(PRFileDesc *fd) andre@0: { andre@0: PRInt32 osfd = fd->secret->md.osfd; andre@0: int flags; andre@0: andre@0: if (osfd <= 2) { andre@0: /* Don't mess around with stdin, stdout or stderr */ andre@0: return; andre@0: } andre@0: flags = fcntl(osfd, F_GETFL, 0); andre@0: andre@0: /* andre@0: * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible. andre@0: * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O), andre@0: * otherwise connect() still blocks and can be interrupted by SIGALRM. andre@0: */ andre@0: andre@0: fcntl(osfd, F_SETFL, flags | O_NONBLOCK); andre@0: } andre@0: andre@0: PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode) andre@0: { andre@0: PRInt32 osflags; andre@0: PRInt32 rv, err; andre@0: andre@0: if (flags & PR_RDWR) { andre@0: osflags = O_RDWR; andre@0: } else if (flags & PR_WRONLY) { andre@0: osflags = O_WRONLY; andre@0: } else { andre@0: osflags = O_RDONLY; andre@0: } andre@0: andre@0: if (flags & PR_EXCL) andre@0: osflags |= O_EXCL; andre@0: if (flags & PR_APPEND) andre@0: osflags |= O_APPEND; andre@0: if (flags & PR_TRUNCATE) andre@0: osflags |= O_TRUNC; andre@0: if (flags & PR_SYNC) { andre@0: #if defined(O_SYNC) andre@0: osflags |= O_SYNC; andre@0: #elif defined(O_FSYNC) andre@0: osflags |= O_FSYNC; andre@0: #else andre@0: #error "Neither O_SYNC nor O_FSYNC is defined on this platform" andre@0: #endif andre@0: } andre@0: andre@0: /* andre@0: ** On creations we hold the 'create' lock in order to enforce andre@0: ** the semantics of PR_Rename. (see the latter for more details) andre@0: */ andre@0: if (flags & PR_CREATE_FILE) andre@0: { andre@0: osflags |= O_CREAT; andre@0: if (NULL !=_pr_rename_lock) andre@0: PR_Lock(_pr_rename_lock); andre@0: } andre@0: andre@0: #if defined(ANDROID) andre@0: osflags |= O_LARGEFILE; andre@0: #endif andre@0: andre@0: rv = _md_iovector._open64(name, osflags, mode); andre@0: andre@0: if (rv < 0) { andre@0: err = _MD_ERRNO(); andre@0: _PR_MD_MAP_OPEN_ERROR(err); andre@0: } andre@0: andre@0: if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) andre@0: PR_Unlock(_pr_rename_lock); andre@0: return rv; andre@0: } andre@0: andre@0: PRIntervalTime intr_timeout_ticks; andre@0: andre@0: #if defined(SOLARIS) || defined(IRIX) andre@0: static void sigsegvhandler() { andre@0: fprintf(stderr,"Received SIGSEGV\n"); andre@0: fflush(stderr); andre@0: pause(); andre@0: } andre@0: andre@0: static void sigaborthandler() { andre@0: fprintf(stderr,"Received SIGABRT\n"); andre@0: fflush(stderr); andre@0: pause(); andre@0: } andre@0: andre@0: static void sigbushandler() { andre@0: fprintf(stderr,"Received SIGBUS\n"); andre@0: fflush(stderr); andre@0: pause(); andre@0: } andre@0: #endif /* SOLARIS, IRIX */ andre@0: andre@0: #endif /* !defined(_PR_PTHREADS) */ andre@0: andre@0: void _MD_query_fd_inheritable(PRFileDesc *fd) andre@0: { andre@0: int flags; andre@0: andre@0: PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); andre@0: flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); andre@0: PR_ASSERT(-1 != flags); andre@0: fd->secret->inheritable = (flags & FD_CLOEXEC) ? andre@0: _PR_TRI_FALSE : _PR_TRI_TRUE; andre@0: } andre@0: andre@0: PROffset32 _MD_lseek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) andre@0: { andre@0: PROffset32 rv, where; andre@0: andre@0: switch (whence) { andre@0: case PR_SEEK_SET: andre@0: where = SEEK_SET; andre@0: break; andre@0: case PR_SEEK_CUR: andre@0: where = SEEK_CUR; andre@0: break; andre@0: case PR_SEEK_END: andre@0: where = SEEK_END; andre@0: break; andre@0: default: andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: rv = -1; andre@0: goto done; andre@0: } andre@0: rv = lseek(fd->secret->md.osfd,offset,where); andre@0: if (rv == -1) andre@0: { andre@0: PRInt32 syserr = _MD_ERRNO(); andre@0: _PR_MD_MAP_LSEEK_ERROR(syserr); andre@0: } andre@0: done: andre@0: return(rv); andre@0: } andre@0: andre@0: PROffset64 _MD_lseek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) andre@0: { andre@0: PRInt32 where; andre@0: PROffset64 rv; andre@0: andre@0: switch (whence) andre@0: { andre@0: case PR_SEEK_SET: andre@0: where = SEEK_SET; andre@0: break; andre@0: case PR_SEEK_CUR: andre@0: where = SEEK_CUR; andre@0: break; andre@0: case PR_SEEK_END: andre@0: where = SEEK_END; andre@0: break; andre@0: default: andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: rv = minus_one; andre@0: goto done; andre@0: } andre@0: rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where); andre@0: if (LL_EQ(rv, minus_one)) andre@0: { andre@0: PRInt32 syserr = _MD_ERRNO(); andre@0: _PR_MD_MAP_LSEEK_ERROR(syserr); andre@0: } andre@0: done: andre@0: return rv; andre@0: } /* _MD_lseek64 */ andre@0: andre@0: /* andre@0: ** _MD_set_fileinfo_times -- andre@0: ** Set the modifyTime and creationTime of the PRFileInfo andre@0: ** structure using the values in struct stat. andre@0: ** andre@0: ** _MD_set_fileinfo64_times -- andre@0: ** Set the modifyTime and creationTime of the PRFileInfo64 andre@0: ** structure using the values in _MDStat64. andre@0: */ andre@0: andre@0: #if defined(_PR_STAT_HAS_ST_ATIM) andre@0: /* andre@0: ** struct stat has st_atim, st_mtim, and st_ctim fields of andre@0: ** type timestruc_t. andre@0: */ andre@0: static void _MD_set_fileinfo_times( andre@0: const struct stat *sb, andre@0: PRFileInfo *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtim.tv_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctim.tv_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctim.tv_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: andre@0: static void _MD_set_fileinfo64_times( andre@0: const _MDStat64 *sb, andre@0: PRFileInfo64 *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtim.tv_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctim.tv_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctim.tv_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: #elif defined(_PR_STAT_HAS_ST_ATIM_UNION) andre@0: /* andre@0: ** The st_atim, st_mtim, and st_ctim fields in struct stat are andre@0: ** unions with a st__tim union member of type timestruc_t. andre@0: */ andre@0: static void _MD_set_fileinfo_times( andre@0: const struct stat *sb, andre@0: PRFileInfo *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: andre@0: static void _MD_set_fileinfo64_times( andre@0: const _MDStat64 *sb, andre@0: PRFileInfo64 *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: #elif defined(_PR_STAT_HAS_ST_ATIMESPEC) andre@0: /* andre@0: ** struct stat has st_atimespec, st_mtimespec, and st_ctimespec andre@0: ** fields of type struct timespec. andre@0: */ andre@0: #if defined(_PR_TIMESPEC_HAS_TS_SEC) andre@0: static void _MD_set_fileinfo_times( andre@0: const struct stat *sb, andre@0: PRFileInfo *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: andre@0: static void _MD_set_fileinfo64_times( andre@0: const _MDStat64 *sb, andre@0: PRFileInfo64 *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: #else /* _PR_TIMESPEC_HAS_TS_SEC */ andre@0: /* andre@0: ** The POSIX timespec structure has tv_sec and tv_nsec. andre@0: */ andre@0: static void _MD_set_fileinfo_times( andre@0: const struct stat *sb, andre@0: PRFileInfo *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: andre@0: static void _MD_set_fileinfo64_times( andre@0: const _MDStat64 *sb, andre@0: PRFileInfo64 *info) andre@0: { andre@0: PRInt64 us, s2us; andre@0: andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); andre@0: LL_MUL(info->modifyTime, info->modifyTime, s2us); andre@0: LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); andre@0: LL_ADD(info->modifyTime, info->modifyTime, us); andre@0: LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); andre@0: LL_MUL(info->creationTime, info->creationTime, s2us); andre@0: LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); andre@0: LL_ADD(info->creationTime, info->creationTime, us); andre@0: } andre@0: #endif /* _PR_TIMESPEC_HAS_TS_SEC */ andre@0: #elif defined(_PR_STAT_HAS_ONLY_ST_ATIME) andre@0: /* andre@0: ** struct stat only has st_atime, st_mtime, and st_ctime fields andre@0: ** of type time_t. andre@0: */ andre@0: static void _MD_set_fileinfo_times( andre@0: const struct stat *sb, andre@0: PRFileInfo *info) andre@0: { andre@0: PRInt64 s, s2us; andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(s, sb->st_mtime); andre@0: LL_MUL(s, s, s2us); andre@0: info->modifyTime = s; andre@0: LL_I2L(s, sb->st_ctime); andre@0: LL_MUL(s, s, s2us); andre@0: info->creationTime = s; andre@0: } andre@0: andre@0: static void _MD_set_fileinfo64_times( andre@0: const _MDStat64 *sb, andre@0: PRFileInfo64 *info) andre@0: { andre@0: PRInt64 s, s2us; andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(s, sb->st_mtime); andre@0: LL_MUL(s, s, s2us); andre@0: info->modifyTime = s; andre@0: LL_I2L(s, sb->st_ctime); andre@0: LL_MUL(s, s, s2us); andre@0: info->creationTime = s; andre@0: } andre@0: #else andre@0: #error "I don't know yet" andre@0: #endif andre@0: andre@0: static int _MD_convert_stat_to_fileinfo( andre@0: const struct stat *sb, andre@0: PRFileInfo *info) andre@0: { andre@0: if (S_IFREG & sb->st_mode) andre@0: info->type = PR_FILE_FILE; andre@0: else if (S_IFDIR & sb->st_mode) andre@0: info->type = PR_FILE_DIRECTORY; andre@0: else andre@0: info->type = PR_FILE_OTHER; andre@0: andre@0: #if defined(_PR_HAVE_LARGE_OFF_T) andre@0: if (0x7fffffffL < sb->st_size) andre@0: { andre@0: PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); andre@0: return -1; andre@0: } andre@0: #endif /* defined(_PR_HAVE_LARGE_OFF_T) */ andre@0: info->size = sb->st_size; andre@0: andre@0: _MD_set_fileinfo_times(sb, info); andre@0: return 0; andre@0: } /* _MD_convert_stat_to_fileinfo */ andre@0: andre@0: static int _MD_convert_stat64_to_fileinfo64( andre@0: const _MDStat64 *sb, andre@0: PRFileInfo64 *info) andre@0: { andre@0: if (S_IFREG & sb->st_mode) andre@0: info->type = PR_FILE_FILE; andre@0: else if (S_IFDIR & sb->st_mode) andre@0: info->type = PR_FILE_DIRECTORY; andre@0: else andre@0: info->type = PR_FILE_OTHER; andre@0: andre@0: LL_I2L(info->size, sb->st_size); andre@0: andre@0: _MD_set_fileinfo64_times(sb, info); andre@0: return 0; andre@0: } /* _MD_convert_stat64_to_fileinfo64 */ andre@0: andre@0: PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info) andre@0: { andre@0: PRInt32 rv; andre@0: struct stat sb; andre@0: andre@0: rv = stat(fn, &sb); andre@0: if (rv < 0) andre@0: _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); andre@0: else if (NULL != info) andre@0: rv = _MD_convert_stat_to_fileinfo(&sb, info); andre@0: return rv; andre@0: } andre@0: andre@0: PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info) andre@0: { andre@0: _MDStat64 sb; andre@0: PRInt32 rv = _md_iovector._stat64(fn, &sb); andre@0: if (rv < 0) andre@0: _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); andre@0: else if (NULL != info) andre@0: rv = _MD_convert_stat64_to_fileinfo64(&sb, info); andre@0: return rv; andre@0: } andre@0: andre@0: PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info) andre@0: { andre@0: struct stat sb; andre@0: PRInt32 rv = fstat(fd->secret->md.osfd, &sb); andre@0: if (rv < 0) andre@0: _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); andre@0: else if (NULL != info) andre@0: rv = _MD_convert_stat_to_fileinfo(&sb, info); andre@0: return rv; andre@0: } andre@0: andre@0: PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info) andre@0: { andre@0: _MDStat64 sb; andre@0: PRInt32 rv = _md_iovector._fstat64(fd->secret->md.osfd, &sb); andre@0: if (rv < 0) andre@0: _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); andre@0: else if (NULL != info) andre@0: rv = _MD_convert_stat64_to_fileinfo64(&sb, info); andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: * _md_iovector._open64 must be initialized to 'open' so that _PR_InitLog can andre@0: * open the log file during NSPR initialization, before _md_iovector is andre@0: * initialized by _PR_MD_FINAL_INIT. This means the log file cannot be a andre@0: * large file on some platforms. andre@0: */ andre@0: #ifdef SYMBIAN andre@0: struct _MD_IOVector _md_iovector; /* Will crash if NSPR_LOG_FILE is set. */ andre@0: #else andre@0: struct _MD_IOVector _md_iovector = { open }; andre@0: #endif andre@0: andre@0: /* andre@0: ** These implementations are to emulate large file routines on systems that andre@0: ** don't have them. Their goal is to check in case overflow occurs. Otherwise andre@0: ** they will just operate as normal using 32-bit file routines. andre@0: ** andre@0: ** The checking might be pre- or post-op, depending on the semantics. andre@0: */ andre@0: andre@0: #if defined(SOLARIS2_5) andre@0: andre@0: static PRIntn _MD_solaris25_fstat64(PRIntn osfd, _MDStat64 *buf) andre@0: { andre@0: PRInt32 rv; andre@0: struct stat sb; andre@0: andre@0: rv = fstat(osfd, &sb); andre@0: if (rv >= 0) andre@0: { andre@0: /* andre@0: ** I'm only copying the fields that are immediately needed. andre@0: ** If somebody else calls this function, some of the fields andre@0: ** may not be defined. andre@0: */ andre@0: (void)memset(buf, 0, sizeof(_MDStat64)); andre@0: buf->st_mode = sb.st_mode; andre@0: buf->st_ctim = sb.st_ctim; andre@0: buf->st_mtim = sb.st_mtim; andre@0: buf->st_size = sb.st_size; andre@0: } andre@0: return rv; andre@0: } /* _MD_solaris25_fstat64 */ andre@0: andre@0: static PRIntn _MD_solaris25_stat64(const char *fn, _MDStat64 *buf) andre@0: { andre@0: PRInt32 rv; andre@0: struct stat sb; andre@0: andre@0: rv = stat(fn, &sb); andre@0: if (rv >= 0) andre@0: { andre@0: /* andre@0: ** I'm only copying the fields that are immediately needed. andre@0: ** If somebody else calls this function, some of the fields andre@0: ** may not be defined. andre@0: */ andre@0: (void)memset(buf, 0, sizeof(_MDStat64)); andre@0: buf->st_mode = sb.st_mode; andre@0: buf->st_ctim = sb.st_ctim; andre@0: buf->st_mtim = sb.st_mtim; andre@0: buf->st_size = sb.st_size; andre@0: } andre@0: return rv; andre@0: } /* _MD_solaris25_stat64 */ andre@0: #endif /* defined(SOLARIS2_5) */ andre@0: andre@0: #if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) andre@0: andre@0: static PROffset64 _MD_Unix_lseek64(PRIntn osfd, PROffset64 offset, PRIntn whence) andre@0: { andre@0: PRUint64 maxoff; andre@0: PROffset64 rv = minus_one; andre@0: LL_I2L(maxoff, 0x7fffffff); andre@0: if (LL_CMP(offset, <=, maxoff)) andre@0: { andre@0: off_t off; andre@0: LL_L2I(off, offset); andre@0: LL_I2L(rv, lseek(osfd, off, whence)); andre@0: } andre@0: else errno = EFBIG; /* we can't go there */ andre@0: return rv; andre@0: } /* _MD_Unix_lseek64 */ andre@0: andre@0: static void* _MD_Unix_mmap64( andre@0: void *addr, PRSize len, PRIntn prot, PRIntn flags, andre@0: PRIntn fildes, PRInt64 offset) andre@0: { andre@0: PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); andre@0: return NULL; andre@0: } /* _MD_Unix_mmap64 */ andre@0: #endif /* defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) */ andre@0: andre@0: /* Android doesn't have mmap64. */ andre@0: #if defined(ANDROID) andre@0: extern void *__mmap2(void *, size_t, int, int, int, size_t); andre@0: andre@0: #define ANDROID_PAGE_SIZE 4096 andre@0: andre@0: static void * andre@0: mmap64(void *addr, size_t len, int prot, int flags, int fd, loff_t offset) andre@0: { andre@0: if (offset & (ANDROID_PAGE_SIZE - 1)) { andre@0: errno = EINVAL; andre@0: return MAP_FAILED; andre@0: } andre@0: return __mmap2(addr, len, prot, flags, fd, offset / ANDROID_PAGE_SIZE); andre@0: } andre@0: #endif andre@0: andre@0: #if defined(OSF1) && defined(__GNUC__) andre@0: andre@0: /* andre@0: * On OSF1 V5.0A, defines stat and fstat as andre@0: * macros when compiled under gcc, so it is rather tricky to andre@0: * take the addresses of the real functions the macros expend andre@0: * to. A simple solution is to define forwarder functions andre@0: * and take the addresses of the forwarder functions instead. andre@0: */ andre@0: andre@0: static int stat_forwarder(const char *path, struct stat *buffer) andre@0: { andre@0: return stat(path, buffer); andre@0: } andre@0: andre@0: static int fstat_forwarder(int filedes, struct stat *buffer) andre@0: { andre@0: return fstat(filedes, buffer); andre@0: } andre@0: andre@0: #endif andre@0: andre@0: static void _PR_InitIOV(void) andre@0: { andre@0: #if defined(SOLARIS2_5) andre@0: PRLibrary *lib; andre@0: void *open64_func; andre@0: andre@0: open64_func = PR_FindSymbolAndLibrary("open64", &lib); andre@0: if (NULL != open64_func) andre@0: { andre@0: PR_ASSERT(NULL != lib); andre@0: _md_iovector._open64 = (_MD_Open64)open64_func; andre@0: _md_iovector._mmap64 = (_MD_Mmap64)PR_FindSymbol(lib, "mmap64"); andre@0: _md_iovector._fstat64 = (_MD_Fstat64)PR_FindSymbol(lib, "fstat64"); andre@0: _md_iovector._stat64 = (_MD_Stat64)PR_FindSymbol(lib, "stat64"); andre@0: _md_iovector._lseek64 = (_MD_Lseek64)PR_FindSymbol(lib, "lseek64"); andre@0: (void)PR_UnloadLibrary(lib); andre@0: } andre@0: else andre@0: { andre@0: _md_iovector._open64 = open; andre@0: _md_iovector._mmap64 = _MD_Unix_mmap64; andre@0: _md_iovector._fstat64 = _MD_solaris25_fstat64; andre@0: _md_iovector._stat64 = _MD_solaris25_stat64; andre@0: _md_iovector._lseek64 = _MD_Unix_lseek64; andre@0: } andre@0: #elif defined(_PR_NO_LARGE_FILES) andre@0: _md_iovector._open64 = open; andre@0: _md_iovector._mmap64 = _MD_Unix_mmap64; andre@0: _md_iovector._fstat64 = fstat; andre@0: _md_iovector._stat64 = stat; andre@0: _md_iovector._lseek64 = _MD_Unix_lseek64; andre@0: #elif defined(_PR_HAVE_OFF64_T) andre@0: #if defined(IRIX5_3) || defined(ANDROID) andre@0: /* andre@0: * Android doesn't have open64. We pass the O_LARGEFILE flag to open andre@0: * in _MD_open. andre@0: */ andre@0: _md_iovector._open64 = open; andre@0: #else andre@0: _md_iovector._open64 = open64; andre@0: #endif andre@0: _md_iovector._mmap64 = mmap64; andre@0: _md_iovector._fstat64 = fstat64; andre@0: _md_iovector._stat64 = stat64; andre@0: _md_iovector._lseek64 = lseek64; andre@0: #elif defined(_PR_HAVE_LARGE_OFF_T) andre@0: _md_iovector._open64 = open; andre@0: _md_iovector._mmap64 = mmap; andre@0: #if defined(OSF1) && defined(__GNUC__) andre@0: _md_iovector._fstat64 = fstat_forwarder; andre@0: _md_iovector._stat64 = stat_forwarder; andre@0: #else andre@0: _md_iovector._fstat64 = fstat; andre@0: _md_iovector._stat64 = stat; andre@0: #endif andre@0: _md_iovector._lseek64 = lseek; andre@0: #else andre@0: #error "I don't know yet" andre@0: #endif andre@0: LL_I2L(minus_one, -1); andre@0: } /* _PR_InitIOV */ andre@0: andre@0: void _PR_UnixInit(void) andre@0: { andre@0: struct sigaction sigact; andre@0: int rv; andre@0: andre@0: sigemptyset(&timer_set); andre@0: andre@0: #if !defined(_PR_PTHREADS) andre@0: andre@0: sigaddset(&timer_set, SIGALRM); andre@0: sigemptyset(&empty_set); andre@0: intr_timeout_ticks = andre@0: PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS); andre@0: andre@0: #if defined(SOLARIS) || defined(IRIX) andre@0: andre@0: if (getenv("NSPR_SIGSEGV_HANDLE")) { andre@0: sigact.sa_handler = sigsegvhandler; andre@0: sigact.sa_flags = 0; andre@0: sigact.sa_mask = timer_set; andre@0: sigaction(SIGSEGV, &sigact, 0); andre@0: } andre@0: andre@0: if (getenv("NSPR_SIGABRT_HANDLE")) { andre@0: sigact.sa_handler = sigaborthandler; andre@0: sigact.sa_flags = 0; andre@0: sigact.sa_mask = timer_set; andre@0: sigaction(SIGABRT, &sigact, 0); andre@0: } andre@0: andre@0: if (getenv("NSPR_SIGBUS_HANDLE")) { andre@0: sigact.sa_handler = sigbushandler; andre@0: sigact.sa_flags = 0; andre@0: sigact.sa_mask = timer_set; andre@0: sigaction(SIGBUS, &sigact, 0); andre@0: } andre@0: andre@0: #endif andre@0: #endif /* !defined(_PR_PTHREADS) */ andre@0: andre@0: /* andre@0: * Under HP-UX DCE threads, sigaction() installs a per-thread andre@0: * handler, so we use sigvector() to install a process-wide andre@0: * handler. andre@0: */ andre@0: #if defined(HPUX) && defined(_PR_DCETHREADS) andre@0: { andre@0: struct sigvec vec; andre@0: andre@0: vec.sv_handler = SIG_IGN; andre@0: vec.sv_mask = 0; andre@0: vec.sv_flags = 0; andre@0: rv = sigvector(SIGPIPE, &vec, NULL); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: #else andre@0: sigact.sa_handler = SIG_IGN; andre@0: sigemptyset(&sigact.sa_mask); andre@0: sigact.sa_flags = 0; andre@0: rv = sigaction(SIGPIPE, &sigact, 0); andre@0: PR_ASSERT(0 == rv); andre@0: #endif /* HPUX && _PR_DCETHREADS */ andre@0: andre@0: _pr_rename_lock = PR_NewLock(); andre@0: PR_ASSERT(NULL != _pr_rename_lock); andre@0: _pr_Xfe_mon = PR_NewMonitor(); andre@0: PR_ASSERT(NULL != _pr_Xfe_mon); andre@0: andre@0: _PR_InitIOV(); /* one last hack */ andre@0: } andre@0: andre@0: void _PR_UnixCleanup(void) andre@0: { andre@0: if (_pr_rename_lock) { andre@0: PR_DestroyLock(_pr_rename_lock); andre@0: _pr_rename_lock = NULL; andre@0: } andre@0: if (_pr_Xfe_mon) { andre@0: PR_DestroyMonitor(_pr_Xfe_mon); andre@0: _pr_Xfe_mon = NULL; andre@0: } andre@0: } andre@0: andre@0: #if !defined(_PR_PTHREADS) andre@0: andre@0: /* andre@0: * Variables used by the GC code, initialized in _MD_InitSegs(). andre@0: */ andre@0: static PRInt32 _pr_zero_fd = -1; andre@0: static PRLock *_pr_md_lock = NULL; andre@0: andre@0: /* andre@0: * _MD_InitSegs -- andre@0: * andre@0: * This is Unix's version of _PR_MD_INIT_SEGS(), which is andre@0: * called by _PR_InitSegs(), which in turn is called by andre@0: * PR_Init(). andre@0: */ andre@0: void _MD_InitSegs(void) andre@0: { andre@0: #ifdef DEBUG andre@0: /* andre@0: ** Disable using mmap(2) if NSPR_NO_MMAP is set andre@0: */ andre@0: if (getenv("NSPR_NO_MMAP")) { andre@0: _pr_zero_fd = -2; andre@0: return; andre@0: } andre@0: #endif andre@0: _pr_zero_fd = open("/dev/zero",O_RDWR , 0); andre@0: /* Prevent the fd from being inherited by child processes */ andre@0: fcntl(_pr_zero_fd, F_SETFD, FD_CLOEXEC); andre@0: _pr_md_lock = PR_NewLock(); andre@0: } andre@0: andre@0: PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) andre@0: { andre@0: static char *lastaddr = (char*) _PR_STACK_VMBASE; andre@0: PRStatus retval = PR_SUCCESS; andre@0: int prot; andre@0: void *rv; andre@0: andre@0: PR_ASSERT(seg != 0); andre@0: PR_ASSERT(size != 0); andre@0: andre@0: PR_Lock(_pr_md_lock); andre@0: if (_pr_zero_fd < 0) { andre@0: from_heap: andre@0: seg->vaddr = PR_MALLOC(size); andre@0: if (!seg->vaddr) { andre@0: retval = PR_FAILURE; andre@0: } andre@0: else { andre@0: seg->size = size; andre@0: } andre@0: goto exit; andre@0: } andre@0: andre@0: prot = PROT_READ|PROT_WRITE; andre@0: /* andre@0: * On Alpha Linux, the user-level thread stack needs andre@0: * to be made executable because longjmp/signal seem andre@0: * to put machine instructions on the stack. andre@0: */ andre@0: #if defined(LINUX) && defined(__alpha) andre@0: prot |= PROT_EXEC; andre@0: #endif andre@0: rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot, andre@0: _MD_MMAP_FLAGS, andre@0: _pr_zero_fd, 0); andre@0: if (rv == (void*)-1) { andre@0: goto from_heap; andre@0: } andre@0: lastaddr += size; andre@0: seg->vaddr = rv; andre@0: seg->size = size; andre@0: seg->flags = _PR_SEG_VM; andre@0: andre@0: exit: andre@0: PR_Unlock(_pr_md_lock); andre@0: return retval; andre@0: } andre@0: andre@0: void _MD_FreeSegment(PRSegment *seg) andre@0: { andre@0: if (seg->flags & _PR_SEG_VM) andre@0: (void) munmap(seg->vaddr, seg->size); andre@0: else andre@0: PR_DELETE(seg->vaddr); andre@0: } andre@0: andre@0: #endif /* _PR_PTHREADS */ andre@0: andre@0: /* andre@0: *----------------------------------------------------------------------- andre@0: * andre@0: * PR_Now -- andre@0: * andre@0: * Returns the current time in microseconds since the epoch. andre@0: * The epoch is midnight January 1, 1970 GMT. andre@0: * The implementation is machine dependent. This is the Unix andre@0: * implementation. andre@0: * Cf. time_t time(time_t *tp) andre@0: * andre@0: *----------------------------------------------------------------------- andre@0: */ andre@0: andre@0: PR_IMPLEMENT(PRTime) andre@0: PR_Now(void) andre@0: { andre@0: struct timeval tv; andre@0: PRInt64 s, us, s2us; andre@0: andre@0: GETTIMEOFDAY(&tv); andre@0: LL_I2L(s2us, PR_USEC_PER_SEC); andre@0: LL_I2L(s, tv.tv_sec); andre@0: LL_I2L(us, tv.tv_usec); andre@0: LL_MUL(s, s, s2us); andre@0: LL_ADD(s, s, us); andre@0: return s; andre@0: } andre@0: andre@0: #if defined(_MD_INTERVAL_USE_GTOD) andre@0: /* andre@0: * This version of interval times is based on the time of day andre@0: * capability offered by the system. This isn't valid for two reasons: andre@0: * 1) The time of day is neither linear nor montonically increasing andre@0: * 2) The units here are milliseconds. That's not appropriate for our use. andre@0: */ andre@0: PRIntervalTime _PR_UNIX_GetInterval() andre@0: { andre@0: struct timeval time; andre@0: PRIntervalTime ticks; andre@0: andre@0: (void)GETTIMEOFDAY(&time); /* fallicy of course */ andre@0: ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds */ andre@0: ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */ andre@0: return ticks; andre@0: } /* _PR_UNIX_GetInterval */ andre@0: andre@0: PRIntervalTime _PR_UNIX_TicksPerSecond() andre@0: { andre@0: return 1000; /* this needs some work :) */ andre@0: } andre@0: #endif andre@0: andre@0: #if defined(HAVE_CLOCK_MONOTONIC) andre@0: PRIntervalTime _PR_UNIX_GetInterval2() andre@0: { andre@0: struct timespec time; andre@0: PRIntervalTime ticks; andre@0: andre@0: if (clock_gettime(CLOCK_MONOTONIC, &time) != 0) { andre@0: fprintf(stderr, "clock_gettime failed: %d\n", errno); andre@0: abort(); andre@0: } andre@0: andre@0: ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; andre@0: ticks += (PRUint32)time.tv_nsec / PR_NSEC_PER_MSEC; andre@0: return ticks; andre@0: } andre@0: andre@0: PRIntervalTime _PR_UNIX_TicksPerSecond2() andre@0: { andre@0: return 1000; andre@0: } andre@0: #endif andre@0: andre@0: #if !defined(_PR_PTHREADS) andre@0: /* andre@0: * Wait for I/O on multiple descriptors. andre@0: * andre@0: * Return 0 if timed out, return -1 if interrupted, andre@0: * else return the number of ready descriptors. andre@0: */ andre@0: PRInt32 _PR_WaitForMultipleFDs( andre@0: _PRUnixPollDesc *unixpds, andre@0: PRInt32 pdcnt, andre@0: PRIntervalTime timeout) andre@0: { andre@0: PRPollQueue pq; andre@0: PRIntn is; andre@0: PRInt32 rv; andre@0: _PRCPU *io_cpu; andre@0: _PRUnixPollDesc *unixpd, *eunixpd; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); andre@0: andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: return -1; andre@0: } andre@0: andre@0: pq.pds = unixpds; andre@0: pq.npds = pdcnt; andre@0: andre@0: _PR_INTSOFF(is); andre@0: _PR_MD_IOQ_LOCK(); andre@0: _PR_THREAD_LOCK(me); andre@0: andre@0: pq.thr = me; andre@0: io_cpu = me->cpu; andre@0: pq.on_ioq = PR_TRUE; andre@0: pq.timeout = timeout; andre@0: _PR_ADD_TO_IOQ(pq, me->cpu); andre@0: andre@0: #if !defined(_PR_USE_POLL) andre@0: eunixpd = unixpds + pdcnt; andre@0: for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { andre@0: PRInt32 osfd = unixpd->osfd; andre@0: if (unixpd->in_flags & _PR_UNIX_POLL_READ) { andre@0: FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); andre@0: _PR_FD_READ_CNT(me->cpu)[osfd]++; andre@0: } andre@0: if (unixpd->in_flags & _PR_UNIX_POLL_WRITE) { andre@0: FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); andre@0: (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; andre@0: } andre@0: if (unixpd->in_flags & _PR_UNIX_POLL_EXCEPT) { andre@0: FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); andre@0: (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; andre@0: } andre@0: if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) { andre@0: _PR_IOQ_MAX_OSFD(me->cpu) = osfd; andre@0: } andre@0: } andre@0: #endif /* !defined(_PR_USE_POLL) */ andre@0: andre@0: if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) { andre@0: _PR_IOQ_TIMEOUT(me->cpu) = timeout; andre@0: } andre@0: andre@0: _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt; andre@0: andre@0: _PR_SLEEPQ_LOCK(me->cpu); andre@0: _PR_ADD_SLEEPQ(me, timeout); andre@0: me->state = _PR_IO_WAIT; andre@0: me->io_pending = PR_TRUE; andre@0: me->io_suspended = PR_FALSE; andre@0: _PR_SLEEPQ_UNLOCK(me->cpu); andre@0: _PR_THREAD_UNLOCK(me); andre@0: _PR_MD_IOQ_UNLOCK(); andre@0: andre@0: _PR_MD_WAIT(me, timeout); andre@0: andre@0: me->io_pending = PR_FALSE; andre@0: me->io_suspended = PR_FALSE; andre@0: andre@0: /* andre@0: * This thread should run on the same cpu on which it was blocked; when andre@0: * the IO request times out the fd sets and fd counts for the andre@0: * cpu are updated below. andre@0: */ andre@0: PR_ASSERT(me->cpu == io_cpu); andre@0: andre@0: /* andre@0: ** If we timed out the pollq might still be on the ioq. Remove it andre@0: ** before continuing. andre@0: */ andre@0: if (pq.on_ioq) { andre@0: _PR_MD_IOQ_LOCK(); andre@0: /* andre@0: * Need to check pq.on_ioq again andre@0: */ andre@0: if (pq.on_ioq) { andre@0: PR_REMOVE_LINK(&pq.links); andre@0: #ifndef _PR_USE_POLL andre@0: eunixpd = unixpds + pdcnt; andre@0: for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { andre@0: PRInt32 osfd = unixpd->osfd; andre@0: PRInt16 in_flags = unixpd->in_flags; andre@0: andre@0: if (in_flags & _PR_UNIX_POLL_READ) { andre@0: if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); andre@0: } andre@0: if (in_flags & _PR_UNIX_POLL_WRITE) { andre@0: if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); andre@0: } andre@0: if (in_flags & _PR_UNIX_POLL_EXCEPT) { andre@0: if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) andre@0: FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); andre@0: } andre@0: } andre@0: #endif /* _PR_USE_POLL */ andre@0: PR_ASSERT(pq.npds == pdcnt); andre@0: _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt; andre@0: PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); andre@0: } andre@0: _PR_MD_IOQ_UNLOCK(); andre@0: } andre@0: /* XXX Should we use _PR_FAST_INTSON or _PR_INTSON? */ andre@0: if (1 == pdcnt) { andre@0: _PR_FAST_INTSON(is); andre@0: } else { andre@0: _PR_INTSON(is); andre@0: } andre@0: andre@0: if (_PR_PENDING_INTERRUPT(me)) { andre@0: me->flags &= ~_PR_INTERRUPT; andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: return -1; andre@0: } andre@0: andre@0: rv = 0; andre@0: if (pq.on_ioq == PR_FALSE) { andre@0: /* Count the number of ready descriptors */ andre@0: while (--pdcnt >= 0) { andre@0: if (unixpds->out_flags != 0) { andre@0: rv++; andre@0: } andre@0: unixpds++; andre@0: } andre@0: } andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: * Unblock threads waiting for I/O andre@0: * used when interrupting threads andre@0: * andre@0: * NOTE: The thread lock should held when this function is called. andre@0: * On return, the thread lock is released. andre@0: */ andre@0: void _PR_Unblock_IO_Wait(PRThread *thr) andre@0: { andre@0: int pri = thr->priority; andre@0: _PRCPU *cpu = thr->cpu; andre@0: andre@0: /* andre@0: * GLOBAL threads wakeup periodically to check for interrupt andre@0: */ andre@0: if (_PR_IS_NATIVE_THREAD(thr)) { andre@0: _PR_THREAD_UNLOCK(thr); andre@0: return; andre@0: } andre@0: andre@0: PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); andre@0: _PR_SLEEPQ_LOCK(cpu); andre@0: _PR_DEL_SLEEPQ(thr, PR_TRUE); andre@0: _PR_SLEEPQ_UNLOCK(cpu); andre@0: andre@0: PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); andre@0: thr->state = _PR_RUNNABLE; andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(thr, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: _PR_THREAD_UNLOCK(thr); andre@0: _PR_MD_WAKEUP_WAITER(thr); andre@0: } andre@0: #endif /* !defined(_PR_PTHREADS) */ andre@0: andre@0: /* andre@0: * When a nonblocking connect has completed, determine whether it andre@0: * succeeded or failed, and if it failed, what the error code is. andre@0: * andre@0: * The function returns the error code. An error code of 0 means andre@0: * that the nonblocking connect succeeded. andre@0: */ andre@0: andre@0: int _MD_unix_get_nonblocking_connect_error(int osfd) andre@0: { andre@0: #if defined(NTO) andre@0: /* Neutrino does not support the SO_ERROR socket option */ andre@0: PRInt32 rv; andre@0: PRNetAddr addr; andre@0: _PRSockLen_t addrlen = sizeof(addr); andre@0: andre@0: /* Test to see if we are using the Tiny TCP/IP Stack or the Full one. */ andre@0: struct statvfs superblock; andre@0: rv = fstatvfs(osfd, &superblock); andre@0: if (rv == 0) { andre@0: if (strcmp(superblock.f_basetype, "ttcpip") == 0) { andre@0: /* Using the Tiny Stack! */ andre@0: rv = getpeername(osfd, (struct sockaddr *) &addr, andre@0: (_PRSockLen_t *) &addrlen); andre@0: if (rv == -1) { andre@0: int errno_copy = errno; /* make a copy so I don't andre@0: * accidentally reset */ andre@0: andre@0: if (errno_copy == ENOTCONN) { andre@0: struct stat StatInfo; andre@0: rv = fstat(osfd, &StatInfo); andre@0: if (rv == 0) { andre@0: time_t current_time = time(NULL); andre@0: andre@0: /* andre@0: * this is a real hack, can't explain why it andre@0: * works it just does andre@0: */ andre@0: if (abs(current_time - StatInfo.st_atime) < 5) { andre@0: return ECONNREFUSED; andre@0: } else { andre@0: return ETIMEDOUT; andre@0: } andre@0: } else { andre@0: return ECONNREFUSED; andre@0: } andre@0: } else { andre@0: return errno_copy; andre@0: } andre@0: } else { andre@0: /* No Error */ andre@0: return 0; andre@0: } andre@0: } else { andre@0: /* Have the FULL Stack which supports SO_ERROR */ andre@0: /* Hasn't been written yet, never been tested! */ andre@0: /* Jerry.Kirk@Nexwarecorp.com */ andre@0: andre@0: int err; andre@0: _PRSockLen_t optlen = sizeof(err); andre@0: andre@0: if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, andre@0: (char *) &err, &optlen) == -1) { andre@0: return errno; andre@0: } else { andre@0: return err; andre@0: } andre@0: } andre@0: } else { andre@0: return ECONNREFUSED; andre@0: } andre@0: #elif defined(UNIXWARE) andre@0: /* andre@0: * getsockopt() fails with EPIPE, so use getmsg() instead. andre@0: */ andre@0: andre@0: int rv; andre@0: int flags = 0; andre@0: rv = getmsg(osfd, NULL, NULL, &flags); andre@0: PR_ASSERT(-1 == rv || 0 == rv); andre@0: if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { andre@0: return errno; andre@0: } andre@0: return 0; /* no error */ andre@0: #else andre@0: int err; andre@0: _PRSockLen_t optlen = sizeof(err); andre@0: if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { andre@0: return errno; andre@0: } else { andre@0: return err; andre@0: } andre@0: #endif andre@0: } andre@0: andre@0: /************************************************************************/ andre@0: andre@0: /* andre@0: ** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread andre@0: ** safe. Unfortunately, neither is mozilla. To make these programs work andre@0: ** in a pre-emptive threaded environment, we need to use a lock. andre@0: */ andre@0: andre@0: void PR_XLock(void) andre@0: { andre@0: PR_EnterMonitor(_pr_Xfe_mon); andre@0: } andre@0: andre@0: void PR_XUnlock(void) andre@0: { andre@0: PR_ExitMonitor(_pr_Xfe_mon); andre@0: } andre@0: andre@0: PRBool PR_XIsLocked(void) andre@0: { andre@0: return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; andre@0: } andre@0: andre@0: void PR_XWait(int ms) andre@0: { andre@0: PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); andre@0: } andre@0: andre@0: void PR_XNotify(void) andre@0: { andre@0: PR_Notify(_pr_Xfe_mon); andre@0: } andre@0: andre@0: void PR_XNotifyAll(void) andre@0: { andre@0: PR_NotifyAll(_pr_Xfe_mon); andre@0: } andre@0: andre@0: #if defined(HAVE_FCNTL_FILE_LOCKING) andre@0: andre@0: PRStatus andre@0: _MD_LockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: struct flock arg; andre@0: andre@0: arg.l_type = F_WRLCK; andre@0: arg.l_whence = SEEK_SET; andre@0: arg.l_start = 0; andre@0: arg.l_len = 0; /* until EOF */ andre@0: rv = fcntl(f, F_SETLKW, &arg); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus andre@0: _MD_TLockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: struct flock arg; andre@0: andre@0: arg.l_type = F_WRLCK; andre@0: arg.l_whence = SEEK_SET; andre@0: arg.l_start = 0; andre@0: arg.l_len = 0; /* until EOF */ andre@0: rv = fcntl(f, F_SETLK, &arg); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus andre@0: _MD_UnlockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: struct flock arg; andre@0: andre@0: arg.l_type = F_UNLCK; andre@0: arg.l_whence = SEEK_SET; andre@0: arg.l_start = 0; andre@0: arg.l_len = 0; /* until EOF */ andre@0: rv = fcntl(f, F_SETLK, &arg); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: #elif defined(HAVE_BSD_FLOCK) andre@0: andre@0: #include andre@0: andre@0: PRStatus andre@0: _MD_LockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: rv = flock(f, LOCK_EX); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus andre@0: _MD_TLockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: rv = flock(f, LOCK_EX|LOCK_NB); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus andre@0: _MD_UnlockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: rv = flock(f, LOCK_UN); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: #else andre@0: andre@0: PRStatus andre@0: _MD_LockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: rv = lockf(f, F_LOCK, 0); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus andre@0: _MD_TLockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: rv = lockf(f, F_TLOCK, 0); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus andre@0: _MD_UnlockFile(PRInt32 f) andre@0: { andre@0: PRInt32 rv; andre@0: rv = lockf(f, F_ULOCK, 0); andre@0: if (rv == 0) andre@0: return PR_SUCCESS; andre@0: _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: #endif andre@0: andre@0: PRStatus _MD_gethostname(char *name, PRUint32 namelen) andre@0: { andre@0: PRIntn rv; andre@0: andre@0: rv = gethostname(name, namelen); andre@0: if (0 == rv) { andre@0: return PR_SUCCESS; andre@0: } andre@0: _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen) andre@0: { andre@0: struct utsname info; andre@0: andre@0: PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE)); andre@0: andre@0: if (uname(&info) == -1) { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: if (PR_SI_SYSNAME == cmd) andre@0: (void)PR_snprintf(name, namelen, info.sysname); andre@0: else if (PR_SI_RELEASE == cmd) andre@0: (void)PR_snprintf(name, namelen, info.release); andre@0: else andre@0: return PR_FAILURE; andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: /* andre@0: ******************************************************************* andre@0: * andre@0: * Memory-mapped files andre@0: * andre@0: ******************************************************************* andre@0: */ andre@0: andre@0: PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) andre@0: { andre@0: PRFileInfo info; andre@0: PRUint32 sz; andre@0: andre@0: LL_L2UI(sz, size); andre@0: if (sz) { andre@0: if (PR_GetOpenFileInfo(fmap->fd, &info) == PR_FAILURE) { andre@0: return PR_FAILURE; andre@0: } andre@0: if (sz > info.size) { andre@0: /* andre@0: * Need to extend the file andre@0: */ andre@0: if (fmap->prot != PR_PROT_READWRITE) { andre@0: PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) { andre@0: return PR_FAILURE; andre@0: } andre@0: if (PR_Write(fmap->fd, "", 1) != 1) { andre@0: return PR_FAILURE; andre@0: } andre@0: } andre@0: } andre@0: if (fmap->prot == PR_PROT_READONLY) { andre@0: fmap->md.prot = PROT_READ; andre@0: #ifdef OSF1V4_MAP_PRIVATE_BUG andre@0: /* andre@0: * Use MAP_SHARED to work around a bug in OSF1 V4.0D andre@0: * (QAR 70220 in the OSF_QAR database) that results in andre@0: * corrupted data in the memory-mapped region. This andre@0: * bug is fixed in V5.0. andre@0: */ andre@0: fmap->md.flags = MAP_SHARED; andre@0: #else andre@0: fmap->md.flags = MAP_PRIVATE; andre@0: #endif andre@0: } else if (fmap->prot == PR_PROT_READWRITE) { andre@0: fmap->md.prot = PROT_READ | PROT_WRITE; andre@0: fmap->md.flags = MAP_SHARED; andre@0: } else { andre@0: PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); andre@0: fmap->md.prot = PROT_READ | PROT_WRITE; andre@0: fmap->md.flags = MAP_PRIVATE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: void * _MD_MemMap( andre@0: PRFileMap *fmap, andre@0: PRInt64 offset, andre@0: PRUint32 len) andre@0: { andre@0: PRInt32 off; andre@0: void *addr; andre@0: andre@0: LL_L2I(off, offset); andre@0: if ((addr = mmap(0, len, fmap->md.prot, fmap->md.flags, andre@0: fmap->fd->secret->md.osfd, off)) == (void *) -1) { andre@0: _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); andre@0: addr = NULL; andre@0: } andre@0: return addr; andre@0: } andre@0: andre@0: PRStatus _MD_MemUnmap(void *addr, PRUint32 len) andre@0: { andre@0: if (munmap(addr, len) == 0) { andre@0: return PR_SUCCESS; andre@0: } andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PRStatus _MD_CloseFileMap(PRFileMap *fmap) andre@0: { andre@0: if ( PR_TRUE == fmap->md.isAnonFM ) { andre@0: PRStatus rc = PR_Close( fmap->fd ); andre@0: if ( PR_FAILURE == rc ) { andre@0: PR_LOG( _pr_io_lm, PR_LOG_DEBUG, andre@0: ("_MD_CloseFileMap(): error closing anonymnous file map osfd")); andre@0: return PR_FAILURE; andre@0: } andre@0: } andre@0: PR_DELETE(fmap); andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PRStatus _MD_SyncMemMap( andre@0: PRFileDesc *fd, andre@0: void *addr, andre@0: PRUint32 len) andre@0: { andre@0: /* msync(..., MS_SYNC) alone is sufficient to flush modified data to disk andre@0: * synchronously. It is not necessary to call fsync. */ andre@0: if (msync(addr, len, MS_SYNC) == 0) { andre@0: return PR_SUCCESS; andre@0: } andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: #if defined(_PR_NEED_FAKE_POLL) andre@0: andre@0: /* andre@0: * Some platforms don't have poll(). For easier porting of code andre@0: * that calls poll(), we emulate poll() using select(). andre@0: */ andre@0: andre@0: int poll(struct pollfd *filedes, unsigned long nfds, int timeout) andre@0: { andre@0: int i; andre@0: int rv; andre@0: int maxfd; andre@0: fd_set rd, wr, ex; andre@0: struct timeval tv, *tvp; andre@0: andre@0: if (timeout < 0 && timeout != -1) { andre@0: errno = EINVAL; andre@0: return -1; andre@0: } andre@0: andre@0: if (timeout == -1) { andre@0: tvp = NULL; andre@0: } else { andre@0: tv.tv_sec = timeout / 1000; andre@0: tv.tv_usec = (timeout % 1000) * 1000; andre@0: tvp = &tv; andre@0: } andre@0: andre@0: maxfd = -1; andre@0: FD_ZERO(&rd); andre@0: FD_ZERO(&wr); andre@0: FD_ZERO(&ex); andre@0: andre@0: for (i = 0; i < nfds; i++) { andre@0: int osfd = filedes[i].fd; andre@0: int events = filedes[i].events; andre@0: PRBool fdHasEvent = PR_FALSE; andre@0: andre@0: if (osfd < 0) { andre@0: continue; /* Skip this osfd. */ andre@0: } andre@0: andre@0: /* andre@0: * Map the poll events to the select fd_sets. andre@0: * POLLIN, POLLRDNORM ===> readable andre@0: * POLLOUT, POLLWRNORM ===> writable andre@0: * POLLPRI, POLLRDBAND ===> exception andre@0: * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) andre@0: * are ignored. andre@0: * andre@0: * The output events POLLERR and POLLHUP are never turned on. andre@0: * POLLNVAL may be turned on. andre@0: */ andre@0: andre@0: if (events & (POLLIN | POLLRDNORM)) { andre@0: FD_SET(osfd, &rd); andre@0: fdHasEvent = PR_TRUE; andre@0: } andre@0: if (events & (POLLOUT | POLLWRNORM)) { andre@0: FD_SET(osfd, &wr); andre@0: fdHasEvent = PR_TRUE; andre@0: } andre@0: if (events & (POLLPRI | POLLRDBAND)) { andre@0: FD_SET(osfd, &ex); andre@0: fdHasEvent = PR_TRUE; andre@0: } andre@0: if (fdHasEvent && osfd > maxfd) { andre@0: maxfd = osfd; andre@0: } andre@0: } andre@0: andre@0: rv = select(maxfd + 1, &rd, &wr, &ex, tvp); andre@0: andre@0: /* Compute poll results */ andre@0: if (rv > 0) { andre@0: rv = 0; andre@0: for (i = 0; i < nfds; i++) { andre@0: PRBool fdHasEvent = PR_FALSE; andre@0: andre@0: filedes[i].revents = 0; andre@0: if (filedes[i].fd < 0) { andre@0: continue; andre@0: } andre@0: if (FD_ISSET(filedes[i].fd, &rd)) { andre@0: if (filedes[i].events & POLLIN) { andre@0: filedes[i].revents |= POLLIN; andre@0: } andre@0: if (filedes[i].events & POLLRDNORM) { andre@0: filedes[i].revents |= POLLRDNORM; andre@0: } andre@0: fdHasEvent = PR_TRUE; andre@0: } andre@0: if (FD_ISSET(filedes[i].fd, &wr)) { andre@0: if (filedes[i].events & POLLOUT) { andre@0: filedes[i].revents |= POLLOUT; andre@0: } andre@0: if (filedes[i].events & POLLWRNORM) { andre@0: filedes[i].revents |= POLLWRNORM; andre@0: } andre@0: fdHasEvent = PR_TRUE; andre@0: } andre@0: if (FD_ISSET(filedes[i].fd, &ex)) { andre@0: if (filedes[i].events & POLLPRI) { andre@0: filedes[i].revents |= POLLPRI; andre@0: } andre@0: if (filedes[i].events & POLLRDBAND) { andre@0: filedes[i].revents |= POLLRDBAND; andre@0: } andre@0: fdHasEvent = PR_TRUE; andre@0: } andre@0: if (fdHasEvent) { andre@0: rv++; andre@0: } andre@0: } andre@0: PR_ASSERT(rv > 0); andre@0: } else if (rv == -1 && errno == EBADF) { andre@0: rv = 0; andre@0: for (i = 0; i < nfds; i++) { andre@0: filedes[i].revents = 0; andre@0: if (filedes[i].fd < 0) { andre@0: continue; andre@0: } andre@0: if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) { andre@0: filedes[i].revents = POLLNVAL; andre@0: rv++; andre@0: } andre@0: } andre@0: PR_ASSERT(rv > 0); andre@0: } andre@0: PR_ASSERT(-1 != timeout || rv != 0); andre@0: andre@0: return rv; andre@0: } andre@0: #endif /* _PR_NEED_FAKE_POLL */