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

pthread_barrier_t theBarrier;
int aGlobalVar = 0;
pthread_mutex_t aMutex  = PTHREAD_MUTEX_INITIALIZER;

typedef struct {
	pthread_t *tid;
	int priority;
} ThreadInfo;


void * myFunction(void *args) {
	ThreadInfo *myInfo = (ThreadInfo*) args;
	int policy;
	
	//wait for barrier release
	pthread_barrier_wait(&theBarrier);
	//get vars from passed arg after tid is created
	int priority = myInfo->priority;
	pthread_t tid = *(myInfo->tid);
	printf("I'm thread %d with priority %d and I have escaped the barrier\n", (int) tid, priority);
	
	//grab/wait for grab the mutex
	pthread_mutex_lock(&aMutex);
	printf("I'm thread %d with priority %d and I have the mutex\n", (int) tid, priority);
	aGlobalVar++;
	
	//unlock mutex
	pthread_mutex_unlock(&aMutex);
}

int main(int argc, char *argv[]) {
	pthread_attr_t attr;
	struct sched_param param;
	pthread_t threads[8];
	int i;
	int priority = 8;
	
	//set pthread attributes
	pthread_attr_init(&attr);
	pthread_attr_setschedpolicy(&attr, SCHED_RR);
	pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
	pthread_barrier_init(&theBarrier, NULL, 8);
	
	for(i = 0; i < 8; i++) {
		//initialize vars
		ThreadInfo *myInfo = malloc(sizeof(ThreadInfo));
		void *aStack = malloc(4096);
		
		//set thread info to pass as args
		myInfo->tid = &threads[i];
		myInfo->priority = priority;
		
		//set priority
		pthread_attr_getschedparam(&attr, &param);
		param.sched_priority = priority;
		pthread_attr_setschedparam (&attr, &param);
		
		//set stack size and address
		pthread_attr_setstack(&attr, aStack, 4096);
		//create thread
		pthread_create(&threads[i], &attr, myFunction, myInfo);
		if(i % 2 == 1) {
			priority++;
		}
	}
	for(i = 0; i < 8; i++) {
		pthread_join(threads[i], NULL);
	}
	
}
