#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "Syscalls.h"
#define TRACE 0

/************************************************************************/
/*                                                                      */ 
/* This is the test program for CSC415, PJ2, Spring 2001.  It generates */
/* semaphore activities.  Initially, it creates N semaphores :          */
/* key, key+1, ..., key+N-1, then it repeatedly does waitSem() or       */
/* signalSem() on each of the N semaphores.                             */
/*                                                                      */ 
/* This program can be executed many times to create multiple clients.  */
/* There are exactly six input arguments :                              */
/*                                                                      */ 
/*      argv[0] = program name                                          */
/*      argv[1] = first key value                                       */
/*      argv[2] = number of semaphores, between 1 to 5                  */
/*      argv[3] = init value. Set this value for all semaphores         */
/*      argv[4] = # of loops for semWait() or semSignal()               */
/*      argv[5] = 1 do semWait(), 0 do semSignal()                      */ 
/*                                                                      */ 
/*  Example : a.out 777 2 0 10 1                                        */ 
/*            This create two semaphores with key = 777 & 778           */
/*            Initial value of each semaphore is set to 0               */
/*            Repeat semWait() on each semaphore 10 times               */
/*                                                                      */ 
/* Note : you may modify this program to create more options            */
/*        if you want to see more trace output, set the above TRACE 1   */
/*                                                                      */ 
/************************************************************************/

/* Global variables */
int id[5], flag, key, init, numLoops,numSemaphores;


/* process input arguments */
void GetArguments(int argc, char *argv[])
{

     if ( argc != 6 ) {
        printf("PID=%d : Error! argc=%d != 6, cannot run this program!\n",
               getpid(), argc);
        printf("Usage : progName key numSemaphores initValue numLoops flag\n");
        exit(-1);
     }
        
     /* get parameters */
     key           = atoi(argv[1]);
     numSemaphores = atoi(argv[2]);     
     init          = atoi(argv[3]); 
     numLoops      = atoi(argv[4]);
     flag          = atoi(argv[5]);
  
#if TRACE
     printf("--------------------------------\n");
     printf("Key           = %d\n",key);
     printf("numSemaphores = %d\n",numSemaphores);
     printf("initial value = %d\n",init);
     printf("numLoops      = %d\n",numLoops);
     printf("flag          = %d\n",flag);
     printf("--------------------------------\n");
#endif
    
    /* simple argumenty error checking. There may be more */
    if ( (numSemaphores < 1) || (numSemaphores > 5) || 
         (init < 0)          || (numLoops < 1)      || 
         (flag < 0)          || (flag > 1 )) {
            printf("PID=%d : Error in input parameters, program exits!\n");
            exit(-1);
       }
}



/* This function uses getSem() to get all semaphores */
void DoGetAllSemaphores() 
{
    int i, tmpKey;

    tmpKey = key;

#if TRACE
    printf("\nIn DoGetAllSemaphores: pid=%d : numSemaphores=%d"
           " : key=%d : init=%d \n", 
            getpid(), numSemaphores, key, init);
#endif

    for (i=0; i<numSemaphores; i++) {
        if (getSem(tmpKey, init, &id[i]) == -1) { 
             printf("PID=%d : Error in getSem(%d,%d,--), loop=%d\n",
                     getpid(), tmpKey,init,i);
             exit(-1);
        } else {
             printf("PID=%d : OK in getSem(%d,%d,--), loop=%d, get semid=%d\n",
                     getpid(),tmpKey,init,i,id[i]);
             tmpKey++;
        }
    }
}



/* This function does waitSem() numLoops times on each semaphore */
void DoWaitAllSemaphores() 
{
     int i,j;

#if TRACE
     printf("\n\tIn DoWaitAllSemaphores : pid=%d : numLoops=%d \n", 
            getpid(), numLoops);
#endif

     /* do numLoops times */
     for (j=0; j<numLoops; j++) {

        /* do for each created semaphore */
        for (i=0; i<numSemaphores; i++) {

            printf("\tPID=%d : try waitSem(%d), loop=%d\n", getpid(),id[i],j);
            if (waitSem(id[i]) == -1) {
                printf("\tPID=%d : Error in waitSem(%d), loop=%d\n",
                        getpid(),id[i],j);
                exit(0);        
            } else {
                printf("\tPID=%d : OK  waitSem(%d), loop=%d\n",
                        getpid(),id[i], j);
            }
        }
    }
}



/* This function does signalSem() numLoops times on each semaphore */
void DoSignalAllSemaphores() 
{
     int i,j;

#if TRACE
     printf("\n\t\tIn DoSignalAllSemaphores : pid=%d : numLoops=%d \n", 
            getpid(), numLoops);
#endif

     /* do numLoops times */
     for (j=0; j<numLoops; j++) {

        /* do for each created semaphore */
        for (i=0; i<numSemaphores; i++) {

            printf("\t\tPID=%d : try signalSem(%d), loop=%d\n", 
                   getpid(),id[i], j);
            if (signalSem(id[i]) == -1) {
                printf("\t\tPID=%d : Error in signalSem(%d), loop=%d\n",
                        getpid(),id[i],j);
                exit(0);        
            } else {
                printf("\t\tPID=%d : OK  signalSem(%d), loop=%d\n",
                        getpid(),id[i], j);
                sleep(5); /* delay signalSem operations */
            }
        }
    }
}



/* This function releases all semaphores */
void DoReleaseAllSemaphores() {
     int i;

#if TRACE
     printf("\n\t\t\tIn DoReleaseAllSemaphores : pid=%d : numSemaphores=%d \n", 
            getpid(), numSemaphores);
#endif

     for (i=0; i<numSemaphores; i++) {
        if (releaseSem(id[i]) == -1) {
            printf("\t\t\tPID=%d : Error in releaseSem(%d), loop=%d\n",
                    getpid(),id[i],i);
            exit(0);    
        } else {
            printf("\t\t\tPID=%d : OK in releaseSem(%d), loop=%d\n",
                    getpid(),id[i],i);
        }       
    }
}


/************************************************************************/
/*                                                                      */
/* This main function uses above functions to generate semaphores       */
/* activities. The user can create 1 to 5 semaphores, input key word,   */
/* set initial value. The user has an option to do waitSem() only or    */
/* signalSem() only.                                                    */
/*                                                                      */
/* This program can be used to create multiple client processes.        */
/*                                                                      */
/* Example : Two processs share a semaphore, name = MySem, initial      */
/*           value is 0, the 1st process does semSignal() 10 times, and */
/*           the 2nd process does semWait() 10 times.                   */
/*                                                                      */
/*           a.out MySem 1 0 10 0                                       */
/*           a.out MySem 1 0 10 1                                       */
/*                                                                      */
/************************************************************************/


main(int argc, char *argv[])                    
{
    
    vsinit(&argc, argv);        

    GetArguments(argc, argv);

    /* get all semaphores */
    DoGetAllSemaphores();

    sleep(10);  /* allow other processes to start */   

    /* do waitSem() or signalSem() */
    if (flag)
        DoWaitAllSemaphores();
    else
        DoSignalAllSemaphores();
                
    /* release all semaphores */
    DoReleaseAllSemaphores();
    vsexit();                                   
}