text: /*
   * Code for simulating pthreads API on Windows.  This is Git-specific,
   * but it is enough for Numexpr needs too.
   *
   * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
   *
   * DISCLAIMER: The implementation is Git-specific, it is subset of original
   * Pthreads API, without lots of other features that Git doesn't use.
   * Git also makes sure that the passed arguments are valid, so there's
   * no need for double-checking.
   */
  
  #include "pthread.h"
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <process.h>
  #include <errno.h>
  #include <limits.h>
  
  
  void die(const char *err, ...)
  {
  	printf("%s", err);
  	exit(-1);
  }
  
  static unsigned __stdcall win32_start_routine(void *arg)
  {
  	pthread_t *thread = arg;
  	thread->arg = thread->start_routine(thread->arg);
  	return 0;
  }
  
  int pthread_create(pthread_t *thread, const void *unused,
  		   void *(*start_routine)(void*), void *arg)
  {
  	thread->arg = arg;
  	thread->start_routine = start_routine;
  	thread->handle = (HANDLE)
  		_beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
  
  	if (!thread->handle)
  		return errno;
  	else
  		return 0;
  }
  
  int win32_pthread_join(pthread_t *thread, void **value_ptr)
  {
  	DWORD result = WaitForSingleObject(thread->handle, INFINITE);
  	switch (result) {
  		case WAIT_OBJECT_0:
  			if (value_ptr)
  				*value_ptr = thread->arg;
  			return 0;
  		case WAIT_ABANDONED:
  			return EINVAL;
  		default:
  			return GetLastError();
  	}
  }
  
  int pthread_cond_init(pthread_cond_t *cond, const void *unused)
  {
  	cond->waiters = 0;
  	cond->was_broadcast = 0;
  	InitializeCriticalSection(&cond->waiters_lock);
  
  	cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
  	if (!cond->sema)
  		die("CreateSemaphore() failed");
  
  	cond->continue_broadcast = CreateEvent(NULL,	/* security */
  				FALSE,			/* auto-reset */
  				FALSE,			/* not signaled */
  				NULL);			/* name */
  	if (!cond->continue_broadcast)
  		die("CreateEvent() failed");
  
  	return 0;
  }
  
  int pthread_cond_destroy(pthread_cond_t *cond)
  {
  	CloseHandle(cond->sema);
  	CloseHandle(cond->continue_broadcast);
  	DeleteCriticalSection(&cond->waiters_lock);
  	return 0;
  }
  
  int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
  {
  	int last_waiter;
  
  	EnterCriticalSection(&cond->waiters_lock);
  	cond->waiters++;
  	LeaveCriticalSection(&cond->waiters_lock);
  
  	/*
  	 * Unlock external mutex and wait for signal.
  	 * NOTE: we've held mutex locked long enough to increment
  	 * waiters count above, so there's no problem with
  	 * leaving mutex unlocked before we wait on semaphore.
  	 */
  	LeaveCriticalSection(mutex);
  
  	/* let's wait - ignore return value */
  	WaitForSingleObject(cond->sema, INFINITE);
  
  	/*
  	 * Decrease waiters count. If we are the last waiter, then we must
  	 * notify the broadcasting thread that it can continue.
  	 * But if we continued due to cond_signal, we do not have to do that
  	 * because the signaling thread knows that only one waiter continued.
  	 */
  	EnterCriticalSection(&cond->waiters_lock);
  	cond->waiters--;
  	last_waiter = cond->was_broadcast && cond->waiters == 0;
  	LeaveCriticalSection(&cond->waiters_lock);
  
  	if (last_waiter) {
  		/*
  		 * cond_broadcast was issued while mutex was held. This means
  		 * that all other waiters have continued, but are contending
  		 * for the mutex at the end of this function because the
  		 * broadcasting thread did not leave cond_broadcast, yet.
  		 * (This is so that it can be sure that each waiter has
  		 * consumed exactly one slice of the semaphor.)
  		 * The last waiter must tell the broadcasting thread that it
  		 * can go on.
  		 */
  		SetEvent(cond->continue_broadcast);
  		/*
  		 * Now we go on to contend with all other waiters for
  		 * the mutex. Auf in den Kampf!
  		 */
  	}
  	/* lock external mutex again */
  	EnterCriticalSection(mutex);
  
  	return 0;
  }
  
  /*
   * IMPORTANT: This implementation requires that pthread_cond_signal
   * is called while the mutex is held that is used in the corresponding
   * pthread_cond_wait calls!
   */
  int pthread_cond_signal(pthread_cond_t *cond)
  {
  	int have_waiters;
  
  	EnterCriticalSection(&cond->waiters_lock);
  	have_waiters = cond->waiters > 0;
  	LeaveCriticalSection(&cond->waiters_lock);
  
  	/*
  	 * Signal only when there are waiters
  	 */
  	if (have_waiters)
  		return ReleaseSemaphore(cond->sema, 1, NULL) ?
  			0 : GetLastError();
  	else
  		return 0;
  }
  
  /*
   * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
   * is called while the mutex is held that is used in the corresponding
   * pthread_cond_wait calls!
   */
  int pthread_cond_broadcast(pthread_cond_t *cond)
  {
  	EnterCriticalSection(&cond->waiters_lock);
  
  	if ((cond->was_broadcast = cond->waiters > 0)) {
  		/* wake up all waiters */
  		ReleaseSemaphore(cond->sema, cond->waiters, NULL);
  		LeaveCriticalSection(&cond->waiters_lock);
  		/*
  		 * At this point all waiters continue. Each one takes its
  		 * slice of the semaphor. Now it's our turn to wait: Since
  		 * the external mutex is held, no thread can leave cond_wait,
  		 * yet. For this reason, we can be sure that no thread gets
  		 * a chance to eat *more* than one slice. OTOH, it means
  		 * that the last waiter must send us a wake-up.
  		 */
  		WaitForSingleObject(cond->continue_broadcast, INFINITE);
  		/*
  		 * Since the external mutex is held, no thread can enter
  		 * cond_wait, and, hence, it is safe to reset this flag
  		 * without cond->waiters_lock held.
  		 */
  		cond->was_broadcast = 0;
  	} else {
  		LeaveCriticalSection(&cond->waiters_lock);
  	}
  	return 0;
  }
  