Blame w32/npth.c

Packit 5e354d
/* npth.c - a lightweight implementation of pth over native threads
Packit 5e354d
 * Copyright (C) 2011, 2014 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
/* We implement the join mechanism ourself.  */
Packit 5e354d
Packit 5e354d
#ifdef HAVE_CONFIG_H
Packit 5e354d
#include <config.h>
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
#include <assert.h>
Packit 5e354d
#include <errno.h>
Packit 5e354d
#include <io.h>
Packit 5e354d
Packit 5e354d
#include "npth.h"
Packit 5e354d
Packit 5e354d
#include <stdio.h>
Packit 5e354d
#define DEBUG_CALLS 1
Packit 5e354d
#define _npth_debug(x, ...) fprintf(stderr, __VA_ARGS__)
Packit 5e354d
Packit 5e354d
#ifndef TEST
Packit 5e354d
#undef  DEBUG_CALLS
Packit 5e354d
#define DEBUG_CALLS 0
Packit 5e354d
#undef _npth_debug
Packit 5e354d
#define _npth_debug(x, ...)
Packit 5e354d
#endif
Packit 5e354d
Packit 5e354d
/* This seems to be a common standard.  */
Packit 5e354d
#define THREAD_NAME_MAX 15
Packit 5e354d
Packit 5e354d
/* The global lock that excludes all threads but one.  Note that this
Packit 5e354d
   implements the single-user-thread policy, but also protects all our
Packit 5e354d
   global data such as the thread_table.  GOT_SCEPTRE is a flag used
Packit 5e354d
   for debugging to tell wether we hold SCEPTRE.  */
Packit 5e354d
static CRITICAL_SECTION sceptre;
Packit 5e354d
static int got_sceptre;
Packit 5e354d
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 been initialized before nPth. */
Packit 5e354d
static int initialized_or_any_threads;
Packit 5e354d
Packit 5e354d
Packit 5e354d
typedef struct npth_impl_s *npth_impl_t;
Packit 5e354d
#define MAX_THREADS 1024
Packit 5e354d
#define INVALID_THREAD_ID 0
Packit 5e354d
/* Thread ID to thread context table.  We never allocate ID 0.  */
Packit 5e354d
static npth_impl_t thread_table[MAX_THREADS];
Packit 5e354d
Packit 5e354d
/* The TLS index to store thread ID of the current thread.  Used to
Packit 5e354d
   make faster lookups of the thread data.  */
Packit 5e354d
DWORD tls_index;
Packit 5e354d
Packit 5e354d
Packit 5e354d

Packit 5e354d
/* Map a windows error value (GetLastError) to a POSIX error value.  */
Packit 5e354d
static int
Packit 5e354d
map_error (int winerr)
Packit 5e354d
{
Packit 5e354d
  /* FIXME */
Packit 5e354d
  return EIO;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
wait_for_single_object (HANDLE obj, DWORD msecs)
Packit 5e354d
{
Packit 5e354d
  DWORD res;
Packit 5e354d
Packit 5e354d
  res = WaitForSingleObject(obj, msecs);
Packit 5e354d
Packit 5e354d
  if (res == WAIT_ABANDONED)
Packit 5e354d
    return EDEADLK;
Packit 5e354d
  else if (res == WAIT_TIMEOUT)
Packit 5e354d
    return ETIMEDOUT;
Packit 5e354d
  else if (res == WAIT_FAILED)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
  else if (res != WAIT_OBJECT_0)
Packit 5e354d
    return EINTR;
Packit 5e354d
  else
Packit 5e354d
    return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
int
Packit 5e354d
npth_clock_gettime(struct timespec *tp)
Packit 5e354d
{
Packit 5e354d
  FILETIME ftime;
Packit 5e354d
  ULARGE_INTEGER systime;
Packit 5e354d
  unsigned long long usecs;
Packit 5e354d
Packit 5e354d
  GetSystemTimeAsFileTime (&ftime);
Packit 5e354d
  systime.LowPart = ftime.dwLowDateTime;
Packit 5e354d
  systime.HighPart = ftime.dwHighDateTime;
Packit 5e354d
Packit 5e354d
  /* systime.QuadPart has the 100-nanosecond intervals since Jan 1, 1601.  */
Packit 5e354d
  tp->tv_sec = systime.QuadPart / 10000000ULL;
Packit 5e354d
  tp->tv_nsec = (systime.QuadPart * 100ULL) % 1000000000ULL;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
calculate_timeout (const struct timespec *abstime, DWORD *msecs_r)
Packit 5e354d
{
Packit 5e354d
  struct timespec tp;
Packit 5e354d
  struct timespec tp_delta;
Packit 5e354d
  DWORD msecs;
Packit 5e354d
Packit 5e354d
  npth_clock_gettime (&tp);
Packit 5e354d
  /* Make sure there is a positive time delta.  */
Packit 5e354d
  if (!(npth_timercmp (&tp, abstime, <)))
Packit 5e354d
    return ETIMEDOUT;
Packit 5e354d
Packit 5e354d
  npth_timersub (abstime, &tp, &tp_delta);
Packit 5e354d
  /* Make sure to round up to at least one millisecond.  Note that
Packit 5e354d
     within reasonable timeouts and the above macros, we should always
Packit 5e354d
     end up with a positive wait time here.  */
Packit 5e354d
  msecs = (tp_delta.tv_sec * 1000) + (tp_delta.tv_nsec + 999999) / 1000000;
Packit 5e354d
  if (msecs < 1)
Packit 5e354d
    {
Packit 5e354d
      /* Log a critical error here.  */
Packit 5e354d
      return ETIMEDOUT;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  *msecs_r = msecs;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
static void
Packit 5e354d
enter_npth (const char *function)
Packit 5e354d
{
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  if (DEBUG_CALLS)
Packit 5e354d
    _npth_debug (DEBUG_CALLS, "tid %lu: enter_npth (%s)\n",
Packit 5e354d
		 npth_self (), function ? function : "unknown");
Packit 5e354d
  got_sceptre = 0;
Packit 5e354d
  LeaveCriticalSection (&sceptre);
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static void
Packit 5e354d
leave_npth (const char *function)
Packit 5e354d
{
Packit 5e354d
  EnterCriticalSection (&sceptre);
Packit 5e354d
  got_sceptre = 1;
Packit 5e354d
Packit 5e354d
  if (DEBUG_CALLS)
Packit 5e354d
    _npth_debug (DEBUG_CALLS, "tid %lu: leave_npth (%s)\n",
Packit 5e354d
		 npth_self (), function ? function : "");
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
#define ENTER() enter_npth(__FUNCTION__)
Packit 5e354d
#define LEAVE() leave_npth(__FUNCTION__)
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct npth_impl_s
Packit 5e354d
{
Packit 5e354d
  /* Usually there is one ref owned by the thread as long as it is
Packit 5e354d
     running, and one ref for everybody else as long as the thread is
Packit 5e354d
     joinable.  */
Packit 5e354d
  int refs;
Packit 5e354d
Packit 5e354d
  HANDLE handle;
Packit 5e354d
Packit 5e354d
  /* True if thread is detached.  */
Packit 5e354d
  int detached;
Packit 5e354d
Packit 5e354d
  /* The start routine and arg.  */
Packit 5e354d
  void *(*start_routine) (void *);
Packit 5e354d
  void *start_arg;
Packit 5e354d
Packit 5e354d
  char name[THREAD_NAME_MAX + 1];
Packit 5e354d
Packit 5e354d
  /* Doubly-linked list for the waiter queue in condition
Packit 5e354d
     variables.  */
Packit 5e354d
  npth_impl_t next;
Packit 5e354d
  npth_impl_t *prev_ptr;
Packit 5e354d
Packit 5e354d
  /* The event on which this thread waits when it is queued.  */
Packit 5e354d
  HANDLE event;
Packit 5e354d
Packit 5e354d
  void *result;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
static void
Packit 5e354d
dequeue_thread (npth_impl_t thread)
Packit 5e354d
{
Packit 5e354d
  /* Unlink the thread from any condition waiter queue.  */
Packit 5e354d
  if (thread->next)
Packit 5e354d
    {
Packit 5e354d
      thread->next->prev_ptr = thread->prev_ptr;
Packit 5e354d
      thread->next = NULL;
Packit 5e354d
    }
Packit 5e354d
  if (thread->prev_ptr)
Packit 5e354d
    {
Packit 5e354d
      *(thread->prev_ptr) = thread->next;
Packit 5e354d
      thread->prev_ptr = NULL;
Packit 5e354d
    }
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* Enqueue THREAD to come after the thread whose next pointer is
Packit 5e354d
   prev_ptr.  */
Packit 5e354d
static void
Packit 5e354d
enqueue_thread (npth_impl_t thread, npth_impl_t *prev_ptr)
Packit 5e354d
{
Packit 5e354d
  if (*prev_ptr)
Packit 5e354d
    (*prev_ptr)->prev_ptr = &thread->next;
Packit 5e354d
  thread->prev_ptr = prev_ptr;
Packit 5e354d
  thread->next = *prev_ptr;
Packit 5e354d
  *prev_ptr = thread;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
find_thread (npth_t thread_id, npth_impl_t *thread)
Packit 5e354d
{
Packit 5e354d
  if (thread_id < 1 || thread_id >= MAX_THREADS)
Packit 5e354d
    return ESRCH;
Packit 5e354d
Packit 5e354d
  if (! thread_table[thread_id])
Packit 5e354d
    return ESRCH;
Packit 5e354d
Packit 5e354d
  *thread = thread_table[thread_id];
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static int
Packit 5e354d
new_thread (npth_t *thread_id)
Packit 5e354d
{
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  int id;
Packit 5e354d
Packit 5e354d
  /* ID 0 is never allocated.  */
Packit 5e354d
  for (id = 1; id < MAX_THREADS; id++)
Packit 5e354d
    if (! thread_table[id])
Packit 5e354d
      break;
Packit 5e354d
  if (id == MAX_THREADS)
Packit 5e354d
    return EAGAIN;
Packit 5e354d
Packit 5e354d
  thread = malloc (sizeof (*thread));
Packit 5e354d
  if (! thread)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  thread->refs = 1;
Packit 5e354d
  thread->handle = INVALID_HANDLE_VALUE;
Packit 5e354d
  thread->detached = 0;
Packit 5e354d
  thread->start_routine = NULL;
Packit 5e354d
  thread->start_arg = NULL;
Packit 5e354d
  thread->next = NULL;
Packit 5e354d
  thread->prev_ptr = NULL;
Packit 5e354d
  /* We create the event when it is first needed (not all threads wait
Packit 5e354d
     on conditions).  */
Packit 5e354d
  thread->event = INVALID_HANDLE_VALUE;
Packit 5e354d
  memset (thread->name, '\0', sizeof (thread->name));
Packit 5e354d
Packit 5e354d
  thread_table[id] = thread;
Packit 5e354d
Packit 5e354d
  *thread_id = id;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static void
Packit 5e354d
free_thread (npth_t thread_id)
Packit 5e354d
{
Packit 5e354d
  npth_impl_t thread = thread_table[thread_id];
Packit 5e354d
Packit 5e354d
  if (thread->handle)
Packit 5e354d
    CloseHandle (thread->handle);
Packit 5e354d
Packit 5e354d
  /* Unlink the thread from any condition waiter queue.  */
Packit 5e354d
  dequeue_thread (thread);
Packit 5e354d
Packit 5e354d
  free (thread);
Packit 5e354d
Packit 5e354d
  thread_table[thread_id] = NULL;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static void
Packit 5e354d
deref_thread (npth_t thread_id)
Packit 5e354d
{
Packit 5e354d
  npth_impl_t thread = thread_table[thread_id];
Packit 5e354d
Packit 5e354d
  thread->refs -= 1;
Packit 5e354d
  if (thread->refs == 0)
Packit 5e354d
    free_thread (thread_id);
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d

Packit 5e354d
int
Packit 5e354d
npth_init (void)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_t thread_id;
Packit 5e354d
  BOOL res;
Packit 5e354d
  HANDLE handle;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
Packit 5e354d
  InitializeCriticalSection (&sceptre);
Packit 5e354d
Packit 5e354d
  /* Track that we have been initialized.  */
Packit 5e354d
  initialized_or_any_threads = 1;
Packit 5e354d
Packit 5e354d
  /* Fake a thread table item for the main thread.  */
Packit 5e354d
  tls_index = TlsAlloc();
Packit 5e354d
  if (tls_index == TLS_OUT_OF_INDEXES)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
Packit 5e354d
  err = new_thread(&thread_id);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  /* GetCurrentThread() is not usable by other threads, so it needs to
Packit 5e354d
     be duplicated.  */
Packit 5e354d
  res = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
Packit 5e354d
			GetCurrentProcess(), &handle,
Packit 5e354d
			0, FALSE, DUPLICATE_SAME_ACCESS);
Packit 5e354d
  if (!res)
Packit 5e354d
    {
Packit 5e354d
      free_thread (thread_id);
Packit 5e354d
      return map_error(GetLastError());
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  thread = thread_table[thread_id];
Packit 5e354d
  thread->handle = handle;
Packit 5e354d
Packit 5e354d
  if (! TlsSetValue(tls_index, (LPVOID) thread_id))
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
Packit 5e354d
  LEAVE();
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct npth_attr_s
Packit 5e354d
{
Packit 5e354d
  int detachstate;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_attr_init (npth_attr_t *attr_r)
Packit 5e354d
{
Packit 5e354d
  npth_attr_t attr;
Packit 5e354d
Packit 5e354d
  attr = malloc (sizeof *attr);
Packit 5e354d
  if (!attr)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  attr->detachstate = NPTH_CREATE_JOINABLE;
Packit 5e354d
  *attr_r = attr;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_attr_destroy (npth_attr_t *attr)
Packit 5e354d
{
Packit 5e354d
  free (*attr);
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_attr_getdetachstate (npth_attr_t *attr,
Packit 5e354d
			  int *detachstate)
Packit 5e354d
{
Packit 5e354d
  *detachstate = (*attr)->detachstate;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_attr_setdetachstate (npth_attr_t *attr, int detachstate)
Packit 5e354d
{
Packit 5e354d
  if (detachstate != NPTH_CREATE_JOINABLE
Packit 5e354d
      && detachstate != NPTH_CREATE_DETACHED)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  (*attr)->detachstate = detachstate;
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
  npth_impl_t thread;
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  if (buflen < THREAD_NAME_MAX + 1)
Packit 5e354d
    return ERANGE;
Packit 5e354d
Packit 5e354d
  err = find_thread (target_thread, &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  strcpy (buf, thread->name);
Packit 5e354d
  return 0;
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
  npth_impl_t thread;
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  if (strlen(name) > THREAD_NAME_MAX)
Packit 5e354d
    return ERANGE;
Packit 5e354d
Packit 5e354d
  err = find_thread (target_thread, &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  strcpy (thread->name, name);
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
static DWORD
Packit 5e354d
thread_start (void *arg)
Packit 5e354d
{
Packit 5e354d
  npth_t thread_id = (npth_t) arg;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  void *result;
Packit 5e354d
Packit 5e354d
  if (! TlsSetValue(tls_index, (LPVOID) thread_id))
Packit 5e354d
    /* FIXME: There is not much we can do here.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  LEAVE();
Packit 5e354d
  /* We must be protected here, because we access the global
Packit 5e354d
     thread_table.  */
Packit 5e354d
Packit 5e354d
  thread = thread_table[thread_id];
Packit 5e354d
  result = thread->start_routine (thread->start_arg);
Packit 5e354d
  /* We might not return here if the thread calls npth_exit().  */
Packit 5e354d
Packit 5e354d
  thread->result = result;
Packit 5e354d
Packit 5e354d
  /* Any joiner will be signaled once we terminate.  */
Packit 5e354d
  deref_thread (thread_id);
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
Packit 5e354d
  /* We can not return result, as that is a void*, not a DWORD.  */
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_create (npth_t *newthread, const npth_attr_t *user_attr,
Packit 5e354d
	     void *(*start_routine) (void *), void *start_arg)
Packit 5e354d
{
Packit 5e354d
  int err = 0;
Packit 5e354d
  npth_t thread_id = INVALID_THREAD_ID;
Packit 5e354d
  npth_attr_t attr;
Packit 5e354d
  int attr_allocated;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  HANDLE handle;
Packit 5e354d
Packit 5e354d
  /* We must stay protected here, because we access the global
Packit 5e354d
     thread_table.  Also, creating a new thread is not a blocking
Packit 5e354d
     operation.  */
Packit 5e354d
  if (user_attr)
Packit 5e354d
    {
Packit 5e354d
      attr = *user_attr;
Packit 5e354d
      attr_allocated = 0;
Packit 5e354d
    }
Packit 5e354d
  else
Packit 5e354d
    {
Packit 5e354d
      err = npth_attr_init (&attr);
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
      attr_allocated = 1;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  err = new_thread (&thread_id);
Packit 5e354d
  if (err)
Packit 5e354d
    goto err_out;
Packit 5e354d
Packit 5e354d
  thread = thread_table[thread_id];
Packit 5e354d
  if (attr->detachstate == NPTH_CREATE_DETACHED)
Packit 5e354d
    thread->detached = 1;
Packit 5e354d
  else
Packit 5e354d
    thread->refs += 1;
Packit 5e354d
Packit 5e354d
  thread->start_routine = start_routine;
Packit 5e354d
  thread->start_arg = start_arg;
Packit 5e354d
Packit 5e354d
  handle = CreateThread (NULL, 0,
Packit 5e354d
			 (LPTHREAD_START_ROUTINE)thread_start,
Packit 5e354d
			 (void *) thread_id, CREATE_SUSPENDED,
Packit 5e354d
			 NULL);
Packit 5e354d
  if (handle == NULL)
Packit 5e354d
    {
Packit 5e354d
      err = map_error (GetLastError());
Packit 5e354d
      goto err_out;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  thread->handle = handle;
Packit 5e354d
  *newthread = thread_id;
Packit 5e354d
Packit 5e354d
  ResumeThread (thread->handle);
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
Packit 5e354d
 err_out:
Packit 5e354d
  if (thread_id)
Packit 5e354d
    free_thread (thread_id);
Packit 5e354d
  if (attr_allocated)
Packit 5e354d
    npth_attr_destroy (&attr);
Packit 5e354d
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
npth_t
Packit 5e354d
npth_self (void)
Packit 5e354d
{
Packit 5e354d
  LPVOID thread_id;
Packit 5e354d
Packit 5e354d
  thread_id = TlsGetValue (tls_index);
Packit 5e354d
  if (thread_id == 0 && GetLastError() != ERROR_SUCCESS)
Packit 5e354d
    /* FIXME: Log the error.  */
Packit 5e354d
    ;
Packit 5e354d
  return (npth_t) thread_id;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* Not part of the public interface at the moment, thus static.  */
Packit 5e354d
static int
Packit 5e354d
npth_tryjoin_np (npth_t thread_id, void **thread_return)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  err = find_thread (thread_id, &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if (thread->detached)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = wait_for_single_object (thread->handle, 0);
Packit 5e354d
  if (err == ETIMEDOUT)
Packit 5e354d
    err = EBUSY;
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if (thread_return)
Packit 5e354d
    *thread_return = thread->result;
Packit 5e354d
  deref_thread (thread_id);
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_join (npth_t thread_id, void **thread_return)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  int res;
Packit 5e354d
Packit 5e354d
  /* No need to allow competing threads to enter when we can get the
Packit 5e354d
     lock immediately.  */
Packit 5e354d
  err = npth_tryjoin_np (thread_id, thread_return);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  err = find_thread (thread_id, &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if (thread->detached)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = wait_for_single_object (thread->handle, INFINITE);
Packit 5e354d
  LEAVE();
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if (thread_return)
Packit 5e354d
    *thread_return = thread->result;
Packit 5e354d
  deref_thread (thread_id);
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_detach (npth_t thread_id)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
Packit 5e354d
  err = find_thread (thread_id, &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if (thread->detached)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  /* The detached flag indicates to other thread that the outside
Packit 5e354d
     reference in the global thread table has been consumed.  */
Packit 5e354d
  thread->detached = 1;
Packit 5e354d
  deref_thread (thread_id);
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
void
Packit 5e354d
npth_exit (void *retval)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_t thread_id;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
Packit 5e354d
  thread_id = npth_self();
Packit 5e354d
  err = find_thread (thread_id, &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    /* FIXME: log this?  */
Packit 5e354d
    return;
Packit 5e354d
Packit 5e354d
  thread->result = retval;
Packit 5e354d
  /* Any joiner will be signaled once we terminate.  */
Packit 5e354d
  deref_thread (thread_id);
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
Packit 5e354d
  /* We can not use retval here, as that is a void*, not a DWORD.  */
Packit 5e354d
  ExitThread(0);
Packit 5e354d
Packit 5e354d
  /* Never reached.  But just in case ExitThread does return... */
Packit 5e354d
  LEAVE();
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d

Packit 5e354d
int
Packit 5e354d
npth_key_create (npth_key_t *key,
Packit 5e354d
		 void (*destr_function) (void *))
Packit 5e354d
{
Packit 5e354d
  DWORD idx;
Packit 5e354d
Packit 5e354d
  if (destr_function)
Packit 5e354d
    return EOPNOTSUPP;
Packit 5e354d
Packit 5e354d
  idx = TlsAlloc ();
Packit 5e354d
  if (idx == TLS_OUT_OF_INDEXES)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
Packit 5e354d
  *key = idx;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_key_delete (npth_key_t key)
Packit 5e354d
{
Packit 5e354d
  BOOL res;
Packit 5e354d
Packit 5e354d
  res = TlsFree (key);
Packit 5e354d
  if (res == 0)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
void *
Packit 5e354d
npth_getspecific (npth_key_t key)
Packit 5e354d
{
Packit 5e354d
  /* Pthread doesn't support error reporting beyond returning NULL for
Packit 5e354d
     an invalid key, which is also what TlsGetValue returns in that
Packit 5e354d
     case.  */
Packit 5e354d
  return TlsGetValue (key);
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_setspecific (npth_key_t key, const void *pointer)
Packit 5e354d
{
Packit 5e354d
  BOOL res;
Packit 5e354d
Packit 5e354d
  res = TlsSetValue (key, (void *) pointer);
Packit 5e354d
  if (res == 0)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct npth_mutexattr_s
Packit 5e354d
{
Packit 5e354d
  int kind;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutexattr_init (npth_mutexattr_t *attr_r)
Packit 5e354d
{
Packit 5e354d
  npth_mutexattr_t attr;
Packit 5e354d
Packit 5e354d
  attr = malloc (sizeof *attr);
Packit 5e354d
  if (!attr)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  attr->kind = NPTH_MUTEX_DEFAULT;
Packit 5e354d
  *attr_r = attr;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutexattr_destroy (npth_mutexattr_t *attr)
Packit 5e354d
{
Packit 5e354d
  free (*attr);
Packit 5e354d
  *attr = NULL;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutexattr_gettype (const npth_mutexattr_t *attr,
Packit 5e354d
			int *kind)
Packit 5e354d
{
Packit 5e354d
  *kind = (*attr)->kind;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutexattr_settype (npth_mutexattr_t *attr, int kind)
Packit 5e354d
{
Packit 5e354d
  if (kind != NPTH_MUTEX_NORMAL && kind != NPTH_MUTEX_RECURSIVE
Packit 5e354d
      && kind != NPTH_MUTEX_ERRORCHECK)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  (*attr)->kind = kind;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct npth_mutex_s
Packit 5e354d
{
Packit 5e354d
  /* We have to use a mutex, not a CRITICAL_SECTION, because the
Packit 5e354d
     latter can not be used with timed waits.  */
Packit 5e354d
  HANDLE mutex;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutex_init (npth_mutex_t *mutex_r, const npth_mutexattr_t *mutex_attr)
Packit 5e354d
{
Packit 5e354d
  npth_mutex_t mutex;
Packit 5e354d
Packit 5e354d
  /* We can not check *mutex_r here, as it may contain random data.  */
Packit 5e354d
  mutex = malloc (sizeof (*mutex));
Packit 5e354d
  if (!mutex)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  /* We ignore MUTEX_ATTR.  */
Packit 5e354d
  mutex->mutex = CreateMutex (NULL, FALSE, NULL);
Packit 5e354d
  if (!mutex->mutex)
Packit 5e354d
    {
Packit 5e354d
      int err = map_error (GetLastError());
Packit 5e354d
      free (mutex);
Packit 5e354d
      return err;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  *mutex_r = mutex;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutex_destroy (npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  BOOL res;
Packit 5e354d
Packit 5e354d
  if (*mutex == 0 || *mutex == NPTH_MUTEX_INITIALIZER
Packit 5e354d
      || *mutex == NPTH_RECURSIVE_MUTEX_INITIALIZER_NP)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  res = CloseHandle ((*mutex)->mutex);
Packit 5e354d
  if (res == 0)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
Packit 5e354d
  free (*mutex);
Packit 5e354d
  *mutex = NULL;
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* Must be called with global lock held.  */
Packit 5e354d
static int
Packit 5e354d
mutex_init_check (npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_mutexattr_t attr;
Packit 5e354d
  int kind;
Packit 5e354d
Packit 5e354d
  if (*mutex == 0)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  if ((*mutex) == NPTH_MUTEX_INITIALIZER)
Packit 5e354d
    kind = NPTH_MUTEX_NORMAL;
Packit 5e354d
  else if ((*mutex) == NPTH_RECURSIVE_MUTEX_INITIALIZER_NP)
Packit 5e354d
    kind = NPTH_MUTEX_RECURSIVE;
Packit 5e354d
  else if ((*mutex) == NPTH_ERRORCHECK_MUTEX_INITIALIZER_NP)
Packit 5e354d
    kind = NPTH_MUTEX_ERRORCHECK;
Packit 5e354d
  else
Packit 5e354d
    /* Already initialized.  */
Packit 5e354d
    return 0;
Packit 5e354d
Packit 5e354d
  /* Make sure we don't try again in case of error.  */
Packit 5e354d
  *mutex = 0;
Packit 5e354d
Packit 5e354d
  err = npth_mutexattr_init (&attr);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  err = npth_mutexattr_settype (&attr, kind);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      npth_mutexattr_destroy (&attr);
Packit 5e354d
      return err;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  err = npth_mutex_init (mutex, &attr);
Packit 5e354d
  npth_mutexattr_destroy (&attr);
Packit 5e354d
Packit 5e354d
  return err;
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
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = mutex_init_check (mutex);
Packit 5e354d
  if (err)
Packit 5e354d
    return 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 = npth_mutex_trylock (mutex);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = wait_for_single_object ((*mutex)->mutex, INFINITE);
Packit 5e354d
  LEAVE();
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutex_trylock (npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  DWORD res;
Packit 5e354d
Packit 5e354d
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = mutex_init_check (mutex);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  /* We do not leave the global lock for a quick try.  */
Packit 5e354d
  err = wait_for_single_object ((*mutex)->mutex, 0);
Packit 5e354d
  if (err == ETIMEDOUT)
Packit 5e354d
    err = EBUSY;
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  return 0;
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
  DWORD msecs;
Packit 5e354d
Packit 5e354d
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = mutex_init_check (mutex);
Packit 5e354d
  if (err)
Packit 5e354d
    return 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 = npth_mutex_trylock (mutex);
Packit 5e354d
  if (err != EBUSY)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  err = calculate_timeout (abstime, &msecs);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = wait_for_single_object ((*mutex)->mutex, msecs);
Packit 5e354d
  LEAVE();
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_mutex_unlock (npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  BOOL res;
Packit 5e354d
Packit 5e354d
  if (*mutex == 0 || *mutex == NPTH_MUTEX_INITIALIZER
Packit 5e354d
      || *mutex == NPTH_RECURSIVE_MUTEX_INITIALIZER_NP)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  res = ReleaseMutex ((*mutex)->mutex);
Packit 5e354d
  if (res == 0)
Packit 5e354d
    return map_error (GetLastError());
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct npth_cond_s
Packit 5e354d
{
Packit 5e354d
  /* All conditions are protected by the global lock, so this is
Packit 5e354d
     simple.  */
Packit 5e354d
Packit 5e354d
  /* The waiter queue.  */
Packit 5e354d
  npth_impl_t waiter;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_cond_init (npth_cond_t *cond_r,
Packit 5e354d
		const npth_condattr_t *cond_attr)
Packit 5e354d
{
Packit 5e354d
  npth_cond_t cond;
Packit 5e354d
Packit 5e354d
  if (cond_attr != NULL)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  /* We can not check *cond_r here, as it may contain random data.  */
Packit 5e354d
  cond = malloc (sizeof (*cond));
Packit 5e354d
  if (!cond)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  cond->waiter = NULL;
Packit 5e354d
Packit 5e354d
  *cond_r = cond;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_cond_destroy (npth_cond_t *cond)
Packit 5e354d
{
Packit 5e354d
  if (*cond == 0)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  if ((*cond)->waiter)
Packit 5e354d
    return EBUSY;
Packit 5e354d
Packit 5e354d
  free (*cond);
Packit 5e354d
  *cond = NULL;
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* Must be called with global lock held.  */
Packit 5e354d
static int
Packit 5e354d
cond_init_check (npth_cond_t *cond)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  if (*cond == 0 || *cond == NPTH_COND_INITIALIZER)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  if (*cond != NPTH_COND_INITIALIZER)
Packit 5e354d
    /* Already initialized.  */
Packit 5e354d
    return 0;
Packit 5e354d
Packit 5e354d
  /* Make sure we don't try again in case of error.  */
Packit 5e354d
  *cond = 0;
Packit 5e354d
Packit 5e354d
  err = npth_cond_init (cond, NULL);
Packit 5e354d
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_cond_signal (npth_cond_t *cond)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  DWORD res;
Packit 5e354d
Packit 5e354d
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = cond_init_check (cond);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if ((*cond)->waiter == INVALID_THREAD_ID)
Packit 5e354d
    return 0;
Packit 5e354d
Packit 5e354d
  /* Dequeue the first thread and wake it up.  */
Packit 5e354d
  thread = (*cond)->waiter;
Packit 5e354d
  dequeue_thread (thread);
Packit 5e354d
Packit 5e354d
  res = SetEvent (thread->event);
Packit 5e354d
  if (res == 0)
Packit 5e354d
    /* FIXME: An error here implies a mistake in the npth code.  Log it.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  /* Force the woken up thread into the mutex lock function (for the
Packit 5e354d
     mutex associated with the condition, which is why we have to
Packit 5e354d
     release the global lock here).  This helps to ensure fairness,
Packit 5e354d
     because otherwise our own thread might release and reacquire the
Packit 5e354d
     lock first (followed by removing the condition that lead to the
Packit 5e354d
     wakeup) and starve the woken up thread.  */
Packit 5e354d
  ENTER ();
Packit 5e354d
  Sleep (0);
Packit 5e354d
  LEAVE ();
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_cond_broadcast (npth_cond_t *cond)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  DWORD res;
Packit 5e354d
  int any;
Packit 5e354d
Packit 5e354d
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = cond_init_check (cond);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  if ((*cond)->waiter == INVALID_THREAD_ID)
Packit 5e354d
    return 0;
Packit 5e354d
Packit 5e354d
  while ((*cond)->waiter)
Packit 5e354d
    {
Packit 5e354d
      /* Dequeue the first thread and wake it up.  */
Packit 5e354d
      thread = (*cond)->waiter;
Packit 5e354d
      dequeue_thread (thread);
Packit 5e354d
Packit 5e354d
      res = SetEvent (thread->event);
Packit 5e354d
      if (res == 0)
Packit 5e354d
	/* FIXME: An error here implies a mistake in the npth code.  Log it.  */
Packit 5e354d
	;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* Force the woken up threads into the mutex lock function (for the
Packit 5e354d
     mutex associated with the condition, which is why we have to
Packit 5e354d
     release the global lock here).  This helps to ensure fairness,
Packit 5e354d
     because otherwise our own thread might release and reacquire the
Packit 5e354d
     lock first (followed by removing the condition that lead to the
Packit 5e354d
     wakeup) and starve the woken up threads.  */
Packit 5e354d
  ENTER ();
Packit 5e354d
  Sleep (0);
Packit 5e354d
  LEAVE ();
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* As a special exception in W32 NPTH, mutex can be NULL, in which
Packit 5e354d
   case the global lock doubles as the mutex protecting the condition.
Packit 5e354d
   This is used internally in the RW implementation as an
Packit 5e354d
   optimization.  Note that this is safe as long as the caller does
Packit 5e354d
   not yield to other threads (directly or indirectly) between
Packit 5e354d
   checking the condition and waiting on it.  */
Packit 5e354d
int
Packit 5e354d
npth_cond_wait (npth_cond_t *cond, npth_mutex_t *mutex)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  int err2;
Packit 5e354d
  BOOL bres;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  npth_impl_t *prev_ptr;
Packit 5e354d
Packit 5e354d
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = cond_init_check (cond);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  err = find_thread (npth_self(), &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  /* Ensure there is an event.  */
Packit 5e354d
  if (thread->event == INVALID_HANDLE_VALUE)
Packit 5e354d
    {
Packit 5e354d
      thread->event = CreateEvent (NULL, TRUE, FALSE, NULL);
Packit 5e354d
      if (thread->event == INVALID_HANDLE_VALUE)
Packit 5e354d
	return map_error (GetLastError());
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* Find end of queue and enqueue the thread.  */
Packit 5e354d
  prev_ptr = &(*cond)->waiter;
Packit 5e354d
  while (*prev_ptr)
Packit 5e354d
    prev_ptr = &(*prev_ptr)->next;
Packit 5e354d
  enqueue_thread (thread, prev_ptr);
Packit 5e354d
Packit 5e354d
  /* Make sure the event is not signaled before releasing the mutex.  */
Packit 5e354d
  bres = ResetEvent (thread->event);
Packit 5e354d
  if (bres == 0)
Packit 5e354d
    /* Log an error.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  if (mutex)
Packit 5e354d
    {
Packit 5e354d
      err = npth_mutex_unlock (mutex);
Packit 5e354d
      if (err)
Packit 5e354d
	{
Packit 5e354d
	  dequeue_thread (thread);
Packit 5e354d
	  return err;
Packit 5e354d
	}
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = wait_for_single_object (thread->event, INFINITE);
Packit 5e354d
  LEAVE();
Packit 5e354d
Packit 5e354d
  /* Make sure the thread is dequeued (in case of error).  */
Packit 5e354d
  dequeue_thread (thread);
Packit 5e354d
Packit 5e354d
  if (mutex)
Packit 5e354d
    {
Packit 5e354d
      err2 = npth_mutex_lock (mutex);
Packit 5e354d
      if (err2)
Packit 5e354d
	/* FIXME: Log this at least.  */
Packit 5e354d
	;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  return 0;
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
  int err2;
Packit 5e354d
  BOOL bres;
Packit 5e354d
  npth_impl_t thread;
Packit 5e354d
  npth_impl_t *prev_ptr;
Packit 5e354d
  DWORD msecs;
Packit 5e354d
Packit 5e354d
  err = calculate_timeout (abstime, &msecs);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      if (err != ETIMEDOUT)
Packit 5e354d
	return err;
Packit 5e354d
Packit 5e354d
      /* We have to give up the lock anyway to give others a chance to
Packit 5e354d
	 signal or broadcast.  */
Packit 5e354d
      err = npth_mutex_unlock (mutex);
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
      ENTER();
Packit 5e354d
      Sleep (0);
Packit 5e354d
      LEAVE();
Packit 5e354d
      err = npth_mutex_lock (mutex);
Packit 5e354d
      if (err)
Packit 5e354d
	return (err);
Packit 5e354d
      return ETIMEDOUT;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* While we are protected, let's check for a static initializer.  */
Packit 5e354d
  err = cond_init_check (cond);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  err = find_thread (npth_self(), &thread);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  /* Ensure there is an event.  */
Packit 5e354d
  if (thread->event == INVALID_HANDLE_VALUE)
Packit 5e354d
    {
Packit 5e354d
      thread->event = CreateEvent (NULL, TRUE, FALSE, NULL);
Packit 5e354d
      if (thread->event == INVALID_HANDLE_VALUE)
Packit 5e354d
	return map_error (GetLastError());
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* Make sure the event is not signaled.  */
Packit 5e354d
  bres = ResetEvent (thread->event);
Packit 5e354d
  if (bres == 0)
Packit 5e354d
    /* Log an error.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  /* Find end of queue and enqueue the thread.  */
Packit 5e354d
  prev_ptr = &(*cond)->waiter;
Packit 5e354d
  while (*prev_ptr)
Packit 5e354d
    prev_ptr = &(*prev_ptr)->next;
Packit 5e354d
  enqueue_thread (thread, prev_ptr);
Packit 5e354d
Packit 5e354d
  err = npth_mutex_unlock (mutex);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      dequeue_thread (thread);
Packit 5e354d
      return err;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  ENTER();
Packit 5e354d
  err = wait_for_single_object (thread->event, msecs);
Packit 5e354d
  LEAVE();
Packit 5e354d
Packit 5e354d
  err2 = npth_mutex_lock (mutex);
Packit 5e354d
  if (err2)
Packit 5e354d
    /* FIXME: Log this at least.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d

Packit 5e354d
struct npth_rwlockattr_s
Packit 5e354d
{
Packit 5e354d
  int kind;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlockattr_init (npth_rwlockattr_t *attr_r)
Packit 5e354d
{
Packit 5e354d
  npth_rwlockattr_t attr;
Packit 5e354d
Packit 5e354d
  attr = malloc (sizeof *attr);
Packit 5e354d
  if (!attr)
Packit 5e354d
    return errno;
Packit 5e354d
Packit 5e354d
  attr->kind = NPTH_RWLOCK_DEFAULT_NP;
Packit 5e354d
  *attr_r = attr;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlockattr_destroy (npth_rwlockattr_t *attr)
Packit 5e354d
{
Packit 5e354d
  free (*attr);
Packit 5e354d
  *attr = NULL;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlockattr_gettype_np (const npth_rwlockattr_t *attr,
Packit 5e354d
			    int *kind)
Packit 5e354d
{
Packit 5e354d
  *kind = (*attr)->kind;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlockattr_settype_np (npth_rwlockattr_t *attr, int kind)
Packit 5e354d
{
Packit 5e354d
  if (kind != NPTH_RWLOCK_PREFER_READER_NP
Packit 5e354d
      && kind != NPTH_RWLOCK_PREFER_WRITER_NP
Packit 5e354d
      && kind != NPTH_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  (*attr)->kind = kind;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
struct npth_rwlock_s
Packit 5e354d
{
Packit 5e354d
  /* Objects are protected by the global lock, so no lock here
Packit 5e354d
     necessary.  This is even true for the condition (by specifying
Packit 5e354d
     NULL as the mutex in npth_cond_wait and npth_cond_timedwait).  */
Packit 5e354d
Packit 5e354d
  /* True if we prefer writers over readers.  */
Packit 5e354d
  int prefer_writer;
Packit 5e354d
Packit 5e354d
  /* Readers who want the lock wait on this condition, which is
Packit 5e354d
     broadcast when the last writer goes away.  */
Packit 5e354d
  npth_cond_t reader_wait;
Packit 5e354d
Packit 5e354d
  /* The number of readers waiting on the condition.  */
Packit 5e354d
  int nr_readers_queued;
Packit 5e354d
Packit 5e354d
  /* The number of current readers.  */
Packit 5e354d
  int nr_readers;
Packit 5e354d
Packit 5e354d
  /* Writers who want the lock wait on this condition, which is
Packit 5e354d
     signaled when the current writer or last reader goes away.  */
Packit 5e354d
  npth_cond_t writer_wait;
Packit 5e354d
Packit 5e354d
  /* The number of queued writers.  */
Packit 5e354d
  int nr_writers_queued;
Packit 5e354d
Packit 5e354d
  /* The number of current writers.  This is either 1 (then nr_readers
Packit 5e354d
     is 0) or it is 0.  At unlock time this value tells us if the
Packit 5e354d
     current lock holder is a writer or a reader.  */
Packit 5e354d
  int nr_writers;
Packit 5e354d
};
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_init (npth_rwlock_t *rwlock_r,
Packit 5e354d
		  const npth_rwlockattr_t *user_attr)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_rwlock_t rwlock;
Packit 5e354d
  npth_rwlockattr_t attr;
Packit 5e354d
  int attr_allocated;
Packit 5e354d
Packit 5e354d
  if (user_attr != NULL)
Packit 5e354d
    {
Packit 5e354d
      attr = *user_attr;
Packit 5e354d
      attr_allocated = 0;
Packit 5e354d
    }
Packit 5e354d
  else
Packit 5e354d
    {
Packit 5e354d
      err = npth_rwlockattr_init (&attr);
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* We can not check *rwlock_r here, as it may contain random data.  */
Packit 5e354d
  rwlock = malloc (sizeof (*rwlock));
Packit 5e354d
  if (!rwlock)
Packit 5e354d
    {
Packit 5e354d
      err = errno;
Packit 5e354d
      goto err_out;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  rwlock->prefer_writer = (attr->kind == NPTH_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
Packit 5e354d
Packit 5e354d
  err = npth_cond_init (&rwlock->reader_wait, NULL);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      free (rwlock);
Packit 5e354d
      goto err_out;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  err = npth_cond_init (&rwlock->writer_wait, NULL);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      npth_cond_destroy (&rwlock->reader_wait);
Packit 5e354d
      free (rwlock);
Packit 5e354d
      goto err_out;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  rwlock->nr_readers = 0;
Packit 5e354d
  rwlock->nr_readers_queued = 0;
Packit 5e354d
  rwlock->nr_writers = 0;
Packit 5e354d
  rwlock->nr_writers_queued = 0;
Packit 5e354d
Packit 5e354d
  *rwlock_r = rwlock;
Packit 5e354d
Packit 5e354d
 err_out:
Packit 5e354d
  if (attr_allocated)
Packit 5e354d
    npth_rwlockattr_destroy (&attr);
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
/* Must be called with global lock held.  */
Packit 5e354d
static int
Packit 5e354d
rwlock_init_check (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
  npth_rwlockattr_t attr;
Packit 5e354d
  int kind;
Packit 5e354d
Packit 5e354d
  if (*rwlock == 0)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  if ((*rwlock) == NPTH_RWLOCK_INITIALIZER)
Packit 5e354d
    kind = NPTH_RWLOCK_PREFER_READER_NP;
Packit 5e354d
  if ((*rwlock) == NPTH_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP)
Packit 5e354d
    kind = NPTH_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP;
Packit 5e354d
  else
Packit 5e354d
    /* Already initialized.  */
Packit 5e354d
    return 0;
Packit 5e354d
Packit 5e354d
  /* Make sure we don't try again in case of error.  */
Packit 5e354d
  *rwlock = 0;
Packit 5e354d
Packit 5e354d
  err = npth_rwlockattr_init (&attr);
Packit 5e354d
  if (err)
Packit 5e354d
    return err;
Packit 5e354d
Packit 5e354d
  err = npth_rwlockattr_settype_np (&attr, kind);
Packit 5e354d
  if (err)
Packit 5e354d
    {
Packit 5e354d
      npth_rwlockattr_destroy (&attr);
Packit 5e354d
      return err;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  err = npth_rwlock_init (rwlock, &attr);
Packit 5e354d
  npth_rwlockattr_destroy (&attr);
Packit 5e354d
Packit 5e354d
  return err;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_destroy (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  if (*rwlock == 0 || *rwlock == NPTH_RWLOCK_INITIALIZER)
Packit 5e354d
    return EINVAL;
Packit 5e354d
Packit 5e354d
  if ((*rwlock)->nr_writers || (*rwlock)->nr_readers || (*rwlock)->nr_writers_queued
Packit 5e354d
      || (*rwlock)->nr_readers_queued)
Packit 5e354d
    return EBUSY;
Packit 5e354d
Packit 5e354d
  err = npth_cond_destroy (&(*rwlock)->reader_wait);
Packit 5e354d
  if (err)
Packit 5e354d
    /* FIXME: Log this.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  err = npth_cond_destroy (&(*rwlock)->writer_wait);
Packit 5e354d
  if (err)
Packit 5e354d
    /* FIXME: Log this.  */
Packit 5e354d
    ;
Packit 5e354d
Packit 5e354d
  free (rwlock);
Packit 5e354d
Packit 5e354d
  *rwlock = NULL;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_tryrdlock (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  if ((*rwlock)->nr_writers)
Packit 5e354d
    return EBUSY;
Packit 5e354d
Packit 5e354d
  if ((*rwlock)->nr_writers_queued && (*rwlock)->prefer_writer)
Packit 5e354d
    return EBUSY;
Packit 5e354d
Packit 5e354d
  (*rwlock)->nr_readers++;
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_rdlock (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  while (1)
Packit 5e354d
    {
Packit 5e354d
      /* Quick check.  */
Packit 5e354d
      err = npth_rwlock_tryrdlock (rwlock);
Packit 5e354d
      if (err != EBUSY)
Packit 5e354d
	return err;
Packit 5e354d
Packit 5e354d
      (*rwlock)->nr_readers_queued++;
Packit 5e354d
      err = npth_cond_wait (&(*rwlock)->reader_wait, NULL);
Packit 5e354d
      (*rwlock)->nr_readers_queued--;
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
    }
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_timedrdlock (npth_rwlock_t *rwlock,
Packit 5e354d
			 const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  while (1)
Packit 5e354d
    {
Packit 5e354d
      /* Quick check.  */
Packit 5e354d
      err = npth_rwlock_tryrdlock (rwlock);
Packit 5e354d
      if (err != EBUSY)
Packit 5e354d
	return err;
Packit 5e354d
Packit 5e354d
      (*rwlock)->nr_readers_queued++;
Packit 5e354d
      err = npth_cond_timedwait (&(*rwlock)->reader_wait, NULL, abstime);
Packit 5e354d
      (*rwlock)->nr_readers_queued--;
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
    }
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_trywrlock (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  if ((*rwlock)->nr_writers)
Packit 5e354d
    return EBUSY;
Packit 5e354d
Packit 5e354d
  if ((*rwlock)->nr_readers)
Packit 5e354d
    return EBUSY;
Packit 5e354d
Packit 5e354d
  (*rwlock)->nr_writers = 1;
Packit 5e354d
  return 0;
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
  while (1)
Packit 5e354d
    {
Packit 5e354d
      /* Quick check.  */
Packit 5e354d
      err = npth_rwlock_trywrlock (rwlock);
Packit 5e354d
      if (err != EBUSY)
Packit 5e354d
	return err;
Packit 5e354d
Packit 5e354d
      (*rwlock)->nr_writers_queued++;
Packit 5e354d
      err = npth_cond_wait (&(*rwlock)->writer_wait, NULL);
Packit 5e354d
      (*rwlock)->nr_writers_queued--;
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
    }
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_timedwrlock (npth_rwlock_t *rwlock,
Packit 5e354d
			 const struct timespec *abstime)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  while (1)
Packit 5e354d
    {
Packit 5e354d
      /* Quick check.  */
Packit 5e354d
      err = npth_rwlock_trywrlock (rwlock);
Packit 5e354d
      if (err != EBUSY)
Packit 5e354d
	return err;
Packit 5e354d
Packit 5e354d
      (*rwlock)->nr_writers_queued++;
Packit 5e354d
      err = npth_cond_timedwait (&(*rwlock)->writer_wait, NULL, abstime);
Packit 5e354d
      (*rwlock)->nr_writers_queued--;
Packit 5e354d
      if (err)
Packit 5e354d
	return err;
Packit 5e354d
    }
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
int
Packit 5e354d
npth_rwlock_unlock (npth_rwlock_t *rwlock)
Packit 5e354d
{
Packit 5e354d
  int err;
Packit 5e354d
Packit 5e354d
  if ((*rwlock)->nr_writers)
Packit 5e354d
    /* We are the writer.  */
Packit 5e354d
    (*rwlock)->nr_writers = 0;
Packit 5e354d
  else
Packit 5e354d
    /* We are the reader.  */
Packit 5e354d
    (*rwlock)->nr_readers--;
Packit 5e354d
Packit 5e354d
  if ((*rwlock)->nr_readers == 0)
Packit 5e354d
    {
Packit 5e354d
      if ((*rwlock)->nr_writers_queued)
Packit 5e354d
	{
Packit 5e354d
	  err = npth_cond_signal (&(*rwlock)->writer_wait);
Packit 5e354d
	  if (err)
Packit 5e354d
	    return err;
Packit 5e354d
	}
Packit 5e354d
      else if ((*rwlock)->nr_readers_queued)
Packit 5e354d
	{
Packit 5e354d
	  err = npth_cond_broadcast (&(*rwlock)->reader_wait);
Packit 5e354d
	  return err;
Packit 5e354d
	}
Packit 5e354d
    }
Packit 5e354d
  return 0;
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
  ENTER();
Packit 5e354d
  Sleep((usec + 999) / 1000);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return 0;
Packit 5e354d
}
Packit 5e354d
Packit 5e354d
Packit 5e354d
unsigned int
Packit 5e354d
npth_sleep(unsigned int sec)
Packit 5e354d
{
Packit 5e354d
  ENTER();
Packit 5e354d
  Sleep (sec * 1000);
Packit 5e354d
  LEAVE();
Packit 5e354d
  return 0;
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
  return EOPNOTSUPP;
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
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
  return EOPNOTSUPP;
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
  return EOPNOTSUPP;
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

Packit 5e354d
/* Maximum number of extra handles.  We can only support 31 as that is
Packit 5e354d
   the number of bits we can return.  This is smaller than the maximum
Packit 5e354d
   number of allowed wait objects for WFMO (which is 64).  */
Packit 5e354d
#define MAX_EVENTS 31
Packit 5e354d
Packit 5e354d
/* Although the WSAEventSelect machinery seems to have no limit on the
Packit 5e354d
   number of selectable fds, we impose the same limit as used by
Packit 5e354d
   traditional select.  This allows us to work with a static data
Packit 5e354d
   structure instead of an dynamically allocated array.  */
Packit 5e354d
#define MAX_FDOBJS FD_SETSIZE
Packit 5e354d
Packit 5e354d
/* Using WFMO even for sockets makes Windows objects more composable,
Packit 5e354d
   which helps faking signals and other constructs, so we support
Packit 5e354d
   that.  You can still use npth_select for the plain select
Packit 5e354d
   function.  */
Packit 5e354d
int
Packit 5e354d
npth_eselect(int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
Packit 5e354d
	     const struct timespec *timeout,
Packit 5e354d
             HANDLE *events, unsigned int *events_set)
Packit 5e354d
{
Packit 5e354d
  int err = 0;
Packit 5e354d
  DWORD msecs;
Packit 5e354d
  int i;
Packit 5e354d
  u_int idx;
Packit 5e354d
  /* One more for the handle associated with socket events.  */
Packit 5e354d
  HANDLE obj[MAX_EVENTS + 1];
Packit 5e354d
  int nr_obj = 0;
Packit 5e354d
  /* Number of extra events.  */
Packit 5e354d
  int nr_events = 0;
Packit 5e354d
  HANDLE sock_event = INVALID_HANDLE_VALUE;
Packit 5e354d
  /* This will be (nr_obj - 1) == nr_events.  */
Packit 5e354d
  int sock_event_idx = -1;
Packit 5e354d
  int res;
Packit 5e354d
  DWORD ret;
Packit 5e354d
  SOCKET fd;
Packit 5e354d
  long flags;
Packit 5e354d
  int cnt;
Packit 5e354d
  struct {
Packit 5e354d
    SOCKET fd;
Packit 5e354d
    long flags;
Packit 5e354d
  } fdobj[MAX_FDOBJS];
Packit 5e354d
  int nr_fdobj = 0;
Packit 5e354d
Packit 5e354d
  (void)nfd;  /* No need for it under Windows.  */
Packit 5e354d
Packit 5e354d
  if (events)
Packit 5e354d
    {
Packit 5e354d
      if (!events_set)
Packit 5e354d
	{
Packit 5e354d
	  errno = EINVAL;
Packit 5e354d
	  return -1;
Packit 5e354d
	}
Packit 5e354d
Packit 5e354d
      /* We always ensure that the events_set is valid, even after an
Packit 5e354d
	 error.  */
Packit 5e354d
      *events_set = 0;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  if (timeout && (timeout->tv_sec < 0 || timeout->tv_nsec < 0))
Packit 5e354d
    {
Packit 5e354d
      errno = EINVAL;
Packit 5e354d
      return -1;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  if (timeout == NULL)
Packit 5e354d
    msecs = INFINITE;
Packit 5e354d
  else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0)
Packit 5e354d
    msecs = 0;
Packit 5e354d
  else
Packit 5e354d
    {
Packit 5e354d
      msecs = (timeout->tv_sec * 1000) + (timeout->tv_nsec + 999999) / 1000000;
Packit 5e354d
      if (msecs < 1)
Packit 5e354d
	msecs = 1;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  if (events)
Packit 5e354d
    {
Packit 5e354d
      /* Copy the extra handles.  */
Packit 5e354d
      for (i = 0; i < MAX_EVENTS; i++)
Packit 5e354d
	{
Packit 5e354d
	  if (events[i] == INVALID_HANDLE_VALUE)
Packit 5e354d
	    break;
Packit 5e354d
Packit 5e354d
	  obj[nr_obj] = events[i];
Packit 5e354d
	  nr_obj++;
Packit 5e354d
	  nr_events++;
Packit 5e354d
	}
Packit 5e354d
Packit 5e354d
      /* We can only return the status of up to MAX_EVENTS handles in
Packit 5e354d
         EVENTS_SET.  */
Packit 5e354d
      if (events[i] != INVALID_HANDLE_VALUE)
Packit 5e354d
        {
Packit 5e354d
          errno = EINVAL;
Packit 5e354d
          return -1;
Packit 5e354d
        }
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* From here on, we clean up at err_out, and you can set ERR to
Packit 5e354d
     return an error.  */
Packit 5e354d
Packit 5e354d
  sock_event = WSACreateEvent ();
Packit 5e354d
  if (sock_event == INVALID_HANDLE_VALUE)
Packit 5e354d
    {
Packit 5e354d
      err = EINVAL;
Packit 5e354d
      return -1;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  sock_event_idx = nr_obj;
Packit 5e354d
  obj[nr_obj] = sock_event;
Packit 5e354d
  nr_obj++;
Packit 5e354d
Packit 5e354d
  /* Combine FDs from all lists.  */
Packit 5e354d
#define SET_FDOBJ(x,v) do {                      \
Packit 5e354d
    for (idx=0; idx < (x)->fd_count; idx++)      \
Packit 5e354d
      {                                          \
Packit 5e354d
        for (i=0; i < nr_fdobj; i++)             \
Packit 5e354d
          if (fdobj[i].fd == (x)->fd_array[idx]) \
Packit 5e354d
            break;                               \
Packit 5e354d
        if (i < nr_fdobj)                        \
Packit 5e354d
          ;                                      \
Packit 5e354d
        else if (nr_fdobj < MAX_FDOBJS)          \
Packit 5e354d
          {                                      \
Packit 5e354d
            i = nr_fdobj++;                      \
Packit 5e354d
            fdobj[i].fd    = (x)->fd_array[idx]; \
Packit 5e354d
            fdobj[i].flags = 0;                  \
Packit 5e354d
          }                                      \
Packit 5e354d
        else                                     \
Packit 5e354d
          {                                      \
Packit 5e354d
            err = EINVAL;                        \
Packit 5e354d
            goto err_out;                        \
Packit 5e354d
          }                                      \
Packit 5e354d
        fdobj[i].flags |= (v);                   \
Packit 5e354d
      }                                          \
Packit 5e354d
  } while (0)
Packit 5e354d
Packit 5e354d
  if (rfds)
Packit 5e354d
    SET_FDOBJ (rfds, FD_READ | FD_ACCEPT);
Packit 5e354d
  if (wfds)
Packit 5e354d
    SET_FDOBJ (wfds, FD_WRITE);
Packit 5e354d
  if (efds)
Packit 5e354d
    SET_FDOBJ (efds, FD_OOB | FD_CLOSE);
Packit 5e354d
Packit 5e354d
#undef SET_FDOBJ
Packit 5e354d
Packit 5e354d
  /* Set the select flags.  */
Packit 5e354d
  for (i = 0; i < nr_fdobj; i++)
Packit 5e354d
    {
Packit 5e354d
      res = WSAEventSelect (fdobj[i].fd, sock_event, fdobj[i].flags);
Packit 5e354d
      if (res == SOCKET_ERROR)
Packit 5e354d
	{
Packit 5e354d
	  err = map_error (WSAGetLastError());
Packit 5e354d
	  goto err_out;
Packit 5e354d
	}
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* Let's wait.  */
Packit 5e354d
  ENTER();
Packit 5e354d
  ret = WaitForMultipleObjects (nr_obj, obj, FALSE, msecs);
Packit 5e354d
  LEAVE();
Packit 5e354d
  if (ret == WAIT_TIMEOUT)
Packit 5e354d
    {
Packit 5e354d
      err = ETIMEDOUT;
Packit 5e354d
      goto err_out;
Packit 5e354d
    }
Packit 5e354d
  else if (ret == WAIT_FAILED)
Packit 5e354d
    {
Packit 5e354d
      err = map_error (GetLastError());
Packit 5e354d
      goto err_out;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* All other return values: We look at the objects.  We must not
Packit 5e354d
     fail from here, because then we could lose events.  */
Packit 5e354d
Packit 5e354d
  /* Keep track of result count.  */
Packit 5e354d
  cnt = 0;
Packit 5e354d
Packit 5e354d
  for (i = 0; i < nr_events; i++)
Packit 5e354d
    {
Packit 5e354d
      ret = WaitForSingleObject (obj[i], 0);
Packit 5e354d
      if (ret != WAIT_OBJECT_0)
Packit 5e354d
	/* We ignore errors here.  */
Packit 5e354d
	continue;
Packit 5e354d
Packit 5e354d
      *events_set = (*events_set) | (1 << i);
Packit 5e354d
      /* We consume the event here.  This may be undesirable, but
Packit 5e354d
	 unless we make it configurable we need a common policy,
Packit 5e354d
	 and this saves the user one step.  */
Packit 5e354d
      ResetEvent (obj[i]);
Packit 5e354d
      /* Increase result count.  */
Packit 5e354d
      cnt++;
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* Now update the file descriptors sets.  */
Packit 5e354d
  if (rfds)
Packit 5e354d
    FD_ZERO (rfds);
Packit 5e354d
  if (wfds)
Packit 5e354d
    FD_ZERO (wfds);
Packit 5e354d
  if (efds)
Packit 5e354d
    FD_ZERO (efds);
Packit 5e354d
  for (i = 0; i < nr_fdobj; i++)
Packit 5e354d
    {
Packit 5e354d
      WSANETWORKEVENTS ne;
Packit 5e354d
Packit 5e354d
      fd = fdobj[i].fd;
Packit 5e354d
      flags = fdobj[i].flags;
Packit 5e354d
Packit 5e354d
      res = WSAEnumNetworkEvents (fd, NULL, &ne);
Packit 5e354d
      if (res == SOCKET_ERROR)
Packit 5e354d
	continue; /* FIXME: We ignore this error here.  */
Packit 5e354d
Packit 5e354d
      /* NB that the test on FLAGS guarantees that ?fds is not NULL. */
Packit 5e354d
      if ((flags & FD_READ) && (ne.lNetworkEvents & (FD_READ | FD_ACCEPT)))
Packit 5e354d
	{
Packit 5e354d
	  FD_SET (fd, rfds);
Packit 5e354d
	  cnt++;
Packit 5e354d
	}
Packit 5e354d
      if ((flags & FD_WRITE) && (ne.lNetworkEvents & FD_WRITE))
Packit 5e354d
	{
Packit 5e354d
	  FD_SET (fd, wfds);
Packit 5e354d
	  cnt++;
Packit 5e354d
	}
Packit 5e354d
      if ((flags & FD_CLOSE) && (ne.lNetworkEvents & (FD_OOB | FD_CLOSE)))
Packit 5e354d
	{
Packit 5e354d
	  FD_SET (fd, efds);
Packit 5e354d
	  cnt++;
Packit 5e354d
	}
Packit 5e354d
Packit 5e354d
      WSAEventSelect (fd, NULL, 0); /* We ignore errors.  */
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  /* We ignore errors.  */
Packit 5e354d
  WSACloseEvent (sock_event);
Packit 5e354d
Packit 5e354d
  return cnt;
Packit 5e354d
Packit 5e354d
  /* Cleanup.  */
Packit 5e354d
 err_out:
Packit 5e354d
  if (sock_event != INVALID_HANDLE_VALUE)
Packit 5e354d
    {
Packit 5e354d
      for (i = 0; i < nr_fdobj; i++)
Packit 5e354d
	{
Packit 5e354d
          WSAEventSelect (fdobj[i].fd, NULL, 0); /* We ignore errors.  */
Packit 5e354d
	}
Packit 5e354d
      WSACloseEvent (sock_event); /* We ignore errors.  */
Packit 5e354d
    }
Packit 5e354d
Packit 5e354d
  if (err == ETIMEDOUT)
Packit 5e354d
    return 0;
Packit 5e354d
Packit 5e354d
  errno = err;
Packit 5e354d
  return -1;
Packit 5e354d
}