#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>


#define PID_MIN  	0
#define PID_MAX 	3

#define NUM_THREADS 100
#define ITERATIONS	10
#define SLEEP		5




int S;

/* mutex lock for accessing pid_map */
pthread_mutex_t mutex;

int pid_map[PID_MAX-PID_MIN+1];
int thread_counter =0;


int allocate_map(void);
int allocate_pid(void);
void release_pid(int pid);


 // Allocates the pid map.
 
int allocate_map(void) 
{
	/*initilize to zero explicitly just to make sure*/
	int i;
	for (i =0;i<PID_MAX-PID_MIN+1;i++)
	{
		pid_map[i] = 0;
		S++;
		
	}
	printf("map allocated!S=%d\n",S);
	return 1;
}

/**
 * Allocates a pid
 */
int allocate_pid(void)
{
	int next_pid;
	int i;
	while (S<=0)
	{}
	
	pthread_mutex_lock(&mutex);
	S--;
	for (i =0;i<PID_MAX-PID_MIN;i++)
		{
			if (pid_map[i] == 0)
				{
					pid_map[i] = 1;
					next_pid=i;
					pthread_mutex_unlock(&mutex);
					return next_pid+PID_MIN;
						
				
					
				}
		}
	
	 
}
/**
 * Releases a pid
 */
void release_pid(int pid)
{
	pid = pid-PID_MIN;
	pid_map[pid] = 0;
	S++;
}

void *do_something(void *threadid)
	{
		int  my_pid;
		long thread_id;
		int i;
		double r;
		thread_id= (long)threadid;
		
		for (i=0;i<ITERATIONS;i++)
		{
			r = rand()%50; // 0-50
			r=r/10;
			//r=0.1;
			//printf("thread %d trying to allocate PID..., S=%d\n",thread_id,S);
			my_pid=allocate_pid();

			printf("Thread number %d got PID %d S=%d\n", thread_id, my_pid,S);
			sleep(r);
			release_pid(my_pid);
			printf("Thread number %d released PID %d S=%d \n", thread_id, my_pid,S);
		}
		thread_counter--;
		pthread_exit(NULL);
	}

	
void main()
{
	int i,rc;
	time_t t;
	pthread_t tid[NUM_THREADS];
	srand((unsigned) time(&t));
	allocate_map();
	for (i =0;i<10;i++)
	{
		//printf("In main: creating thread %d S=%d\n", i,S);
		thread_counter++;
		rc=pthread_create(&tid[i], NULL, do_something, (void *)i);
		
	}
	while (thread_counter >0)
	{
		sleep(1);
	}
	printf("DONE!\n");
}



