#include "stdafx.h"
#include "apr_general.h"
#include "apr_strings.h"
#include "apr_thread_proc.h"
#include "apr_lock.h"

static apr_pool_t *context;
static apr_lock_t *lock;
static long counter = 25000;

void DeleteData( void *data) {
	printf( "Initial Count is %ld\n", *((long *)data));
	return;
}

void * APR_THREAD_FUNC ExThreadFunc1( void *data)
{
	long *count;
	apr_threadkey_t *threadData;
	long initialCount = *((long *)data);

	if( apr_threadkey_private_create( &threadData, DeleteData, context) != APR_SUCCESS) {
		printf( "Could not create Private Data area");
		exit( -1);
	}
	apr_threadkey_private_set( &initialCount, threadData);

	if( apr_threadkey_private_get( (void **)&count, threadData) != APR_SUCCESS) {
		printf( "Oops an error\n");
		exit( -1);
	}

    int i;
    for (i = 0; i < *count; i++) {
        apr_lock_acquire(lock);
        counter ++;
        apr_lock_release(lock);
    }
	return NULL;
} 

void * APR_THREAD_FUNC ExThreadFunc2( void *data)
{
	while( counter > 0) {
        apr_lock_acquire( lock);
		counter --;
        apr_lock_release( lock);
    }
	return NULL;
} 

void TstThreadWithLock() {
	apr_status_t status;
	apr_thread_t *thread1;
	apr_thread_t *thread2;
	long initialCount = 1000;

    status = apr_lock_create( &lock, APR_MUTEX, APR_INTRAPROCESS, "my.lock", context); 

	if( apr_thread_create( &thread1, NULL, ExThreadFunc1, &initialCount, context) != APR_SUCCESS) {
		printf( "Could not create the thread\n");
		exit( -1);
	}

	
	if( apr_thread_create( &thread2, NULL, ExThreadFunc2, NULL, context) != NULL) {
		printf( "Could not create the thread\n");
		exit( -1);
	}

    apr_thread_join( &status, thread1);
    apr_thread_join( &status, thread2);
		
}

void * APR_THREAD_FUNC ExThreadFunc( void *data)
{
	printf( "Hello world");
	// Question: Does this really do anything
	return NULL;
} 

void TstSimpleThread() {
	apr_thread_t *thread;
	
	if( apr_thread_create(&thread, NULL, ExThreadFunc, NULL, context) != NULL) {
		printf( "Could not create the thread\n");
		exit( -1);
	}
	apr_status_t status;

    apr_thread_join( &status, thread);
	return;
}


void APRThreads() {
	// Create the pool context
    if (apr_pool_create(&context, NULL) != APR_SUCCESS) {
        fprintf(stderr, "Couldn't allocate context.");
        exit(-1);
    }

	TstSimpleThread();
	TstThreadWithLock();
		
	apr_pool_destroy( context);
	return;
}