/*
Generic Thread library W32/UNIX

createthread 
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef WIN32
#include <windows.h>
#endif
#include "thread.h"
void emsg(char * arg_list, ...);
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

#ifdef WIN32

int th_id(void)
{
	return GetCurrentThreadId();
}
int th_pid(void)
{
	return GetCurrentProcessId();
}
Thread *th_new(int fn(void *x),void *arg)
{
	Thread *t;
	DWORD thid;
	t = calloc(1,sizeof(Thread));
	t->h = CreateThread(
		NULL,	/* Not inherited handle */
		5000,	/* Stack */
		(LPTHREAD_START_ROUTINE) fn,(LPVOID) arg,
		0,	/* Start immediately */
		&thid);	/* Thread id stored  */
	return t;
}
int th_free(Thread **tt)
{
	Thread *t=*tt;
	if (!CloseHandle( (HANDLE) t->h)) {
		emsg("Thread close failed\n");
		t->h = 0;
		free(t);
		*tt = NULL;
		return FALSE;
	}
	t->h = 0;
	free(t);
	*tt = NULL;
	return TRUE;
}
void th_mutex_free(Mutex *m)
{
	CloseHandle(m->h);
	free(m);
}
Mutex *th_mutex_new(char *name) 
{
	Mutex *m;
	m = calloc(1,sizeof(Mutex));
	m->h = 	CreateMutex(NULL,FALSE,NULL);
	return m;
}
int th_mutex_wait(Mutex *m, unsigned int timeout)
{
	int r;
	r = WaitForSingleObject(m->h,timeout);
	if (r==WAIT_TIMEOUT) return FALSE;
	if (r==WAIT_FAILED) return FALSE;
	return TRUE;
}
int th_mutex_release(Mutex *m)
{
	if (!ReleaseMutex(m->h)) {
		emsg("Releasing mutex failed\n");
		abort();
	}
	return TRUE;
}
int th_exit(int x)
{
	ExitThread(x); /* doesn't return */
	return TRUE;
}


#else
/* Unix PTHREAD verison */

#ifdef DOTHREADS
int th_id(void)
{
	return (int) pthread_self();
}
int th_pid(void)
{
	return getpid();
}


Thread *th_new(int fn(void *x),void *arg)
{
	Thread *t=malloc(sizeof(Thread));
	pthread_attr_t attr;

	pthread_attr_init(&attr);	
        if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)!=0)  /* So signals work */ 
		imsg("Thread setscope failed %s\n",strerror(errno));
        if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)!=0)  /* So resources are freed */
		imsg("Thread setdetachstate failed %s\n",strerror(errno));
#ifdef SETSTACK
        pthread_attr_setstacksize(&attr, 1000000); /* on freebsd stack does NOT grow!!! */
#endif
	
	if (pthread_create(&t->h,&attr,(void * (*)(void *)) fn,arg)!=0) {
		emsg("Thread creation failed %s\n",strerror(errno));
		return NULL;	
	}
	return t;
}	
int th_free(Thread **tt)
{
	Thread *t=*tt;
	imsg("No obvious close function to get rid of pthread handles\n");
	free(t);
	*tt=NULL;
	return TRUE;
}
int th_exit(int x)
{
	pthread_exit(&x); /* doesn't return */
	return TRUE;
}
Mutex *th_mutex_new(char *name) 
{
	Mutex *m;

	m = calloc(1,sizeof(Mutex));
/*	m->h.m_kind =  PTHREAD_MUTEX_RECURSIVE_NP;*/
/*	m->h = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;*/

	if (pthread_mutex_init(&m->h,NULL)!=0) {
		emsg("Mutex init failed %s\n",strerror(errno));		
	}
	return m;
}
int th_mutex_wait(Mutex *m, unsigned int timeout)
{
	int r;

/*printf("mutex_lock %d %d %d\n",m->nref,m->threadid,th_id());*/
	if (m->threadid==th_id()) {
		m->nref++;
		return TRUE;
	}
	r = pthread_mutex_lock(&(m->h));
	if (r==0) {
		m->threadid = th_id();
		m->nref = 0;
		return TRUE;
	}
	emsg("Mutex lock failed\n");
	printf("Mutex lock failed\n");
	return FALSE;
}
int th_mutex_release(Mutex *m)
{
	if (m->nref>0) {
		if (m->threadid != th_id()) {
			emsg("threadid wrong in mutex_release\n");
			abort();
		}
		m->nref--;
		return TRUE;
	}	
	m->threadid = -1;
	if (pthread_mutex_unlock(&(m->h))==0) return TRUE;
	emsg("Releasing mutex failed\n");
	abort();
	return FALSE;
}
void th_mutex_free(Mutex *m)
{
	pthread_mutex_destroy(&(m->h));
	free(m);
}
#else
int th_id(void)
{
	return 0;
}

#endif
#endif

