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


#define PID_MIN  	300
#define PID_MAX 	350

#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;
int thread_counter =0;


int allocate_map(void);
int allocate_PID(int thread_id); //not (void) purely for a nicer output, it shows therad id
void release_pid(int pid);



 // Allocates the pid map.
 
int allocate_map(void) 
{
	/*initilize to zero explicitly just to make sure*/
	int i;
		pid_map =(int*)malloc((PID_MAX-PID_MIN+1)*sizeof(int));
		if (pid_map == NULL)
			return -1;
		
		// the structure is a bitmap:
		//0 - available,
		//1 - taken
        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;
	
	if (S<=0)
		return -1; //NOT thread SAFE
	
    pthread_mutex_lock(&mutex);
	while (S<=0)
    {}
	
	for (i =0;i<PID_MAX-PID_MIN+1;i++)
		{
			if (pid_map[i] == 0)
				{
                    
                    S--;
                    printf("Thread number %d got PID %d S=%d\n", t_id, i+PID_MIN,S);
                    pid_map[i] = 1;
					next_pid=i;
					pthread_mutex_unlock(&mutex);
					return (next_pid+PID_MIN);
						
				
					
				}
		}
	//for debug purposes:
	//if a thread will pass mutex and S-semaphore
	//but won't find a PID then -999 will be returned
	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<10;i++)
		while(2>1)	
		{
			r = rand()%50; // 0-50
			r=r/10;
			
			sleep(r/100);
			my_pid=allocate_PID(thread_id); //will return PID or "-1" if unsucessfull
			if (my_pid==-1)
				{
					printf("thread %d was NOT able allocate PID\n",thread_id);	
				
				}
			else
				{
					sleep(r);
					release_pid(my_pid);
				
					printf("Thread number %d released PID %d \tPIDs available: %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 < NUM_THREADS)
    {
        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");
}



