#include <v_lib.h>

#if 0

#define	NUM_THREADS		5

u32_t	key;

void	print_specific(void)
{
	printf("Thread specific is %d\n",
		(unsigned)threadGetSpecific(key));
}

void V_CALL
thread_proc(void *arg)
{
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	printf("Arg: %X\n",(unsigned)arg);
	threadSetSpecific(key,(void*)arg);
	print_specific();
	timeDelay((u32_t)1000);
	printf("Exit: %X\n",(unsigned)arg);
	threadExit((u32_t)arg);
}

mutex_t	l;

void V_CALL
mutex_thread_proc(void *arg)
{
	vboolean already_locked;
	already_locked=!mutexTryLock(l);
	printf("Thread %d: mutex %s, locking for 1 second\n",
		(unsigned)arg,already_locked ? "already locked" : "free");
	if(already_locked) /* seems to be not intuitive ... */
		mutexLock(l);
	printf("Thread %d: mutex aquired\n",(unsigned)arg);
	timeDelay(1000);
	printf("Thread %d: unlocking mutex\n",(unsigned)arg);
	mutexUnlock(l);
}

int main()
{
	int i;
	thread_t threads[NUM_THREADS];
	u32_t ret_vals[NUM_THREADS];
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
    key=threadCreateKey();
	if(!key)
	{
		printf("threadCreateKey() failed !\n");
		return -1;
	}
	puts("Setting specific to 100");
	threadSetSpecific(key,(void*)100);
	print_specific();
	l=mutexCreate();
	printf("\nThread demo: spawning %d threads...\n\n",NUM_THREADS);
	for(i=0;i<NUM_THREADS;i++)
	{
		threads[i]=threadCreate(thread_proc,(void*)i);
		timeDelay(100);
	}
	print_specific();
	puts("Setting specific to 101");
	threadSetSpecific(key,(void*)101);
	print_specific();
	for(i=0;i<NUM_THREADS;i++)
		threadJoin(threads[i],&ret_vals[i]);
	for(i=0;i<NUM_THREADS;i++)
	{
		printf("Thread %x exited with code %lu\n",
			(unsigned)threads[i],ret_vals[i]);
	}
	printf("\nMutex demo: spawning %d threads...\n\n",NUM_THREADS);
	for(i=0;i<NUM_THREADS;i++)
	{
		threads[i]=threadCreate(mutex_thread_proc,(void*)i);
		timeDelay(10);
	}
	for(i=0;i<NUM_THREADS;i++)
		threadJoin(threads[i],NULL);
	mutexDestroy(l);
	print_specific();
	threadDestroyKey(key);
    memPrintStats();
	return 0;
}

#endif

#define MUTEX_BREAK

#ifdef MUTEX_BREAK

/*
 * Let's try to break LibV down.
 *
 * Core dump will be produced in normal mode; error messages if
 * defined(CHECKED_BUILD).
 */

void V_CALL _t(void *arg)
{
	mutex_t m = (mutex_t)arg;
	
	puts("START");
	fflush(stdout);
	
	mutexLock(m);
	mutexLock(m);

	puts("CONT");
	fflush(stdout);
	
	mutexUnlock(m);
	mutexUnlock(m);

	threadExit(0);
}
	
int main()
{
	mutex_t m;
	thread_t t1, t2;

	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	
	m=mutexCreate();
	
	mutexLock(m);
	mutexLock(m);
	
	t1 = threadCreate(_t,m);
	t2 = threadCreate(_t,m);
	
	timeDelay(100);
	
	puts("mutexDestroy");
	
	mutexDestroy(m);
	
	threadJoin(t1,NULL);
	threadJoin(t2,NULL);
		
	memPrintObjStats();
	memPrintMemStats();

	return 0;	
}

#elif defined(RECURSION_CHECK)

/*
 * Recursion check
 */

void V_CALL _t(void *arg)
{
	mutex_t m = (mutex_t)arg;
	puts("thread START");
	fflush(stdout);

	mutexLock(m);
	mutexLock(m);

	timeDelay(10);
	
	puts("thread CONT");
	fflush(stdout);
	
	mutexUnlock(m);
	mutexUnlock(m);

	timeDelay(10);
	
	puts("thread EXIT");
	fflush(stdout);

	threadExit(0);
}
	
int main()
{
	mutex_t m;
	thread_t t1, t2;

	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	
	m=mutexCreate();
	
	t1 = threadCreate(_t,m);
	t2 = threadCreate(_t,m);
	
	timeDelay(100);
	
	threadJoin(t1,NULL);
	threadJoin(t2,NULL);
		
	mutexDestroy(m);
	
	memPrintObjStats();
	memPrintMemStats();

	return 0;	
}

#endif	/* RECURSION_CHECK */
