Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/nsprpub/pr/src/md/unix/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 91 kB image not shown  

Quelle  unix.c   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "primpl.h"

#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/utsname.h>

#ifdef _PR_POLL_AVAILABLE
#  include <poll.h>
#endif

#if defined(ANDROID)
#  include <android/api-level.h>
#endif

#if defined(NTO)
#  include <sys/statvfs.h>
#endif

/*
 * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
 * PRInt32* pointer to a _PRSockLen_t* pointer.
 */

#if defined(HAVE_SOCKLEN_T) || (defined(__GLIBC__) && __GLIBC__ >= 2)
#  define _PRSockLen_t socklen_t
#elif defined(HPUX) || defined(SOLARIS) || defined(AIX4_1) || \
    defined(LINUX) || defined(DARWIN) || defined(QNX)
#  define _PRSockLen_t int
#elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) || \
    defined(NETBSD) || defined(OPENBSD)
|| defined(NTO) ||
    defined(RISCOS)
#  define _PRSockLen_t size_t
#else
#  error "Cannot determine architecture"
#endif

/*
** Global lock variable used to bracket calls into rusty libraries that
** aren't thread safe (like libc, libX, etc).
*/

static PRLock* _pr_unix_rename_lock = NULL;
static PRMonitor* _pr_Xfe_mon = NULL;

static PRInt64 minus_one;

sigset_t timer_set;

#if !defined(_PR_PTHREADS)

static sigset_t empty_set;

#  ifdef SOLARIS
#    include <sys/file.h>
#    include <sys/filio.h>
#  endif

#  ifndef PIPE_BUF
#    define PIPE_BUF 512
#  endif

/*
 * _nspr_noclock - if set clock interrupts are disabled
 */

int _nspr_noclock = 1;

/*
 * There is an assertion in this code that NSPR's definition of PRIOVec
 * is bit compatible with UNIX' definition of a struct iovec. This is
 * applicable to the 'writev()' operations where the types are casually
 * cast to avoid warnings.
 */


int _pr_md_pipefd[2] = {-1, -1};
static char _pr_md_pipebuf[PIPE_BUF];
static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag,
                             PRIntervalTime timeout);

_PRInterruptTable _pr_interruptTable[] = {{
                                              "clock",
                                              _PR_MISSED_CLOCK,
                                              _PR_ClockInterrupt,
                                          },
                                          {0}};

void _MD_unix_init_running_cpu(_PRCPU* cpu) {
  PR_INIT_CLIST(&(cpu->md.md_unix.ioQ));
  cpu->md.md_unix.ioq_max_osfd = -1;
  cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT;
}

PRStatus _MD_open_dir(_MDDir* d, const char* name) {
  int err;

  d->d = opendir(name);
  if (!d->d) {
    err = _MD_ERRNO();
    _PR_MD_MAP_OPENDIR_ERROR(err);
    return PR_FAILURE;
  }
  return PR_SUCCESS;
}

PRInt32 _MD_close_dir(_MDDir* d) {
  int rv = 0, err;

  if (d->d) {
    rv = closedir(d->d);
    if (rv == -1) {
      err = _MD_ERRNO();
      _PR_MD_MAP_CLOSEDIR_ERROR(err);
    }
  }
  return rv;
}

char* _MD_read_dir(_MDDir* d, PRIntn flags) {
  struct dirent* de;
  int err;

  for (;;) {
    /*
     * XXX: readdir() is not MT-safe. There is an MT-safe version
     * readdir_r() on some systems.
     */

    _MD_ERRNO() = 0;
    de = readdir(d->d);
    if (!de) {
      err = _MD_ERRNO();
      _PR_MD_MAP_READDIR_ERROR(err);
      return 0;
    }
    if ((flags & PR_SKIP_DOT) && (de->d_name[0] == '.') &&
        (de->d_name[1] == 0)) {
      continue;
    }
    if ((flags & PR_SKIP_DOT_DOT) && (de->d_name[0] == '.') &&
        (de->d_name[1] == '.') && (de->d_name[2] == 0)) {
      continue;
    }
    if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.')) {
      continue;
    }
    break;
  }
  return de->d_name;
}

PRInt32 _MD_delete(const char* name) {
  PRInt32 rv, err;

  rv = unlink(name);
  if (rv == -1) {
    err = _MD_ERRNO();
    _PR_MD_MAP_UNLINK_ERROR(err);
  }
  return (rv);
}

PRInt32 _MD_rename(const char* from, const char* to) {
  PRInt32 rv = -1, err;

  /*
  ** This is trying to enforce the semantics of WINDOZE' rename
  ** operation. That means one is not allowed to rename over top
  ** of an existing file. Holding a lock across these two function
  ** and the open function is known to be a bad idea, but ....
  */

  if (NULL != _pr_unix_rename_lock) {
    PR_Lock(_pr_unix_rename_lock);
  }
  if (0 == access(to, F_OK)) {
    PR_SetError(PR_FILE_EXISTS_ERROR, 0);
  } else {
    rv = rename(from, to);
    if (rv < 0) {
      err = _MD_ERRNO();
      _PR_MD_MAP_RENAME_ERROR(err);
    }
  }
  if (NULL != _pr_unix_rename_lock) {
    PR_Unlock(_pr_unix_rename_lock);
  }
  return rv;
}

PRInt32 _MD_access(const char* name, PRAccessHow how) {
  PRInt32 rv, err;
  int amode;

  switch (how) {
    case PR_ACCESS_WRITE_OK:
      amode = W_OK;
      break;
    case PR_ACCESS_READ_OK:
      amode = R_OK;
      break;
    case PR_ACCESS_EXISTS:
      amode = F_OK;
      break;
    default:
      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
      rv = -1;
      goto done;
  }
  rv = access(name, amode);

  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_ACCESS_ERROR(err);
  }

done:
  return (rv);
}

PRInt32 _MD_mkdir(const char* name, PRIntn mode) {
  int rv, err;

  /*
  ** This lock is used to enforce rename semantics as described
  ** in PR_Rename. Look there for more fun details.
  */

  if (NULL != _pr_unix_rename_lock) {
    PR_Lock(_pr_unix_rename_lock);
  }
  rv = mkdir(name, mode);
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_MKDIR_ERROR(err);
  }
  if (NULL != _pr_unix_rename_lock) {
    PR_Unlock(_pr_unix_rename_lock);
  }
  return rv;
}

PRInt32 _MD_rmdir(const char* name) {
  int rv, err;

  rv = rmdir(name);
  if (rv == -1) {
    err = _MD_ERRNO();
    _PR_MD_MAP_RMDIR_ERROR(err);
  }
  return rv;
}

PRInt32 _MD_read(PRFileDesc* fd, void* buf, PRInt32 amount) {
  PRThread* me = _PR_MD_CURRENT_THREAD();
  PRInt32 rv, err;
#  ifndef _PR_USE_POLL
  fd_set rd;
#  else
  struct pollfd pfd;
#  endif /* _PR_USE_POLL */
  PRInt32 osfd = fd->secret->md.osfd;

#  ifndef _PR_USE_POLL
  FD_ZERO(&rd);
  FD_SET(osfd, &rd);
#  else
  pfd.fd = osfd;
  pfd.events = POLLIN;
#  endif /* _PR_USE_POLL */
  while ((rv = read(osfd, buf, amount)) == -1) {
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ,
                                PR_INTERVAL_NO_TIMEOUT)) < 0) {
          goto done;
        }
      } else {
#  ifndef _PR_USE_POLL
        while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL)) == -1 &&
               (err = _MD_ERRNO()) == EINTR) {
          /* retry _MD_SELECT() if it is interrupted */
        }
#  else  /* _PR_USE_POLL */
        while ((rv = _MD_POLL(&pfd, 1, -1)) == -1 &&
               (err = _MD_ERRNO()) == EINTR) {
          /* retry _MD_POLL() if it is interrupted */
        }
#  endif /* _PR_USE_POLL */
        if (rv == -1) {
          break;
        }
      }
      if (_PR_PENDING_INTERRUPT(me)) {
        break;
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  if (rv < 0) {
    if (_PR_PENDING_INTERRUPT(me)) {
      me->flags &= ~_PR_INTERRUPT;
      PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    } else {
      _PR_MD_MAP_READ_ERROR(err);
    }
  }
done:
  return (rv);
}

PRInt32 _MD_write(PRFileDesc* fd, const void* buf, PRInt32 amount) {
  PRThread* me = _PR_MD_CURRENT_THREAD();
  PRInt32 rv, err;
#  ifndef _PR_USE_POLL
  fd_set wd;
#  else
  struct pollfd pfd;
#  endif /* _PR_USE_POLL */
  PRInt32 osfd = fd->secret->md.osfd;

#  ifndef _PR_USE_POLL
  FD_ZERO(&wd);
  FD_SET(osfd, &wd);
#  else
  pfd.fd = osfd;
  pfd.events = POLLOUT;
#  endif /* _PR_USE_POLL */
  while ((rv = write(osfd, buf, amount)) == -1) {
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE,
                                PR_INTERVAL_NO_TIMEOUT)) < 0) {
          goto done;
        }
      } else {
#  ifndef _PR_USE_POLL
        while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL)) == -1 &&
               (err = _MD_ERRNO()) == EINTR) {
          /* retry _MD_SELECT() if it is interrupted */
        }
#  else  /* _PR_USE_POLL */
        while ((rv = _MD_POLL(&pfd, 1, -1)) == -1 &&
               (err = _MD_ERRNO()) == EINTR) {
          /* retry _MD_POLL() if it is interrupted */
        }
#  endif /* _PR_USE_POLL */
        if (rv == -1) {
          break;
        }
      }
      if (_PR_PENDING_INTERRUPT(me)) {
        break;
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  if (rv < 0) {
    if (_PR_PENDING_INTERRUPT(me)) {
      me->flags &= ~_PR_INTERRUPT;
      PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    } else {
      _PR_MD_MAP_WRITE_ERROR(err);
    }
  }
done:
  return (rv);
}

PRInt32 _MD_fsync(PRFileDesc* fd) {
  PRInt32 rv, err;

  rv = fsync(fd->secret->md.osfd);
  if (rv == -1) {
    err = _MD_ERRNO();
    _PR_MD_MAP_FSYNC_ERROR(err);
  }
  return (rv);
}

PRInt32 _MD_close(PRInt32 osfd) {
  PRInt32 rv, err;

  rv = close(osfd);
  if (rv == -1) {
    err = _MD_ERRNO();
    _PR_MD_MAP_CLOSE_ERROR(err);
  }
  return (rv);
}

PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) {
  PRInt32 osfd, err;

  osfd = socket(domain, type, proto);

  if (osfd == -1) {
    err = _MD_ERRNO();
    _PR_MD_MAP_SOCKET_ERROR(err);
    return (osfd);
  }

  return (osfd);
}

PRInt32 _MD_socketavailable(PRFileDesc* fd) {
  PRInt32 result;

  if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) {
    _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO());
    return -1;
  }
  return result;
}

PRInt64 _MD_socketavailable64(PRFileDesc* fd) {
  PRInt64 result;
  LL_I2L(result, _MD_socketavailable(fd));
  return result;
/* _MD_socketavailable64 */

#  define READ_FD 1
#  define WRITE_FD 2

/*
 * socket_io_wait --
 *
 * wait for socket i/o, periodically checking for interrupt
 *
 * The first implementation uses select(), for platforms without
 * poll().  The second (preferred) implementation uses poll().
 */


#  ifndef _PR_USE_POLL

static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
                              PRIntervalTime timeout) {
  PRInt32 rv = -1;
  struct timeval tv;
  PRThread* me = _PR_MD_CURRENT_THREAD();
  PRIntervalTime epoch, now, elapsed, remaining;
  PRBool wait_for_remaining;
  PRInt32 syserror;
  fd_set rd_wr;

  switch (timeout) {
    case PR_INTERVAL_NO_WAIT:
      PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
      break;
    case PR_INTERVAL_NO_TIMEOUT:
      /*
       * This is a special case of the 'default' case below.
       * Please see the comments there.
       */

      tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
      tv.tv_usec = 0;
      FD_ZERO(&rd_wr);
      do {
        FD_SET(osfd, &rd_wr);
        if (fd_type == READ_FD) {
          rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
        } else {
          rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
        }
        if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
          _PR_MD_MAP_SELECT_ERROR(syserror);
          break;
        }
        if (_PR_PENDING_INTERRUPT(me)) {
          me->flags &= ~_PR_INTERRUPT;
          PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
          rv = -1;
          break;
        }
      } while (rv == 0 || (rv == -1 && syserror == EINTR));
      break;
    default:
      now = epoch = PR_IntervalNow();
      remaining = timeout;
      FD_ZERO(&rd_wr);
      do {
        /*
         * We block in _MD_SELECT for at most
         * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
         * so that there is an upper limit on the delay
         * before the interrupt bit is checked.
         */

        wait_for_remaining = PR_TRUE;
        tv.tv_sec = PR_IntervalToSeconds(remaining);
        if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
          wait_for_remaining = PR_FALSE;
          tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
          tv.tv_usec = 0;
        } else {
          tv.tv_usec = PR_IntervalToMicroseconds(
              remaining - PR_SecondsToInterval(tv.tv_sec));
        }
        FD_SET(osfd, &rd_wr);
        if (fd_type == READ_FD) {
          rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
        } else {
          rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
        }
        /*
         * we don't consider EINTR a real error
         */

        if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
          _PR_MD_MAP_SELECT_ERROR(syserror);
          break;
        }
        if (_PR_PENDING_INTERRUPT(me)) {
          me->flags &= ~_PR_INTERRUPT;
          PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
          rv = -1;
          break;
        }
        /*
         * We loop again if _MD_SELECT timed out or got interrupted
         * by a signal, and the timeout deadline has not passed yet.
         */

        if (rv == 0 || (rv == -1 && syserror == EINTR)) {
          /*
           * If _MD_SELECT timed out, we know how much time
           * we spent in blocking, so we can avoid a
           * PR_IntervalNow() call.
           */

          if (rv == 0) {
            if (wait_for_remaining) {
              now += remaining;
            } else {
              now += PR_SecondsToInterval(tv.tv_sec) +
                     PR_MicrosecondsToInterval(tv.tv_usec);
            }
          } else {
            now = PR_IntervalNow();
          }
          elapsed = (PRIntervalTime)(now - epoch);
          if (elapsed >= timeout) {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
            rv = -1;
            break;
          } else {
            remaining = timeout - elapsed;
          }
        }
      } while (rv == 0 || (rv == -1 && syserror == EINTR));
      break;
  }
  return (rv);
}

#  else /* _PR_USE_POLL */

static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
                              PRIntervalTime timeout) {
  PRInt32 rv = -1;
  int msecs;
  PRThread* me = _PR_MD_CURRENT_THREAD();
  PRIntervalTime epoch, now, elapsed, remaining;
  PRBool wait_for_remaining;
  PRInt32 syserror;
  struct pollfd pfd;

  switch (timeout) {
    case PR_INTERVAL_NO_WAIT:
      PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
      break;
    case PR_INTERVAL_NO_TIMEOUT:
      /*
       * This is a special case of the 'default' case below.
       * Please see the comments there.
       */

      msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
      pfd.fd = osfd;
      if (fd_type == READ_FD) {
        pfd.events = POLLIN;
      } else {
        pfd.events = POLLOUT;
      }
      do {
        rv = _MD_POLL(&pfd, 1, msecs);
        if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
          _PR_MD_MAP_POLL_ERROR(syserror);
          break;
        }
        /*
         * If POLLERR is set, don't process it; retry the operation
         */

        if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) {
          rv = -1;
          _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents);
          break;
        }
        if (_PR_PENDING_INTERRUPT(me)) {
          me->flags &= ~_PR_INTERRUPT;
          PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
          rv = -1;
          break;
        }
      } while (rv == 0 || (rv == -1 && syserror == EINTR));
      break;
    default:
      now = epoch = PR_IntervalNow();
      remaining = timeout;
      pfd.fd = osfd;
      if (fd_type == READ_FD) {
        pfd.events = POLLIN;
      } else {
        pfd.events = POLLOUT;
      }
      do {
        /*
         * We block in _MD_POLL for at most
         * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
         * so that there is an upper limit on the delay
         * before the interrupt bit is checked.
         */

        wait_for_remaining = PR_TRUE;
        msecs = PR_IntervalToMilliseconds(remaining);
        if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
          wait_for_remaining = PR_FALSE;
          msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
        }
        rv = _MD_POLL(&pfd, 1, msecs);
        /*
         * we don't consider EINTR a real error
         */

        if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
          _PR_MD_MAP_POLL_ERROR(syserror);
          break;
        }
        if (_PR_PENDING_INTERRUPT(me)) {
          me->flags &= ~_PR_INTERRUPT;
          PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
          rv = -1;
          break;
        }
        /*
         * If POLLERR is set, don't process it; retry the operation
         */

        if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) {
          rv = -1;
          _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents);
          break;
        }
        /*
         * We loop again if _MD_POLL timed out or got interrupted
         * by a signal, and the timeout deadline has not passed yet.
         */

        if (rv == 0 || (rv == -1 && syserror == EINTR)) {
          /*
           * If _MD_POLL timed out, we know how much time
           * we spent in blocking, so we can avoid a
           * PR_IntervalNow() call.
           */

          if (rv == 0) {
            if (wait_for_remaining) {
              now += remaining;
            } else {
              now += PR_MillisecondsToInterval(msecs);
            }
          } else {
            now = PR_IntervalNow();
          }
          elapsed = (PRIntervalTime)(now - epoch);
          if (elapsed >= timeout) {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
            rv = -1;
            break;
          } else {
            remaining = timeout - elapsed;
          }
        }
      } while (rv == 0 || (rv == -1 && syserror == EINTR));
      break;
  }
  return (rv);
}

#  endif /* _PR_USE_POLL */

static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag,
                             PRIntervalTime timeout) {
  _PRUnixPollDesc pd;
  PRInt32 rv;

  PR_LOG(_pr_io_lm, PR_LOG_MIN,
         ("waiting to %s on osfd=%d",
          (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write", osfd));

  if (timeout == PR_INTERVAL_NO_WAIT) {
    return 0;
  }

  pd.osfd = osfd;
  pd.in_flags = wait_flag;
  pd.out_flags = 0;

  rv = _PR_WaitForMultipleFDs(&pd, 1, timeout);

  if (rv == 0) {
    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
    rv = -1;
  }
  return rv;
}

PRInt32 _MD_recv(PRFileDesc* fd, void* buf, PRInt32 amount, PRInt32 flags,
                 PRIntervalTime timeout) {
  PRInt32 osfd = fd->secret->md.osfd;
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();

  /*
   * Many OS's (ex: Solaris) have a broken recv which won't read
   * from socketpairs.  As long as we don't use flags on socketpairs, this
   * is a decent fix. - mikep
   */

#  if defined(SOLARIS)
  while ((rv = read(osfd, buf, amount)) == -1) {
#  else
  while ((rv = recv(osfd, buf, amount, flags)) == -1) {
#  endif
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) {
          goto done;
        }
      } else {
        if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
          goto done;
        }
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  if (rv < 0) {
    _PR_MD_MAP_RECV_ERROR(err);
  }
done:
  return (rv);
}

PRInt32 _MD_recvfrom(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
                     PRNetAddr* addr, PRUint32* addrlen,
                     PRIntervalTime timeout) {
  PRInt32 osfd = fd->secret->md.osfd;
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();

  while ((*addrlen = PR_NETADDR_SIZE(addr)),
         ((rv = recvfrom(osfd, buf, amount, flags, (struct sockaddr*)addr,
                         (_PRSockLen_t*)addrlen)) == -1)) {
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) {
          goto done;
        }
      } else {
        if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
          goto done;
        }
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  if (rv < 0) {
    _PR_MD_MAP_RECVFROM_ERROR(err);
  }
done:
#  ifdef _PR_HAVE_SOCKADDR_LEN
  if (rv != -1) {
    /* ignore the sa_len field of struct sockaddr */
    if (addr) {
      addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    }
  }
#  endif /* _PR_HAVE_SOCKADDR_LEN */
  return (rv);
}

PRInt32 _MD_send(PRFileDesc* fd, const void* buf, PRInt32 amount, PRInt32 flags,
                 PRIntervalTime timeout) {
  PRInt32 osfd = fd->secret->md.osfd;
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();
#  if defined(SOLARIS)
  PRInt32 tmp_amount = amount;
#  endif

  /*
   * On pre-2.6 Solaris, send() is much slower than write().
   * On 2.6 and beyond, with in-kernel sockets, send() and
   * write() are fairly equivalent in performance.
   */

#  if defined(SOLARIS)
  PR_ASSERT(0 == flags);
  while ((rv = write(osfd, buf, tmp_amount)) == -1) {
#  else
  while ((rv = send(osfd, buf, amount, flags)) == -1) {
#  endif
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) {
          goto done;
        }
      } else {
        if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) {
          goto done;
        }
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
#  if defined(SOLARIS)
      /*
       * The write system call has been reported to return the ERANGE
       * error on occasion. Try to write in smaller chunks to workaround
       * this bug.
       */

      if (err == ERANGE) {
        if (tmp_amount > 1) {
          tmp_amount = tmp_amount / 2; /* half the bytes */
          continue;
        }
      }
#  endif
      break;
    }
  }
  /*
   * optimization; if bytes sent is less than "amount" call
   * select before returning. This is because it is likely that
   * the next send() call will return EWOULDBLOCK.
   */

  if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) &&
      (timeout != PR_INTERVAL_NO_WAIT)) {
    if (_PR_IS_NATIVE_THREAD(me)) {
      if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
        rv = -1;
        goto done;
      }
    } else {
      if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) {
        rv = -1;
        goto done;
      }
    }
  }
  if (rv < 0) {
    _PR_MD_MAP_SEND_ERROR(err);
  }
done:
  return (rv);
}

PRInt32 _MD_sendto(PRFileDesc* fd, const void* buf, PRInt32 amount,
                   PRIntn flags, const PRNetAddr* addr, PRUint32 addrlen,
                   PRIntervalTime timeout) {
  PRInt32 osfd = fd->secret->md.osfd;
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();
#  ifdef _PR_HAVE_SOCKADDR_LEN
  PRNetAddr addrCopy;

  addrCopy = *addr;
  ((struct sockaddr*)&addrCopy)->sa_len = addrlen;
  ((struct sockaddr*)&addrCopy)->sa_family = addr->raw.family;

  while ((rv = sendto(osfd, buf, amount, flags, (struct sockaddr*)&addrCopy,
                      addrlen)) == -1) {
#  else
  while ((rv = sendto(osfd, buf, amount, flags, (struct sockaddr*)addr,
                      addrlen)) == -1) {
#  endif
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) {
          goto done;
        }
      } else {
        if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) {
          goto done;
        }
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  if (rv < 0) {
    _PR_MD_MAP_SENDTO_ERROR(err);
  }
done:
  return (rv);
}

PRInt32 _MD_writev(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_size,
                   PRIntervalTime timeout) {
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();
  PRInt32 index, amount = 0;
  PRInt32 osfd = fd->secret->md.osfd;

  /*
   * Calculate the total number of bytes to be sent; needed for
   * optimization later.
   * We could avoid this if this number was passed in; but it is
   * probably not a big deal because iov_size is usually small (less than
   * 3)
   */

  if (!fd->secret->nonblocking) {
    for (index = 0; index < iov_size; index++) {
      amount += iov[index].iov_len;
    }
  }

  while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) {
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) {
          goto done;
        }
      } else {
        if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) {
          goto done;
        }
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  /*
   * optimization; if bytes sent is less than "amount" call
   * select before returning. This is because it is likely that
   * the next writev() call will return EWOULDBLOCK.
   */

  if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) &&
      (timeout != PR_INTERVAL_NO_WAIT)) {
    if (_PR_IS_NATIVE_THREAD(me)) {
      if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
        rv = -1;
        goto done;
      }
    } else {
      if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) {
        rv = -1;
        goto done;
      }
    }
  }
  if (rv < 0) {
    _PR_MD_MAP_WRITEV_ERROR(err);
  }
done:
  return (rv);
}

PRInt32 _MD_accept(PRFileDesc* fd, PRNetAddr* addr, PRUint32* addrlen,
                   PRIntervalTime timeout) {
  PRInt32 osfd = fd->secret->md.osfd;
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();

  while ((rv = accept(osfd, (struct sockaddr*)addr, (_PRSockLen_t*)addrlen)) ==
         -1) {
    err = _MD_ERRNO();
    if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == ECONNABORTED)) {
      if (fd->secret->nonblocking) {
        break;
      }
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) {
          goto done;
        }
      } else {
        if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) {
          goto done;
        }
      }
    } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
      continue;
    } else {
      break;
    }
  }
  if (rv < 0) {
    _PR_MD_MAP_ACCEPT_ERROR(err);
  }
done:
#  ifdef _PR_HAVE_SOCKADDR_LEN
  if (rv != -1) {
    /* ignore the sa_len field of struct sockaddr */
    if (addr) {
      addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    }
  }
#  endif /* _PR_HAVE_SOCKADDR_LEN */
  return (rv);
}

extern int _connect(int s, const struct sockaddr* name, int namelen);
PRInt32 _MD_connect(PRFileDesc* fd, const PRNetAddr* addr, PRUint32 addrlen,
                    PRIntervalTime timeout) {
  PRInt32 rv, err;
  PRThread* me = _PR_MD_CURRENT_THREAD();
  PRInt32 osfd = fd->secret->md.osfd;
#  ifdef _PR_HAVE_SOCKADDR_LEN
  PRNetAddr addrCopy;

  addrCopy = *addr;
  ((struct sockaddr*)&addrCopy)->sa_len = addrlen;
  ((struct sockaddr*)&addrCopy)->sa_family = addr->raw.family;
#  endif

  /*
   * We initiate the connection setup by making a nonblocking connect()
   * call.  If the connect() call fails, there are two cases we handle
   * specially:
   * 1. The connect() call was interrupted by a signal.  In this case
   *    we simply retry connect().
   * 2. The NSPR socket is nonblocking and connect() fails with
   *    EINPROGRESS.  We first wait until the socket becomes writable.
   *    Then we try to find out whether the connection setup succeeded
   *    or failed.
   */


retry:
#  ifdef _PR_HAVE_SOCKADDR_LEN
  if ((rv = connect(osfd, (struct sockaddr*)&addrCopy, addrlen)) == -1) {
#  else
  if ((rv = connect(osfd, (struct sockaddr*)addr, addrlen)) == -1) {
#  endif
    err = _MD_ERRNO();

    if (err == EINTR) {
      if (_PR_PENDING_INTERRUPT(me)) {
        me->flags &= ~_PR_INTERRUPT;
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        return -1;
      }
      goto retry;
    }

    if (!fd->secret->nonblocking && (err == EINPROGRESS)) {
      if (!_PR_IS_NATIVE_THREAD(me)) {
        if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) {
          return -1;
        }
      } else {
        /*
         * socket_io_wait() may return -1 or 1.
         */


        rv = socket_io_wait(osfd, WRITE_FD, timeout);
        if (rv == -1) {
          return -1;
        }
      }

      PR_ASSERT(rv == 1);
      if (_PR_PENDING_INTERRUPT(me)) {
        me->flags &= ~_PR_INTERRUPT;
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        return -1;
      }
      err = _MD_unix_get_nonblocking_connect_error(osfd);
      if (err != 0) {
        _PR_MD_MAP_CONNECT_ERROR(err);
        return -1;
      }
      return 0;
    }

    _PR_MD_MAP_CONNECT_ERROR(err);
  }

  return rv;
/* _MD_connect */

PRInt32 _MD_bind(PRFileDesc* fd, const PRNetAddr* addr, PRUint32 addrlen) {
  PRInt32 rv, err;
#  ifdef _PR_HAVE_SOCKADDR_LEN
  PRNetAddr addrCopy;

  addrCopy = *addr;
  ((struct sockaddr*)&addrCopy)->sa_len = addrlen;
  ((struct sockaddr*)&addrCopy)->sa_family = addr->raw.family;
  rv = bind(fd->secret->md.osfd, (struct sockaddr*)&addrCopy, (int)addrlen);
#  else
  rv = bind(fd->secret->md.osfd, (struct sockaddr*)addr, (int)addrlen);
#  endif
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_BIND_ERROR(err);
  }
  return (rv);
}

PRInt32 _MD_listen(PRFileDesc* fd, PRIntn backlog) {
  PRInt32 rv, err;

  rv = listen(fd->secret->md.osfd, backlog);
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_LISTEN_ERROR(err);
  }
  return (rv);
}

PRInt32 _MD_shutdown(PRFileDesc* fd, PRIntn how) {
  PRInt32 rv, err;

  rv = shutdown(fd->secret->md.osfd, how);
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_SHUTDOWN_ERROR(err);
  }
  return (rv);
}

PRInt32 _MD_socketpair(int af, int type, int flags, PRInt32* osfd) {
  PRInt32 rv, err;

  rv = socketpair(af, type, flags, osfd);
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_SOCKETPAIR_ERROR(err);
  }
  return rv;
}

PRStatus _MD_getsockname(PRFileDesc* fd, PRNetAddr* addr, PRUint32* addrlen) {
  PRInt32 rv, err;

  rv = getsockname(fd->secret->md.osfd, (struct sockaddr*)addr,
                   (_PRSockLen_t*)addrlen);
#  ifdef _PR_HAVE_SOCKADDR_LEN
  if (rv == 0) {
    /* ignore the sa_len field of struct sockaddr */
    if (addr) {
      addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    }
  }
#  endif /* _PR_HAVE_SOCKADDR_LEN */
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_GETSOCKNAME_ERROR(err);
  }
  return rv == 0 ? PR_SUCCESS : PR_FAILURE;
}

PRStatus _MD_getpeername(PRFileDesc* fd, PRNetAddr* addr, PRUint32* addrlen) {
  PRInt32 rv, err;

  rv = getpeername(fd->secret->md.osfd, (struct sockaddr*)addr,
                   (_PRSockLen_t*)addrlen);
#  ifdef _PR_HAVE_SOCKADDR_LEN
  if (rv == 0) {
    /* ignore the sa_len field of struct sockaddr */
    if (addr) {
      addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    }
  }
#  endif /* _PR_HAVE_SOCKADDR_LEN */
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_GETPEERNAME_ERROR(err);
  }
  return rv == 0 ? PR_SUCCESS : PR_FAILURE;
}

PRStatus _MD_getsockopt(PRFileDesc* fd, PRInt32 level, PRInt32 optname,
                        char* optval, PRInt32* optlen) {
  PRInt32 rv, err;

  rv = getsockopt(fd->secret->md.osfd, level, optname, optval,
                  (_PRSockLen_t*)optlen);
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_GETSOCKOPT_ERROR(err);
  }
  return rv == 0 ? PR_SUCCESS : PR_FAILURE;
}

PRStatus _MD_setsockopt(PRFileDesc* fd, PRInt32 level, PRInt32 optname,
                        const char* optval, PRInt32 optlen) {
  PRInt32 rv, err;

  rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_SETSOCKOPT_ERROR(err);
  }
  return rv == 0 ? PR_SUCCESS : PR_FAILURE;
}

PRStatus _MD_set_fd_inheritable(PRFileDesc* fd, PRBool inheritable) {
  int rv;

  rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC);
  if (-1 == rv) {
    PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
    return PR_FAILURE;
  }
  return PR_SUCCESS;
}

void _MD_init_fd_inheritable(PRFileDesc* fd, PRBool imported) {
  if (imported) {
    fd->secret->inheritable = _PR_TRI_UNKNOWN;
  } else {
    /* By default, a Unix fd is not closed on exec. */
#  ifdef DEBUG
    {
      int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
      PR_ASSERT(0 == flags);
    }
#  endif
    fd->secret->inheritable = _PR_TRI_TRUE;
  }
}

/************************************************************************/
#  if !defined(_PR_USE_POLL)

/*
** Scan through io queue and find any bad fd's that triggered the error
** from _MD_SELECT
*/

static void FindBadFDs(void) {
  PRCList* q;
  PRThread* me = _MD_CURRENT_THREAD();

  PR_ASSERT(!_PR_IS_NATIVE_THREAD(me));
  q = (_PR_IOQ(me->cpu)).next;
  _PR_IOQ_MAX_OSFD(me->cpu) = -1;
  _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
  while (q != &_PR_IOQ(me->cpu)) {
    PRPollQueue* pq = _PR_POLLQUEUE_PTR(q);
    PRBool notify = PR_FALSE;
    _PRUnixPollDesc* pds = pq->pds;
    _PRUnixPollDesc* epds = pds + pq->npds;
    PRInt32 pq_max_osfd = -1;

    q = q->next;
    for (; pds < epds; pds++) {
      PRInt32 osfd = pds->osfd;
      pds->out_flags = 0;
      PR_ASSERT(osfd >= 0 || pds->in_flags == 0);
      if (pds->in_flags == 0) {
        continue/* skip this fd */
      }
      if (fcntl(osfd, F_GETFL, 0) == -1) {
        /* Found a bad descriptor, remove it from the fd_sets. */
        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("file descriptor %d is bad", osfd));
        pds->out_flags = _PR_UNIX_POLL_NVAL;
        notify = PR_TRUE;
      }
      if (osfd > pq_max_osfd) {
        pq_max_osfd = osfd;
      }
    }

    if (notify) {
      PRIntn pri;
      PR_REMOVE_LINK(&pq->links);
      pq->on_ioq = PR_FALSE;

      /*
       * Decrement the count of descriptors for each desciptor/event
       * because this I/O request is being removed from the
       * ioq
       */

      pds = pq->pds;
      for (; pds < epds; pds++) {
        PRInt32 osfd = pds->osfd;
        PRInt16 in_flags = pds->in_flags;
        PR_ASSERT(osfd >= 0 || in_flags == 0);
        if (in_flags & _PR_UNIX_POLL_READ) {
          if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) {
            FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
          }
        }
        if (in_flags & _PR_UNIX_POLL_WRITE) {
          if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) {
            FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
          }
        }
        if (in_flags & _PR_UNIX_POLL_EXCEPT) {
          if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) {
            FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
          }
        }
      }

      _PR_THREAD_LOCK(pq->thr);
      if (pq->thr->flags & (_PR_ON_PAUSEQ | _PR_ON_SLEEPQ)) {
        _PRCPU* cpu = pq->thr->cpu;
        _PR_SLEEPQ_LOCK(pq->thr->cpu);
        _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
        _PR_SLEEPQ_UNLOCK(pq->thr->cpu);

        if (pq->thr->flags & _PR_SUSPENDING) {
          /*
           * set thread state to SUSPENDED;
           * a Resume operation on the thread
           * will move it to the runQ
           */

          pq->thr->state = _PR_SUSPENDED;
          _PR_MISCQ_LOCK(pq->thr->cpu);
          _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
          _PR_MISCQ_UNLOCK(pq->thr->cpu);
        } else {
          pri = pq->thr->priority;
          pq->thr->state = _PR_RUNNABLE;

          _PR_RUNQ_LOCK(cpu);
          _PR_ADD_RUNQ(pq->thr, cpu, pri);
          _PR_RUNQ_UNLOCK(cpu);
        }
      }
      _PR_THREAD_UNLOCK(pq->thr);
    } else {
      if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) {
        _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
      }
      if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) {
        _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
      }
    }
  }
  if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
    if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) {
      _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
    }
  }
}
#  endif /* !defined(_PR_USE_POLL) */

/************************************************************************/

/*
** Called by the scheduler when there is nothing to do. This means that
** all threads are blocked on some monitor somewhere.
**
** Note: this code doesn't release the scheduler lock.
*/

/*
** Pause the current CPU. longjmp to the cpu's pause stack
**
** This must be called with the scheduler locked
*/

void _MD_PauseCPU(PRIntervalTime ticks) {
  PRThread* me = _MD_CURRENT_THREAD();
#  ifdef _PR_USE_POLL
  int timeout;
  struct pollfd* pollfds;   /* an array of pollfd structures */
  struct pollfd* pollfdPtr; /* a pointer that steps through the array */
  unsigned long npollfds;   /* number of pollfd structures in array */
  unsigned long pollfds_size;
  int nfd; /* to hold the return value of poll() */
#  else
  struct timeval timeout, *tvp;
  fd_set r, w, e;
  fd_set *rp, *wp, *ep;
  PRInt32 max_osfd, nfd;
#  endif /* _PR_USE_POLL */
  PRInt32 rv;
  PRCList* q;
  PRUint32 min_timeout;
  sigset_t oldset;

  PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);

  _PR_MD_IOQ_LOCK();

#  ifdef _PR_USE_POLL
  /* Build up the pollfd structure array to wait on */

  /* Find out how many pollfd structures are needed */
  npollfds = _PR_IOQ_OSFD_CNT(me->cpu);
  PR_ASSERT(npollfds >= 0);

  /*
   * We use a pipe to wake up a native thread.  An fd is needed
   * for the pipe and we poll it for reading.
   */

  if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
    npollfds++;
  }

  /*
   * if the cpu's pollfd array is not big enough, release it and allocate a new
   * one
   */

  if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) {
    if (_PR_IOQ_POLLFDS(me->cpu) != NULL) {
      PR_DELETE(_PR_IOQ_POLLFDS(me->cpu));
    }
    pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds);
    pollfds = (struct pollfd*)PR_MALLOC(pollfds_size * sizeof(struct pollfd));
    _PR_IOQ_POLLFDS(me->cpu) = pollfds;
    _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size;
  } else {
    pollfds = _PR_IOQ_POLLFDS(me->cpu);
  }
  pollfdPtr = pollfds;

  /*
   * If we need to poll the pipe for waking up a native thread,
   * the pipe's fd is the first element in the pollfds array.
   */

  if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
    pollfdPtr->fd = _pr_md_pipefd[0];
    pollfdPtr->events = POLLIN;
    pollfdPtr++;
  }

  min_timeout = PR_INTERVAL_NO_TIMEOUT;
  for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) {
    PRPollQueue* pq = _PR_POLLQUEUE_PTR(q);
    _PRUnixPollDesc* pds = pq->pds;
    _PRUnixPollDesc* epds = pds + pq->npds;

    if (pq->timeout < min_timeout) {
      min_timeout = pq->timeout;
    }
    for (; pds < epds; pds++, pollfdPtr++) {
      /*
       * Assert that the pollfdPtr pointer does not go
       * beyond the end of the pollfds array
       */

      PR_ASSERT(pollfdPtr < pollfds + npollfds);
      pollfdPtr->fd = pds->osfd;
      /* direct copy of poll flags */
      pollfdPtr->events = pds->in_flags;
    }
  }
  _PR_IOQ_TIMEOUT(me->cpu) = min_timeout;
#  else
  /*
   * assigment of fd_sets
   */

  r = _PR_FD_READ_SET(me->cpu);
  w = _PR_FD_WRITE_SET(me->cpu);
  e = _PR_FD_EXCEPTION_SET(me->cpu);

  rp = &r;
  wp = &w;
  ep = &e;

  max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1;
  min_timeout = _PR_IOQ_TIMEOUT(me->cpu);
#  endif /* _PR_USE_POLL */
  /*
  ** Compute the minimum timeout value: make it the smaller of the
  ** timeouts specified by the i/o pollers or the timeout of the first
  ** sleeping thread.
  */

  q = _PR_SLEEPQ(me->cpu).next;

  if (q != &_PR_SLEEPQ(me->cpu)) {
    PRThread* t = _PR_THREAD_PTR(q);

    if (t->sleep < min_timeout) {
      min_timeout = t->sleep;
    }
  }
  if (min_timeout > ticks) {
    min_timeout = ticks;
  }

#  ifdef _PR_USE_POLL
  if (min_timeout == PR_INTERVAL_NO_TIMEOUT) {
    timeout = -1;
  } else {
    timeout = PR_IntervalToMilliseconds(min_timeout);
  }
#  else
  if (min_timeout == PR_INTERVAL_NO_TIMEOUT) {
    tvp = NULL;
  } else {
    timeout.tv_sec = PR_IntervalToSeconds(min_timeout);
    timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) % PR_USEC_PER_SEC;
    tvp = &timeout;
  }
#  endif /* _PR_USE_POLL */

  _PR_MD_IOQ_UNLOCK();
  _MD_CHECK_FOR_EXIT();
  /*
   * check for i/o operations
   */

#  ifndef _PR_NO_CLOCK_TIMER
  /*
   * Disable the clock interrupts while we are in select, if clock interrupts
   * are enabled. Otherwise, when the select/poll calls are interrupted, the
   * timer value starts ticking from zero again when the system call is
   * restarted.
   */

  if (!_nspr_noclock) {
    PR_ASSERT(sigismember(&timer_set, SIGALRM));
  }
  sigprocmask(SIG_BLOCK, &timer_set, &oldset);
#  endif /* !_PR_NO_CLOCK_TIMER */

#  ifndef _PR_USE_POLL
  PR_ASSERT(FD_ISSET(_pr_md_pipefd[0], rp));
  nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp);
#  else
  nfd = _MD_POLL(pollfds, npollfds, timeout);
#  endif /* !_PR_USE_POLL */

#  ifndef _PR_NO_CLOCK_TIMER
  if (!_nspr_noclock) {
    sigprocmask(SIG_SETMASK, &oldset, 0);
  }
#  endif /* !_PR_NO_CLOCK_TIMER */

  _MD_CHECK_FOR_EXIT();

  _PR_MD_primordial_cpu();

  _PR_MD_IOQ_LOCK();
  /*
  ** Notify monitors that are associated with the selected descriptors.
  */

#  ifdef _PR_USE_POLL
  if (nfd > 0) {
    pollfdPtr = pollfds;
    if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
      /*
       * Assert that the pipe is the first element in the
       * pollfds array.
       */

      PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]);
      if ((pollfds[0].revents & POLLIN) && (nfd == 1)) {
        /*
         * woken up by another thread; read all the data
         * in the pipe to empty the pipe
         */

        while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) ==
               PIPE_BUF) {
        }
        PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN)));
      }
      pollfdPtr++;
    }
    for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) {
      PRPollQueue* pq = _PR_POLLQUEUE_PTR(q);
      PRBool notify = PR_FALSE;
      _PRUnixPollDesc* pds = pq->pds;
      _PRUnixPollDesc* epds = pds + pq->npds;

      for (; pds < epds; pds++, pollfdPtr++) {
        /*
         * Assert that the pollfdPtr pointer does not go beyond
         * the end of the pollfds array.
         */

        PR_ASSERT(pollfdPtr < pollfds + npollfds);
        /*
         * Assert that the fd's in the pollfds array (stepped
         * through by pollfdPtr) are in the same order as
         * the fd's in _PR_IOQ() (stepped through by q and pds).
         * This is how the pollfds array was created earlier.
         */

        PR_ASSERT(pollfdPtr->fd == pds->osfd);
        pds->out_flags = pollfdPtr->revents;
        /* Negative fd's are ignored by poll() */
        if (pds->osfd >= 0 && pds->out_flags) {
          notify = PR_TRUE;
        }
      }
      if (notify) {
        PRIntn pri;
        PRThread* thred;

        PR_REMOVE_LINK(&pq->links);
        pq->on_ioq = PR_FALSE;

        thred = pq->thr;
        _PR_THREAD_LOCK(thred);
        if (pq->thr->flags & (_PR_ON_PAUSEQ | _PR_ON_SLEEPQ)) {
          _PRCPU* cpu = pq->thr->cpu;
          _PR_SLEEPQ_LOCK(pq->thr->cpu);
          _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
          _PR_SLEEPQ_UNLOCK(pq->thr->cpu);

          if (pq->thr->flags & _PR_SUSPENDING) {
            /*
             * set thread state to SUSPENDED;
             * a Resume operation on the thread
             * will move it to the runQ
             */

            pq->thr->state = _PR_SUSPENDED;
            _PR_MISCQ_LOCK(pq->thr->cpu);
            _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
            _PR_MISCQ_UNLOCK(pq->thr->cpu);
          } else {
            pri = pq->thr->priority;
            pq->thr->state = _PR_RUNNABLE;

            _PR_RUNQ_LOCK(cpu);
            _PR_ADD_RUNQ(pq->thr, cpu, pri);
            _PR_RUNQ_UNLOCK(cpu);
            if (_pr_md_idle_cpus > 1) {
              _PR_MD_WAKEUP_WAITER(thred);
            }
          }
        }
        _PR_THREAD_UNLOCK(thred);
        _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds;
        PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0);
      }
    }
  } else if (nfd == -1) {
    PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno));
  }

#  else
  if (nfd > 0) {
    q = _PR_IOQ(me->cpu).next;
    _PR_IOQ_MAX_OSFD(me->cpu) = -1;
    _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
    while (q != &_PR_IOQ(me->cpu)) {
      PRPollQueue* pq = _PR_POLLQUEUE_PTR(q);
      PRBool notify = PR_FALSE;
      _PRUnixPollDesc* pds = pq->pds;
      _PRUnixPollDesc* epds = pds + pq->npds;
      PRInt32 pq_max_osfd = -1;

      q = q->next;
      for (; pds < epds; pds++) {
        PRInt32 osfd = pds->osfd;
        PRInt16 in_flags = pds->in_flags;
        PRInt16 out_flags = 0;
        PR_ASSERT(osfd >= 0 || in_flags == 0);
        if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) {
          out_flags |= _PR_UNIX_POLL_READ;
        }
        if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) {
          out_flags |= _PR_UNIX_POLL_WRITE;
        }
        if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) {
          out_flags |= _PR_UNIX_POLL_EXCEPT;
        }
        pds->out_flags = out_flags;
        if (out_flags) {
          notify = PR_TRUE;
        }
        if (osfd > pq_max_osfd) {
          pq_max_osfd = osfd;
        }
      }
      if (notify == PR_TRUE) {
        PRIntn pri;
        PRThread* thred;

        PR_REMOVE_LINK(&pq->links);
        pq->on_ioq = PR_FALSE;

        /*
         * Decrement the count of descriptors for each desciptor/event
         * because this I/O request is being removed from the
         * ioq
         */

        pds = pq->pds;
        for (; pds < epds; pds++) {
          PRInt32 osfd = pds->osfd;
          PRInt16 in_flags = pds->in_flags;
          PR_ASSERT(osfd >= 0 || in_flags == 0);
          if (in_flags & _PR_UNIX_POLL_READ) {
            if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) {
              FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu));
            }
          }
          if (in_flags & _PR_UNIX_POLL_WRITE) {
            if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) {
              FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu));
            }
          }
          if (in_flags & _PR_UNIX_POLL_EXCEPT) {
            if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) {
              FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu));
            }
          }
        }

        /*
         * Because this thread can run on a different cpu right
         * after being added to the run queue, do not dereference
         * pq
         */

        thred = pq->thr;
        _PR_THREAD_LOCK(thred);
        if (pq->thr->flags & (_PR_ON_PAUSEQ | _PR_ON_SLEEPQ)) {
          _PRCPU* cpu = thred->cpu;
          _PR_SLEEPQ_LOCK(pq->thr->cpu);
          _PR_DEL_SLEEPQ(pq->thr, PR_TRUE);
          _PR_SLEEPQ_UNLOCK(pq->thr->cpu);

          if (pq->thr->flags & _PR_SUSPENDING) {
            /*
             * set thread state to SUSPENDED;
             * a Resume operation on the thread
             * will move it to the runQ
             */

            pq->thr->state = _PR_SUSPENDED;
            _PR_MISCQ_LOCK(pq->thr->cpu);
            _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu);
            _PR_MISCQ_UNLOCK(pq->thr->cpu);
          } else {
            pri = pq->thr->priority;
            pq->thr->state = _PR_RUNNABLE;

            pq->thr->cpu = cpu;
            _PR_RUNQ_LOCK(cpu);
            _PR_ADD_RUNQ(pq->thr, cpu, pri);
            _PR_RUNQ_UNLOCK(cpu);
            if (_pr_md_idle_cpus > 1) {
              _PR_MD_WAKEUP_WAITER(thred);
            }
          }
        }
        _PR_THREAD_UNLOCK(thred);
      } else {
        if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) {
          _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
        }
        if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) {
          _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
        }
      }
    }
    if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
      if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) {
        /*
         * woken up by another thread; read all the data
         * in the pipe to empty the pipe
         */

        while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) ==
               PIPE_BUF) {
        }
        PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN)));
      }
      if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) {
        _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
      }
    }
  } else if (nfd < 0) {
    if (errno == EBADF) {
      FindBadFDs();
    } else {
      PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", errno));
    }
  } else {
    PR_ASSERT(nfd == 0);
    /*
     * compute the new value of _PR_IOQ_TIMEOUT
     */

    q = _PR_IOQ(me->cpu).next;
    _PR_IOQ_MAX_OSFD(me->cpu) = -1;
    _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT;
    while (q != &_PR_IOQ(me->cpu)) {
      PRPollQueue* pq = _PR_POLLQUEUE_PTR(q);
      _PRUnixPollDesc* pds = pq->pds;
      _PRUnixPollDesc* epds = pds + pq->npds;
      PRInt32 pq_max_osfd = -1;

      q = q->next;
      for (; pds < epds; pds++) {
        if (pds->osfd > pq_max_osfd) {
          pq_max_osfd = pds->osfd;
        }
      }
      if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) {
        _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout;
      }
      if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) {
        _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd;
      }
    }
    if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
      if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) {
        _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
      }
    }
  }
#  endif /* _PR_USE_POLL */
  _PR_MD_IOQ_UNLOCK();
}

void _MD_Wakeup_CPUs() {
  PRInt32 rv, data;

  data = 0;
  rv = write(_pr_md_pipefd[1], &data, 1);

  while ((rv < 0) && (errno == EAGAIN)) {
    /*
     * pipe full, read all data in pipe to empty it
     */

    while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) ==
           PIPE_BUF) {
    }
    PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN)));
    rv = write(_pr_md_pipefd[1], &data, 1);
  }
}

void _MD_InitCPUS() {
  PRInt32 rv, flags;
  PRThread* me = _MD_CURRENT_THREAD();

  rv = pipe(_pr_md_pipefd);
  PR_ASSERT(rv == 0);
  _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0];
#  ifndef _PR_USE_POLL
  FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu));
#  endif

  flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0);
  fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK);
  flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0);
  fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK);
}

/*
** Unix SIGALRM (clock) signal handler
*/

static void ClockInterruptHandler() {
  int olderrno;
  PRUintn pri;
  _PRCPU* cpu = _PR_MD_CURRENT_CPU();
  PRThread* me = _MD_CURRENT_THREAD();

#  ifdef SOLARIS
  if (!me || _PR_IS_NATIVE_THREAD(me)) {
    _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK;
    return;
  }
#  endif

  if (_PR_MD_GET_INTSOFF() != 0) {
    cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK;
    return;
  }
  _PR_MD_SET_INTSOFF(1);

  olderrno = errno;
  _PR_ClockInterrupt();
  errno = olderrno;

  /*
  ** If the interrupt wants a resched or if some other thread at
  ** the same priority needs the cpu, reschedule.
  */

  pri = me->priority;
  if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) {
#  ifdef _PR_NO_PREEMPT
    cpu->resched = PR_TRUE;
    if (pr_interruptSwitchHook) {
      (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg);
    }
#  else  /* _PR_NO_PREEMPT */
    /*
    ** Re-enable unix interrupts (so that we can use
    ** setjmp/longjmp for context switching without having to
    ** worry about the signal state)
    */

    sigprocmask(SIG_SETMASK, &empty_set, 0);
    PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch"));

    if (!(me->flags & _PR_IDLE_THREAD)) {
      _PR_THREAD_LOCK(me);
      me->state = _PR_RUNNABLE;
      me->cpu = cpu;
      _PR_RUNQ_LOCK(cpu);
      _PR_ADD_RUNQ(me, cpu, pri);
      _PR_RUNQ_UNLOCK(cpu);
      _PR_THREAD_UNLOCK(me);
    } else {
      me->state = _PR_RUNNABLE;
    }
    _MD_SWITCH_CONTEXT(me);
    PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch"));
#  endif /* _PR_NO_PREEMPT */
  }
  /*
   * Because this thread could be running on a different cpu after
   * a context switch the current cpu should be accessed and the
   * value of the 'cpu' variable should not be used.
   */

  _PR_MD_SET_INTSOFF(0);
}

/* # of milliseconds per clock tick that we will use */
#  define MSEC_PER_TICK 50

void _MD_StartInterrupts() {
  char* eval;

  if ((eval = getenv("NSPR_NOCLOCK")) != NULL) {
    if (atoi(eval) == 0) {
      _nspr_noclock = 0;
    } else {
      _nspr_noclock = 1;
    }
  }

#  ifndef _PR_NO_CLOCK_TIMER
  if (!_nspr_noclock) {
    _MD_EnableClockInterrupts();
  }
#  endif
}

void _MD_StopInterrupts() { sigprocmask(SIG_BLOCK, &timer_set, 0); }

void _MD_EnableClockInterrupts() {
  struct itimerval itval;
  extern PRUintn _pr_numCPU;
  struct sigaction vtact;

  vtact.sa_handler = (void (*)())ClockInterruptHandler;
  sigemptyset(&vtact.sa_mask);
  vtact.sa_flags = SA_RESTART;
  sigaction(SIGALRM, &vtact, 0);

  PR_ASSERT(_pr_numCPU == 1);
  itval.it_interval.tv_sec = 0;
  itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC;
  itval.it_value = itval.it_interval;
  setitimer(ITIMER_REAL, &itval, 0);
}

void _MD_DisableClockInterrupts() {
  struct itimerval itval;
  extern PRUintn _pr_numCPU;

  PR_ASSERT(_pr_numCPU == 1);
  itval.it_interval.tv_sec = 0;
  itval.it_interval.tv_usec = 0;
  itval.it_value = itval.it_interval;
  setitimer(ITIMER_REAL, &itval, 0);
}

void _MD_BlockClockInterrupts() { sigprocmask(SIG_BLOCK, &timer_set, 0); }

void _MD_UnblockClockInterrupts() { sigprocmask(SIG_UNBLOCK, &timer_set, 0); }

void _MD_MakeNonblock(PRFileDesc* fd) {
  PRInt32 osfd = fd->secret->md.osfd;
  int flags;

  if (osfd <= 2) {
    /* Don't mess around with stdin, stdout or stderr */
    return;
  }
  flags = fcntl(osfd, F_GETFL, 0);

  /*
   * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible.
   * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O),
   * otherwise connect() still blocks and can be interrupted by SIGALRM.
   */


  fcntl(osfd, F_SETFL, flags | O_NONBLOCK);
}

PRInt32 _MD_open(const char* name, PRIntn flags, PRIntn mode) {
  PRInt32 osflags;
  PRInt32 rv, err;

  if (flags & PR_RDWR) {
    osflags = O_RDWR;
  } else if (flags & PR_WRONLY) {
    osflags = O_WRONLY;
  } else {
    osflags = O_RDONLY;
  }

  if (flags & PR_EXCL) {
    osflags |= O_EXCL;
  }
  if (flags & PR_APPEND) {
    osflags |= O_APPEND;
  }
  if (flags & PR_TRUNCATE) {
    osflags |= O_TRUNC;
  }
  if (flags & PR_SYNC) {
#  if defined(O_SYNC)
    osflags |= O_SYNC;
#  elif defined(O_FSYNC)
    osflags |= O_FSYNC;
#  else
#    error "Neither O_SYNC nor O_FSYNC is defined on this platform"
#  endif
  }

  /*
  ** On creations we hold the 'create' lock in order to enforce
  ** the semantics of PR_Rename. (see the latter for more details)
  */

  if (flags & PR_CREATE_FILE) {
    osflags |= O_CREAT;
    if (NULL != _pr_unix_rename_lock) {
      PR_Lock(_pr_unix_rename_lock);
    }
  }

#  if defined(ANDROID)
  osflags |= O_LARGEFILE;
#  endif

  rv = _md_iovector._open64(name, osflags, mode);

  if (rv < 0) {
    err = _MD_ERRNO();
    _PR_MD_MAP_OPEN_ERROR(err);
  }

  if ((flags & PR_CREATE_FILE) && (NULL != _pr_unix_rename_lock)) {
    PR_Unlock(_pr_unix_rename_lock);
  }
  return rv;
}

PRIntervalTime intr_timeout_ticks;

#  if defined(SOLARIS)
static void sigsegvhandler() {
  fprintf(stderr, "Received SIGSEGV\n");
  fflush(stderr);
  pause();
}

static void sigaborthandler() {
  fprintf(stderr, "Received SIGABRT\n");
  fflush(stderr);
  pause();
}

static void sigbushandler() {
  fprintf(stderr, "Received SIGBUS\n");
  fflush(stderr);
  pause();
}
#  endif /* SOLARIS */

#endif /* !defined(_PR_PTHREADS) */

void _MD_query_fd_inheritable(PRFileDesc* fd) {
  int flags;

  PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
  flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
  PR_ASSERT(-1 != flags);
  fd->secret->inheritable = (flags & FD_CLOEXEC) ? _PR_TRI_FALSE : _PR_TRI_TRUE;
}

PROffset32 _MD_lseek(PRFileDesc* fd, PROffset32 offset, PRSeekWhence whence) {
  PROffset32 rv, where;

  switch (whence) {
    case PR_SEEK_SET:
      where = SEEK_SET;
      break;
    case PR_SEEK_CUR:
      where = SEEK_CUR;
      break;
    case PR_SEEK_END:
      where = SEEK_END;
      break;
    default:
      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
      rv = -1;
      goto done;
  }
  rv = lseek(fd->secret->md.osfd, offset, where);
  if (rv == -1) {
    PRInt32 syserr = _MD_ERRNO();
    _PR_MD_MAP_LSEEK_ERROR(syserr);
  }
done:
  return (rv);
}

PROffset64 _MD_lseek64(PRFileDesc* fd, PROffset64 offset, PRSeekWhence whence) {
  PRInt32 where;
  PROffset64 rv;

  switch (whence) {
    case PR_SEEK_SET:
      where = SEEK_SET;
      break;
    case PR_SEEK_CUR:
      where = SEEK_CUR;
      break;
    case PR_SEEK_END:
      where = SEEK_END;
      break;
    default:
      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
      rv = minus_one;
      goto done;
  }
  rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where);
  if (LL_EQ(rv, minus_one)) {
    PRInt32 syserr = _MD_ERRNO();
    _PR_MD_MAP_LSEEK_ERROR(syserr);
  }
done:
  return rv;
/* _MD_lseek64 */

/*
** _MD_set_fileinfo_times --
**     Set the modifyTime and creationTime of the PRFileInfo
**     structure using the values in struct stat.
**
** _MD_set_fileinfo64_times --
**     Set the modifyTime and creationTime of the PRFileInfo64
**     structure using the values in _MDStat64.
*/


#if defined(_PR_STAT_HAS_ST_ATIM)
/*
** struct stat has st_atim, st_mtim, and st_ctim fields of
** type timestruc_t.
*/

static void _MD_set_fileinfo_times(const struct stat* sb, PRFileInfo* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtim.tv_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtim.tv_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctim.tv_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctim.tv_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}

static void _MD_set_fileinfo64_times(const _MDStat64* sb, PRFileInfo64* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtim.tv_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtim.tv_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctim.tv_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctim.tv_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}
#elif defined(_PR_STAT_HAS_ST_ATIM_UNION)
/*
** The st_atim, st_mtim, and st_ctim fields in struct stat are
** unions with a st__tim union member of type timestruc_t.
*/

static void _MD_set_fileinfo_times(const struct stat* sb, PRFileInfo* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}

static void _MD_set_fileinfo64_times(const _MDStat64* sb, PRFileInfo64* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}
#elif defined(_PR_STAT_HAS_ST_ATIMESPEC)
/*
** struct stat has st_atimespec, st_mtimespec, and st_ctimespec
** fields of type struct timespec.
*/

#  if defined(_PR_TIMESPEC_HAS_TS_SEC)
static void _MD_set_fileinfo_times(const struct stat* sb, PRFileInfo* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}

static void _MD_set_fileinfo64_times(const _MDStat64* sb, PRFileInfo64* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}
#  else  /* _PR_TIMESPEC_HAS_TS_SEC */
/*
** The POSIX timespec structure has tv_sec and tv_nsec.
*/

static void _MD_set_fileinfo_times(const struct stat* sb, PRFileInfo* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}

static void _MD_set_fileinfo64_times(const _MDStat64* sb, PRFileInfo64* info) {
  PRInt64 us, s2us;

  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec);
  LL_MUL(info->modifyTime, info->modifyTime, s2us);
  LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000);
  LL_ADD(info->modifyTime, info->modifyTime, us);
  LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec);
  LL_MUL(info->creationTime, info->creationTime, s2us);
  LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000);
  LL_ADD(info->creationTime, info->creationTime, us);
}
#  endif /* _PR_TIMESPEC_HAS_TS_SEC */
#elif defined(_PR_STAT_HAS_ONLY_ST_ATIME)
/*
** struct stat only has st_atime, st_mtime, and st_ctime fields
** of type time_t.
*/

static void _MD_set_fileinfo_times(const struct stat* sb, PRFileInfo* info) {
  PRInt64 s, s2us;
  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(s, sb->st_mtime);
  LL_MUL(s, s, s2us);
  info->modifyTime = s;
  LL_I2L(s, sb->st_ctime);
  LL_MUL(s, s, s2us);
  info->creationTime = s;
}

static void _MD_set_fileinfo64_times(const _MDStat64* sb, PRFileInfo64* info) {
  PRInt64 s, s2us;
  LL_I2L(s2us, PR_USEC_PER_SEC);
  LL_I2L(s, sb->st_mtime);
  LL_MUL(s, s, s2us);
  info->modifyTime = s;
  LL_I2L(s, sb->st_ctime);
  LL_MUL(s, s, s2us);
  info->creationTime = s;
}
#else
#  error "I don't know yet"
#endif

static int _MD_convert_stat_to_fileinfo(const struct stat* sb,
                                        PRFileInfo* info) {
  if (S_IFREG & sb->st_mode) {
    info->type = PR_FILE_FILE;
  } else if (S_IFDIR & sb->st_mode) {
    info->type = PR_FILE_DIRECTORY;
  } else {
    info->type = PR_FILE_OTHER;
  }

#if defined(_PR_HAVE_LARGE_OFF_T)
  if (0x7fffffffL < sb->st_size) {
    PR_SetError(PR_FILE_TOO_BIG_ERROR, 0);
    return -1;
  }
#endif /* defined(_PR_HAVE_LARGE_OFF_T) */
  info->size = sb->st_size;

  _MD_set_fileinfo_times(sb, info);
  return 0;
/* _MD_convert_stat_to_fileinfo */

static int _MD_convert_stat64_to_fileinfo64(const _MDStat64* sb,
                                            PRFileInfo64* info) {
  if (S_IFREG & sb->st_mode) {
    info->type = PR_FILE_FILE;
  } else if (S_IFDIR & sb->st_mode) {
    info->type = PR_FILE_DIRECTORY;
  } else {
    info->type = PR_FILE_OTHER;
  }

  LL_I2L(info->size, sb->st_size);

  _MD_set_fileinfo64_times(sb, info);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=90 G=91

¤ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.