/* thread.c */

#include <stdlib.h>
#ifdef _WIN32
	#define WIN32_LEAN_AND_MEAN
	#include <windows.h>
	#define THREAD_HANDLE_T HANDLE
	#define MTHREAD_THREADENTRY_T unsigned int WINAPI
#else
	#include <pthread.h>
	#define THREAD_HANDLE_T pthread_t
	#define MTHREAD_THREADENTRY_T void*
#endif
#include "thread.h"

/* Common */

struct thread_data_t {
	THREAD_HANDLE_T hThread;
	thread_func     func;
	void*           data;
};

thread_t thread_new(thread_func tf, void* data) {
	thread_t th = (thread_t) malloc(sizeof(struct thread_data_t));
	
	th->hThread = 0;
	th->func    = tf;
	th->data    = data;
	return th;
}

MTHREAD_THREADENTRY_T entryPoint(void* data) {
#ifndef _WIN32
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
#endif

	thread_t th = (thread_t)data;
	th->func(th->data);
	return 0;
}

/* Windows-only */

#ifdef _WIN32

void thread_start(thread_t th) {
	th->hThread = CreateThread(
		0, 0, (LPTHREAD_START_ROUTINE)entryPoint, th, 0, NULL
	);
}

void thread_join(thread_t th) {
	WaitForSingleObject(th->hThread, INFINITE);
}

void thread_free(thread_t th) {
	if (th->hThread) CloseHandle(th->hThread);
	free(th);
}

/* Pthreads-only */

#else

void thread_start(thread_t th) {
	pthread_create(&(th->hThread), NULL, entryPoint, th);
}

void mtThread::join() {
	void* exit_code;
	pthread_join(thread_h, &exit_code);
}

void thread_free(thread_t th) {
	if (th->hThread) pthread_cancel(th->hThread);
	free(th);
}

#endif
