#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(int thread_id);
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(int t_id)
{
	int next_pid;
	int i,j;
	int err;
	
	for (j=0;j<PID_MAX-PID_MIN+1;j++)
		{
		printf("%d",pid_map[j]);
		}
	printf("\n");
	
	
	printf("Thread %d trying to lock...%d\n",t_id,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;
						
				
					
				}
		}
	return -999;
	 
}
/**
 * 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;
		//printf("\nthread %d launched do_something\n", thread_id);
		for (i=0;i<1;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(thread_id);
			
			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--;
		return;
	}

	
int main()
{
	int i,err;
	time_t t;
	
	pthread_t tid[NUM_THREADS];
	if (pthread_mutex_init(&mutex, NULL) != 0)
    {
        printf("\n mutex init failed\n");
        return 1;
    }
	
	
	srand((unsigned) time(&t));
	allocate_map();
	while(i < 20)
    {
        err = pthread_create(&(tid[i]), NULL, &do_something, (void*)i);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        i++;
		thread_counter++;
		//printf("\nthread %d created\n", i);
    }
	
	while (thread_counter >0)
	{
		sleep(1);
	}
	 pthread_mutex_destroy(&mutex);
	printf("DONE!\n");
}



