#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <pthread.h>

#define NUMELEM 100

typedef struct _cagssd_task cagssd_task;
struct _cagssd_task {
	void *extra;
	cagssd_task *_next;
};

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

cagssd_task *pool = NULL;

void cagssd_enqueue(cagssd_task *task)
{
	task->_next = pool;
	pool = task;
}
cagssd_task *cagssd_dequeue(void)
{
	cagssd_task *retval;
	if(pool == NULL) {
		return NULL;
	}
	retval = pool;
	pool = retval->_next;
	return retval;
}
//#define WITHMUTEX
#ifdef WITHMUTEX
void _cagssd_enqueue(cagssd_task *task)
{
	pthread_mutex_lock(&mutex);
	task->_next = pool;
	pool = task;
	pthread_mutex_unlock(&mutex);
}
cagssd_task *_cagssd_dequeue(void)
{
	pthread_mutex_lock(&mutex);
	cagssd_task *retval;
	if(pool == NULL) {
		pthread_mutex_unlock(&mutex);
		return NULL;
	}
	retval = pool;
	pool = retval->_next;
	pthread_mutex_unlock(&mutex);
	return retval;
}
#else
void _cagssd_enqueue(cagssd_task *task)
{
	task->_next = pool;
	while( !__sync_bool_compare_and_swap(&pool,task->_next,task)) {
		task->_next = pool;
	}
}
cagssd_task *_cagssd_dequeue(void)
{
	cagssd_task *retval;
	if(pool == NULL) {
		return NULL;
	}
	retval = pool;
	while(! __sync_bool_compare_and_swap(&pool,retval,retval->_next)) {
		retval = pool;
	}
	return retval;
}
#endif
void pool_hitter_thread()
{
	cagssd_task *tmp;
	for(uint32_t i=0;i<100000;i++) {
		tmp = _cagssd_dequeue();
		if(tmp != NULL) {
			_cagssd_enqueue(tmp);
		}
	}
	pthread_exit((void *) 0);
}


int main(int argc, char**argv)
{
	pthread_t t[1000];
	cagssd_task *tmp;
	// put 100 thingies in the pool
	for(uint32_t i=0; i<100; i++) {
		tmp = (cagssd_task *)malloc(sizeof(cagssd_task));
		_cagssd_enqueue(tmp);
	}

	 for(uint32_t i=0;i<4;i++) {
		if(pthread_create(&t[i], NULL, (void *)&pool_hitter_thread, NULL) != 0) {
			fprintf(stderr, "Error starting thread %d......\n", i);
			exit(0);
		}
	}

	for(uint32_t i=0;i<4;i++) {
		pthread_join(t[i], NULL);
	}
	//count how many are still there
	uint32_t count=0;
	tmp = _cagssd_dequeue();
	while(tmp != NULL) {
		count++;
		tmp = _cagssd_dequeue();
	}
	if(count == NUMELEM) {
		printf("the right number of elements is in the pool\n");
	} else {
		printf("ERROR, the code sucks\n");
	}
}

