#include <clib/cfathread.h>

#include <stdio.h>
#include <stdlib.h>

thread_local struct drand48_data buffer = { 0 };
int myrand() {
	long int result;
	lrand48_r(&buffer, &result);
	return result;
}


enum Constants { blocked_size = 20 };
cfathread_t volatile blocked[blocked_size];

void Worker( cfathread_t this ) {
	for(int i = 0; i < 1000; i++) {
		int idx = myrand() % blocked_size;
		if(blocked[idx]) {
			cfathread_t thrd = __atomic_exchange_n(&blocked[idx], NULL, __ATOMIC_SEQ_CST);
			cfathread_unpark( thrd );
		} else {
			cfathread_t thrd = __atomic_exchange_n(&blocked[idx], this, __ATOMIC_SEQ_CST);
			cfathread_unpark( thrd );
			cfathread_park();
		}
	}
	printf("Done\n");
}

volatile bool stop;
void Unparker( cfathread_t this ) {
	while(!stop) {
		int idx = myrand() % blocked_size;
		cfathread_t thrd = __atomic_exchange_n(&blocked[idx], NULL, __ATOMIC_SEQ_CST);
		cfathread_unpark( thrd );
		int r = myrand() % 20;
		for( int i = 0; i < r; i++ ) {
			cfathread_yield();
		}
	}
	printf("Done Unparker\n");
}


int main() {
	stop = false;
	for(int i = 0; i < blocked_size; i++) {
		blocked[i] = NULL;
	}

	cfathread_setproccnt( 4 );
	cfathread_t u = cfathread_create( Unparker );
	{
		cfathread_t t[20];
		for(int i = 0; i < 20; i++) {
			t[i] = cfathread_create( Worker );
		}
		for(int i = 0; i < 20; i++) {
			cfathread_join( t[i] );
		}
	}
	stop = true;
	cfathread_join(u);
	cfathread_setproccnt( 1 );
}