Blame src/npth.c

Packit 5e354d
/* npth.c - a lightweight implementation of pth over pthread.
Packit 5e354d
 * Copyright (C) 2011 g10 Code GmbH
Packit 5e354d
 *
Packit 5e354d
 * This file is part of nPth.
Packit 5e354d
 *
Packit 5e354d
 * nPth is free software; you can redistribute it and/or modify
Packit 5e354d
 * it under the terms of the GNU Lesser General Public License as
Packit 5e354d
 * published by the Free Software Foundation; either version 2.1 of
Packit 5e354d
 * the License, or (at your option) any later version.
Packit 5e354d
 *
Packit 5e354d
 * nPth is distributed in the hope that it will be useful, but
Packit 5e354d
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5e354d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
Packit 5e354d
 * the GNU Lesser General Public License for more details.
Packit 5e354d
 *
Packit 5e354d
 * You should have received a copy of the GNU Lesser General Public
Packit 5e354d
 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit 5e354d
 */
Packit 5e354d
Packit 5e354d
#ifdef HAVE_CONFIG_H
Packit 5e354d
#include <config.h>
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
#include <stdlib.h>
Packit 5e354d
#include <stdio.h>
Packit 5e354d
#include <string.h>
Packit 5e354d
#include <assert.h>
Packit 5e354d
#include <errno.h>
Packit 5e354d
#include <pthread.h>
Packit 5e354d
#include <fcntl.h>
Packit 5e354d
#include <sys/stat.h>
Packit 5e354d
#ifdef HAVE_LIB_DISPATCH
Packit 5e354d
# include <dispatch/dispatch.h>
Packit 5e354d
typedef dispatch_semaphore_t sem_t;
Packit 5e354d
Packit 5e354d
/* This glue code is for macOS which does not have full implementation
Packit 5e354d
   of POSIX semaphore.  On macOS, using semaphore in Grand Central
Packit 5e354d
   Dispatch library is better than using the partial implementation of
Packit 5e354d
   POSIX semaphore where sem_init doesn't work well.
Packit 5e354d
 */
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
sem_init (sem_t *sem, int is_shared, unsigned int value)
Packit 5e354d
{
Packit 5e354d
  (void)is_shared;
Packit 5e354d
  if ((*sem = dispatch_semaphore_create (value)) == NULL)
Packit 5e354d
    return -1;
Packit 5e354d
  else
Packit 5e354d
    return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
sem_post (sem_t *sem)
Packit 5e354d
{
Packit 5e354d
  dispatch_semaphore_signal (*sem);
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
sem_wait (sem_t *sem)
Packit 5e354d
{
Packit 5e354d
  dispatch_semaphore_wait (*sem, DISPATCH_TIME_FOREVER);
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
#else
Packit 5e354d
# include <semaphore.h>
Packit 5e354d
#endif
Packit 5e354d
#ifdef HAVE_UNISTD_H
Packit 5e354d
# include <unistd.h>
Packit 5e354d
#endif
Packit 5e354d
#ifndef HAVE_PSELECT
Packit 5e354d
# include <signal.h>
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
#include "npth.h"
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* The global lock that excludes all threads but one.  This is a
Packit 5e354d
   semaphore, because these can be safely used in a library even if
Packit 5e354d
   the application or other libraries call fork(), including from a
Packit 5e354d
   signal handler.  sem_post is async-signal-safe.  (The reason a
Packit 5e354d
   semaphore is safe and a mutex is not safe is that a mutex has an
Packit 5e354d
   owner, while a semaphore does not.)  We init sceptre to a static
Packit 5e354d
   buffer for use by sem_init; in case sem_open is used instead
Packit 5e354d
   SCEPTRE will changed to the value returned by sem_open.
Packit 5e354d
   GOT_SCEPTRE is a flag used for debugging to tell wether we hold
Packit 5e354d
   SCEPTRE.  */
Packit 5e354d
static sem_t sceptre_buffer;
Packit 5e354d
static sem_t *sceptre = &sceptre_buffer;
Packit 5e354d
static int got_sceptre;
Packit 5e354d
Packit 5e354d
/* Configure defines HAVE_FORK_UNSAFE_SEMAPHORE if child process can't
Packit 5e354d
   access non-shared unnamed semaphore which is created by its parent.
Packit 5e354d
Packit 5e354d
   We use unnamed semaphore (if available) for the global lock.  The
Packit 5e354d
   specific semaphore is only valid for those threads in a process,
Packit 5e354d
   and it is no use by other processes.  Thus, PSHARED argument for
Packit 5e354d
   sem_init is naturally 0.
Packit 5e354d
Packit 5e354d
   However, there are daemon-like applications which use fork after
Packit 5e354d
   npth's initialization by npth_init.  In this case, a child process
Packit 5e354d
   uses the semaphore which was created by its parent process, while
Packit 5e354d
   parent does nothing with the semaphore.  In some system (e.g. AIX),
Packit 5e354d
   access by child process to non-shared unnamed semaphore is
Packit 5e354d
   prohibited.  For such a system, HAVE_FORK_UNSAFE_SEMAPHORE should
Packit 5e354d
   be defined, so that unnamed semaphore will be created with the
Packit 5e354d
   option PSHARED=1.  The purpose of the setting of PSHARED=1 is only
Packit 5e354d
   for allowing the access of the lock by child process.  For NPTH, it
Packit 5e354d
   does not mean any other interactions between processes.
Packit 5e354d
Packit 5e354d
 */
Packit 5e354d
#ifdef HAVE_FORK_UNSAFE_SEMAPHORE
Packit 5e354d
#define NPTH_SEMAPHORE_PSHARED 1
Packit 5e354d
#else
Packit 5e354d
#define NPTH_SEMAPHORE_PSHARED 0
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
/* The main thread is the active thread at the time pth_init was
Packit 5e354d
   called.  As of now it is only useful for debugging.  The volatile
Packit 5e354d
   make sure the compiler does not eliminate this set but not used
Packit 5e354d
   variable.  */
Packit 5e354d
static volatile pthread_t main_thread;
Packit 5e354d
Packit 5e354d
/* This flag is set as soon as npth_init has been called or if any
Packit 5e354d
 * thread has been created.  It will never be cleared again.  The only
Packit 5e354d
 * purpose is to make npth_protect and npth_unprotect more robust in
Packit 5e354d
 * that they can be shortcut when npth_init has not yet been called.
Packit 5e354d
 * This is important for libraries which want to support nPth by using
Packit 5e354d
 * those two functions but may have be initialized before pPth. */
Packit 5e354d
static int initialized_or_any_threads;
Packit 5e354d
Packit 5e354d
/* Systems that don't have pthread_mutex_timedlock get a busy wait
Packit 5e354d
   implementation that probes the lock every BUSY_WAIT_INTERVAL
Packit 5e354d
   milliseconds.  */
Packit 5e354d
#define BUSY_WAIT_INTERVAL 200
Packit 5e354d
Packit 5e354d
typedef int (*trylock_func_t) (void *);
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
busy_wait_for (trylock_func_t trylock, void *lock,
Packit 5e354d
	       const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  /* This is not great, but better than nothing.  Only works for locks
Packit 5e354d
     which are mostly uncontested.  Provides absolutely no fairness at
Packit 5e354d
     all.  Creates many wake-ups.  */
Packit 5e354d
  while (1)
Packit 5e354d
    {
Packit 5e354d
      struct timespec ts;
Packit 5e354d
      err = npth_clock_gettime (&ts);
Packit 5e354d
      if (err < 0)
Packit 5e354d
	{
Packit 5e354d
	  /* Just for safety make sure we return some error.  */
Packit 5e354d
	  err = errno ? errno : EINVAL;
Packit 5e354d
	  break;
Packit 5e354d
	}
Packit 5e354d
Packit 5e354d
      if (npth_timercmp (abstime, &ts, <))
Packit 5e354d
	{
Packit 5e354d
	  err = ETIMEDOUT;
Packit 5e354d
	  break;
Packit 5e354d
	}
Packit 5e354d
Packit 5e354d
      err = (*trylock) (lock);
Packit 5e354d
      if (err != EBUSY)
Packit 5e354d
	break;
Packit 5e354d
Packit 5e354d
      /* Try again after waiting a bit.  We could calculate the
Packit 5e354d
	 maximum wait time from ts and abstime, but we don't
Packit 5e354d
	 bother, as our granularity is pretty fine.  */
Packit 5e354d
      usleep (BUSY_WAIT_INTERVAL * 1000);
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
static void
Packit 5e354d
enter_npth (void)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  got_sceptre = 0;
Packit 5e354d
  res = sem_post (sceptre);
Packit 5e354d
  assert (res == 0);
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static void
Packit 5e354d
leave_npth (void)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
  int save_errno = errno;
Packit 5e354d
Packit 5e354d
  do {
Packit 5e354d
    res = sem_wait (sceptre);
Packit 5e354d
  } while (res < 0 && errno == EINTR);
Packit 5e354d
Packit 5e354d
  assert (!res);
Packit 5e354d
  got_sceptre = 1;
Packit 5e354d
  errno = save_errno;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
#define ENTER() enter_npth ()
Packit 5e354d
#define LEAVE() leave_npth ()
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_init (void)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  main_thread = pthread_self();
Packit 5e354d
Packit 5e354d
  /* Track that we have been initialized.  */
Packit 5e354d
  initialized_or_any_threads |= 1;
Packit 5e354d
Packit 5e354d
  /* Better reset ERRNO so that we know that it has been set by
Packit 5e354d
     sem_init.  */
Packit 5e354d
  errno = 0;
Packit 5e354d
Packit 5e354d
  /* The semaphore is binary.  */
Packit 5e354d
  res = sem_init (sceptre, NPTH_SEMAPHORE_PSHARED, 1);
Packit 5e354d
  /* There are some versions of operating systems which have sem_init
Packit 5e354d
     symbol defined but the call actually returns ENOSYS at runtime.
Packit 5e354d
     We know this problem for older versions of AIX (<= 4.3.3) and
Packit 5e354d
     macOS.  For macOS, we use semaphore in Grand Central Dispatch
Packit 5e354d
     library, so ENOSYS doesn't happen.  We only support AIX >= 5.2,
Packit 5e354d
     where sem_init is supported.
Packit 5e354d
   */
Packit 5e354d
  if (res < 0)
Packit 5e354d
    {
Packit 5e354d
      /* POSIX.1-2001 defines the semaphore interface but does not
Packit 5e354d
         specify the return value for success.  Thus we better
Packit 5e354d
         bail out on error only on a POSIX.1-2008 system.  */
Packit 5e354d
#if _POSIX_C_SOURCE >= 200809L
Packit 5e354d
      return errno;
Packit 5e354d
#endif
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  LEAVE();
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_getname_np (npth_t target_thread, char *buf, size_t buflen)
Packit 5e354d
{
Packit 5e354d
#ifdef HAVE_PTHREAD_GETNAME_NP
Packit 5e354d
  return pthread_getname_np (target_thread, buf, buflen);
Packit 5e354d
#else
Packit 5e354d
  (void)target_thread;
Packit 5e354d
  (void)buf;
Packit 5e354d
  (void)buflen;
Packit 5e354d
  return ENOSYS;
Packit 5e354d
#endif
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_setname_np (npth_t target_thread, const char *name)
Packit 5e354d
{
Packit 5e354d
#ifdef HAVE_PTHREAD_SETNAME_NP
Packit 5e354d
#ifdef __NetBSD__
Packit 5e354d
  return pthread_setname_np (target_thread, "%s", (void*) name);
Packit 5e354d
#else
Packit 5e354d
#ifdef __APPLE__
Packit 5e354d
  if (target_thread == npth_self ())
Packit 5e354d
    return pthread_setname_np (name);
Packit 5e354d
  else
Packit 5e354d
    return ENOTSUP;
Packit 5e354d
#else
Packit 5e354d
  return pthread_setname_np (target_thread, name);
Packit 5e354d
#endif
Packit 5e354d
#endif
Packit 5e354d
#else
Packit 5e354d
  (void)target_thread;
Packit 5e354d
  (void)name;
Packit 5e354d
  return ENOSYS;
Packit 5e354d
#endif
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct startup_s
Packit 5e354d
{
Packit 5e354d
  void *(*start_routine) (void *);
Packit 5e354d
  void *arg;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
static void *
Packit 5e354d
thread_start (void *startup_arg)
Packit 5e354d
{
Packit 5e354d
  struct startup_s *startup = startup_arg;
Packit 5e354d
  void *(*start_routine) (void *);
Packit 5e354d
  void *arg;
Packit 5e354d
  void *result;
Packit 5e354d
Packit 5e354d
  start_routine = startup->start_routine;
Packit 5e354d
  arg = startup->arg;
Packit 5e354d
  free (startup);
Packit 5e354d
Packit 5e354d
  LEAVE();
Packit 5e354d
  result = (*start_routine) (arg);
Packit 5e354d
  /* Note: instead of returning here, we might end up in
Packit 5e354d
     npth_exit() instead.  */
Packit 5e354d
  ENTER();
Packit 5e354d
Packit 5e354d
  return result;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_create (npth_t *thread, const npth_attr_t *attr,
Packit 5e354d
	     void *(*start_routine) (void *), void *arg)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  struct startup_s *startup;
Packit 5e354d
Packit 5e354d
  startup = malloc (sizeof (*startup));
Packit 5e354d
  if (!startup)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  initialized_or_any_threads |= 2;
Packit 5e354d
Packit 5e354d
  startup->start_routine = start_routine;
Packit 5e354d
  startup->arg = arg;
Packit 5e354d
  err = pthread_create (thread, attr, thread_start, startup);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      free (startup);
Packit 5e354d
      return err;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* Memory is released in thread_start.  */
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_join (npth_t thread, void **retval)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
#ifdef HAVE_PTHREAD_TRYJOIN_NP
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  pthread_tryjoin_np is a GNU extension.  */
Packit 5e354d
  err = pthread_tryjoin_np (thread, retval);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
#endif /*HAVE_PTHREAD_TRYJOIN_NP*/
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = pthread_join (thread, retval);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
void
Packit 5e354d
npth_exit (void *retval)
Packit 5e354d
{
Packit 5e354d
  ENTER();
Packit 5e354d
  pthread_exit (retval);
Packit 5e354d
  /* Never reached.  But just in case pthread_exit does return... */
Packit 5e354d
  LEAVE();
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
int
Packit 5e354d
npth_mutex_lock (npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = pthread_mutex_trylock (mutex);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = pthread_mutex_lock (mutex);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutex_timedlock (npth_mutex_t *mutex, const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = pthread_mutex_trylock (mutex);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
#if HAVE_PTHREAD_MUTEX_TIMEDLOCK
Packit 5e354d
  err = pthread_mutex_timedlock (mutex, abstime);
Packit 5e354d
#else
Packit 5e354d
  err = busy_wait_for ((trylock_func_t) pthread_mutex_trylock, mutex, abstime);
Packit 5e354d
#endif
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
#ifndef _NPTH_NO_RWLOCK
Packit 5e354d
int
Packit 5e354d
npth_rwlock_rdlock (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
#ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = pthread_rwlock_tryrdlock (rwlock);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = pthread_rwlock_rdlock (rwlock);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_timedrdlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
#ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = pthread_rwlock_tryrdlock (rwlock);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
#if HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
Packit 5e354d
  err = pthread_rwlock_timedrdlock (rwlock, abstime);
Packit 5e354d
#else
Packit 5e354d
  err = busy_wait_for ((trylock_func_t) pthread_rwlock_tryrdlock, rwlock,
Packit 5e354d
		       abstime);
Packit 5e354d
#endif
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_wrlock (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
#ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = pthread_rwlock_trywrlock (rwlock);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = pthread_rwlock_wrlock (rwlock);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_timedwrlock (npth_rwlock_t *rwlock, const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
#ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = pthread_rwlock_trywrlock (rwlock);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
#if HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
Packit 5e354d
  err = pthread_rwlock_timedwrlock (rwlock, abstime);
Packit 5e354d
#elif HAVE_PTHREAD_RWLOCK_TRYRDLOCK
Packit 5e354d
  err = busy_wait_for ((trylock_func_t) pthread_rwlock_trywrlock, rwlock,
Packit 5e354d
		       abstime);
Packit 5e354d
#else
Packit 5e354d
  err = ENOSYS;
Packit 5e354d
#endif
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_cond_wait (npth_cond_t *cond, npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = pthread_cond_wait (cond, mutex);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_cond_timedwait (npth_cond_t *cond, npth_mutex_t *mutex,
Packit 5e354d
		     const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = pthread_cond_timedwait (cond, mutex, abstime);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
/* Standard POSIX Replacement API */
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_usleep(unsigned int usec)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = usleep(usec);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
unsigned int
Packit 5e354d
npth_sleep(unsigned int sec)
Packit 5e354d
{
Packit 5e354d
  unsigned res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = sleep(sec);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_system(const char *cmd)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = system(cmd);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
pid_t
Packit 5e354d
npth_waitpid(pid_t pid, int *status, int options)
Packit 5e354d
{
Packit 5e354d
  pid_t res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = waitpid(pid,status, options);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_connect(int s, const struct sockaddr *addr, socklen_t addrlen)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = connect(s, addr, addrlen);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = accept(s, addr, addrlen);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_select(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
Packit 5e354d
	    struct timeval *timeout)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = select(nfd, rfds, wfds, efds, timeout);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_pselect(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
Packit 5e354d
	     const struct timespec *timeout, const sigset_t *sigmask)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
#ifdef HAVE_PSELECT
Packit 5e354d
  res = pselect (nfd, rfds, wfds, efds, timeout, sigmask);
Packit 5e354d
#else /*!HAVE_PSELECT*/
Packit 5e354d
  {
Packit 5e354d
    /* A better emulation of pselect would be to create a pipe, wait
Packit 5e354d
       in the select for one end and have a signal handler write to
Packit 5e354d
       the other end.  However, this is non-trivial to implement and
Packit 5e354d
       thus we only print a compile time warning.  */
Packit 5e354d
#   ifdef __GNUC__
Packit 5e354d
#     warning Using a non race free pselect emulation.
Packit 5e354d
#   endif
Packit 5e354d
Packit 5e354d
    struct timeval t, *tp;
Packit 5e354d
Packit 5e354d
    tp = NULL;
Packit 5e354d
    if (!timeout)
Packit 5e354d
      ;
Packit 5e354d
    else if (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000)
Packit 5e354d
      {
Packit 5e354d
        t.tv_sec = timeout->tv_sec;
Packit 5e354d
        t.tv_usec = (timeout->tv_nsec + 999) / 1000;
Packit 5e354d
        tp = &t;
Packit 5e354d
      }
Packit 5e354d
    else
Packit 5e354d
      {
Packit 5e354d
        errno = EINVAL;
Packit 5e354d
        res = -1;
Packit 5e354d
        goto leave;
Packit 5e354d
      }
Packit 5e354d
Packit 5e354d
    if (sigmask)
Packit 5e354d
      {
Packit 5e354d
        int save_errno;
Packit 5e354d
        sigset_t savemask;
Packit 5e354d
Packit 5e354d
        pthread_sigmask (SIG_SETMASK, sigmask, &savemask);
Packit 5e354d
        res = select (nfd, rfds, wfds, efds, tp);
Packit 5e354d
        save_errno = errno;
Packit 5e354d
        pthread_sigmask (SIG_SETMASK, &savemask, NULL);
Packit 5e354d
        errno = save_errno;
Packit 5e354d
      }
Packit 5e354d
    else
Packit 5e354d
      res = select (nfd, rfds, wfds, efds, tp);
Packit 5e354d
Packit 5e354d
  leave:
Packit 5e354d
    ;
Packit 5e354d
  }
Packit 5e354d
#endif /*!HAVE_PSELECT*/
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
ssize_t
Packit 5e354d
npth_read(int fd, void *buf, size_t nbytes)
Packit 5e354d
{
Packit 5e354d
  ssize_t res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = read(fd, buf, nbytes);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
ssize_t
Packit 5e354d
npth_write(int fd, const void *buf, size_t nbytes)
Packit 5e354d
{
Packit 5e354d
  ssize_t res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = write(fd, buf, nbytes);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_recvmsg (int fd, struct msghdr *msg, int flags)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = recvmsg (fd, msg, flags);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_sendmsg (int fd, const struct msghdr *msg, int flags)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  res = sendmsg (fd, msg, flags);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return res;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
void
Packit 5e354d
npth_unprotect (void)
Packit 5e354d
{
Packit 5e354d
  /* If we are not initialized we may not access the semaphore and
Packit 5e354d
   * thus we shortcut it. Note that in this case the unprotect/protect
Packit 5e354d
   * is not needed.  For failsafe reasons if an nPth thread has ever
Packit 5e354d
   * been created but nPth has accidentally not initialized we do not
Packit 5e354d
   * shortcut so that a stack backtrace (due to the access of the
Packit 5e354d
   * uninitialized semaphore) is more expressive.  */
Packit 5e354d
  if (initialized_or_any_threads)
Packit 5e354d
    ENTER();
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
void
Packit 5e354d
npth_protect (void)
Packit 5e354d
{
Packit 5e354d
  /* See npth_unprotect for commentary.  */
Packit 5e354d
  if (initialized_or_any_threads)
Packit 5e354d
    LEAVE();
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_is_protected (void)
Packit 5e354d
{
Packit 5e354d
  return got_sceptre;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_clock_gettime (struct timespec *ts)
Packit 5e354d
{
Packit 5e354d
#if defined(CLOCK_REALTIME) && HAVE_CLOCK_GETTIME
Packit 5e354d
  return clock_gettime (CLOCK_REALTIME, ts);
Packit 5e354d
#elif HAVE_GETTIMEOFDAY
Packit 5e354d
  {
Packit 5e354d
    struct timeval tv;
Packit 5e354d
Packit 5e354d
    if (gettimeofday (&tv, NULL))
Packit 5e354d
      return -1;
Packit 5e354d
    ts->tv_sec = tv.tv_sec;
Packit 5e354d
    ts->tv_nsec = tv.tv_usec * 1000;
Packit 5e354d
    return 0;
Packit 5e354d
  }
Packit 5e354d
#else
Packit 5e354d
  /* FIXME: fall back on time() with seconds resolution.  */
Packit 5e354d
# error clock_gettime not available - please provide a fallback.
Packit 5e354d
#endif
Packit 5e354d
}