//	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-
//
//	win32compat.c
//
//	Implementation of the tiny Win32 "event" emulation used by
//	epd2wb.c.  See win32compat.h for details.
//
//	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-

#include "win32compat.h"
#include <stdlib.h>
#include <time.h>
#include <errno.h>

//	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-

HANDLE CreateEvent(void * psaAttr, BOOL fManualReset, BOOL fInitialState,
	void * szName)
{
	HANDLE	h = malloc(sizeof(EVENT));

	(void)psaAttr;
	(void)szName;
	if (h == NULL)
		return NULL;
	pthread_mutex_init(&h->mutex, NULL);
	pthread_cond_init(&h->cond, NULL);
	h->fManualReset = fManualReset;
	h->fSignaled = fInitialState;
	return h;
}

//	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-

void SetEvent(HANDLE h)
{
	pthread_mutex_lock(&h->mutex);
	h->fSignaled = TRUE;
	pthread_cond_signal(&h->cond);
	pthread_mutex_unlock(&h->mutex);
}

//	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-

//	Waits for the event to become signaled, or for "dwMilliseconds" to
//	elapse, whichever happens first ("INFINITE" waits forever).  If the
//	event is auto-reset (the only kind epd2wb.c creates), a successful
//	wait clears it back to non-signaled, just like Win32.

DWORD WaitForSingleObject(HANDLE h, DWORD dwMilliseconds)
{
	struct timespec	ts;
	int	rc = 0;

	if (dwMilliseconds != INFINITE) {
		clock_gettime(CLOCK_REALTIME, &ts);
		ts.tv_sec += dwMilliseconds / 1000;
		ts.tv_nsec += (long)(dwMilliseconds % 1000) * 1000000L;
		if (ts.tv_nsec >= 1000000000L) {
			ts.tv_nsec -= 1000000000L;
			ts.tv_sec++;
		}
	}
	pthread_mutex_lock(&h->mutex);
	while (!h->fSignaled && (rc == 0)) {
		if (dwMilliseconds == INFINITE)
			rc = pthread_cond_wait(&h->cond, &h->mutex);
		else
			rc = pthread_cond_timedwait(&h->cond, &h->mutex, &ts);
	}
	if (h->fSignaled) {
		if (!h->fManualReset)
			h->fSignaled = FALSE;
		pthread_mutex_unlock(&h->mutex);
		return WAIT_OBJECT_0;
	}
	pthread_mutex_unlock(&h->mutex);
	return WAIT_TIMEOUT;
}

//	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-	-

void CloseHandle(HANDLE h)
{
	if (h == NULL)
		return;
	pthread_mutex_destroy(&h->mutex);
	pthread_cond_destroy(&h->cond);
	free(h);
}
