/*	Generic Thread library W32/UNIX
	Used for creating threads and mutex (Mutually Exclusive) locks on shared resources.
	Functions:
		th_new				Create a new thread.
		th_free				Free a previously created thread.
		th_pid				Get current thread process id.
		th_id				Get current thread id. (for display)

		o_thread			(pthread_t on linux, int on windows) 
		th_oid				Get opaque thread id. 
		th_equal(oid1,oid2) return true if these are the same threads...	

		th_mutex_new		Create new mutex for resource.
		th_mutex_free		Free a previously created mutex resource.
		th_mutex_wait		Wait for rights to mutex resource.
		th_mutex_release	Release rights to mutex resource.

PLEASE NOTE: Use lib_mutex.c, lib_mutex.h to generate and use your own friendly mutex
calls see lib_mutex.h for instructions.

*/

#ifdef __cplusplus
extern "C" {
#endif

#ifndef WIN32
#ifndef done_pthread_h
#define done_pthread_h 1
#include <pthread.h>
#endif
#endif

#ifndef DONE_OTHREAD
#define DONE_OTHREAD 1
#ifdef WIN32
typedef int o_thread;
#else
typedef pthread_t o_thread;
#endif


#ifndef VLIB_THREAD
#	define VLIB_THREAD
#	include <time.h>
#	ifdef WIN32
#		include <windows.h>

		typedef struct THREAD {
			HANDLE h;
		} Thread;

		typedef struct MUTEX {
			char *name;
			char *file;
			int id;
			int wanted;
			int line;
			HANDLE h;
			time_t aquired;
		} Mutex;
#	else
#		include <pthread.h>

		typedef struct THREAD {
			pthread_t h;
		} Thread;

		typedef struct MUTEX {
			char *file;
			char *name;
			int line;
			int id;
			int wanted;
			pthread_mutex_t h;
			int nref;
			o_thread threadid;
			time_t aquired;
		} Mutex;
#	endif

#define th_new(a,b) th_new_real(a,b,__FILE__,__LINE__)
#define th_new_stack(a,b,s) th_new_stack_real(a,b,s,__FILE__,__LINE__)
		
	int th_lib_lock(int *lock, int msec);
	int th_lib_unlock(int *lock);
	Thread *th_new_stack_real(int fn(void *x),void *arg, int stack, char *source, int line);
	Thread *th_new_real(int fn(void *x),void *arg, char *source, int line);
	int th_free(Thread **tt);

int th_set_spinlock(int x);
	int th_id(void);
	int th_pid(void);	

	Mutex *th_mutex_new_remember(char *name, char *in_file, int at_line);
#define th_mutex_new(name) th_mutex_new_remember(name, __FILE__, __LINE__)
	void th_mutex_free(Mutex *m);

	int th_mutex_wait_or_die_real(Mutex *m, unsigned int timeout, char *in_file, int at_line);
#define th_mutex_wait_or_die(m,timeout) th_mutex_wait_or_die_real(m,timeout,__FILE__,__LINE__)
#define th_mutex_get_or_die(m) th_mutex_wait_or_die_real(m,120000,__FILE__,__LINE__)
	int th_mutex_wait_remember(Mutex *m, unsigned int timeout, char *in_file, int at_line, int notimeout);
#define th_mutex_wait(m, timeout)	th_mutex_wait_remember(m, timeout, __FILE__, __LINE__,FALSE)
#define th_mutex_get(m)				th_mutex_wait_remember(m, 999999, __FILE__, __LINE__,TRUE)

	/* RMH: queued thread wait functions */
	void th_mutex_queue_init();  //Must call ONCE before using 'queue' funcs
	void th_mutex_queue_clear(); //Must call ONCE after finished with 'queue' funcs
	int th_mutex_get_queue_real(Mutex *m, char *in_file, int at_line);
#define th_mutex_get_queue(m)		th_mutex_get_queue_real(m,__FILE__,__LINE__)
	
	int th_mutex_release(Mutex *m);	

	int th_bad_get(int n, char *name);

	int th_bad_mutex(Mutex *m) ;
	int th_exit(int x);
	int th_free_idle_thread(Thread *tt);
	int th_kill_all_threads_exit(void); /* Proper code should use these two calls for full initilization */ 
	int th_init_threads(void);          /* Proper code should use these two calls for full initilization */ 
	int th_new_reuse(int fn(void *x),void *arg);
	int th_new_reuse_th(int fn(void *x),void *arg, Thread **th);
	int th_reuse_killall(void);
	int th_kill(Thread *tt, int x);
	int th_cpu_msec(Thread *tt);
	Thread *th_new_or_idle(int fn(void *x),void *arg);
#endif

#ifdef __cplusplus
}
#endif

int th_equal(o_thread t1, o_thread t2);
o_thread th_oid(void);
#endif

char *th_showid(o_thread pt, char *tmp);
void th_new_stack_bug(int fn(void *x),void *arg, int vstack);
void th_new_stack_bug2(int fn(void *x),void *arg, int vstack);
int th_analyze_show(void);

