//assignment# 2
//cop6611
//compile: g++ sem.cpp


#include < iostream.h >
#include < sys/types.h >
#include < sys/ipc.h >
#include < sys/shm.h >
#include < fcntl.h >
#include < sys/sem.h >
//#include < stdlib.h >

#define SEM_MODE ( 0200 | 0400 | IPC_CREAT)
#define NUM_OF_SEM 1


union semun
{
  int val ;
  struct semid_ds *buf ;
  ushort *array ;
};


typedef struct
{
   int value ;
} SharedMemory ;

int semid ;


	
//using semaphores now
class Semaphore
{
	public :
		//init class
		Semaphore( SharedMemory * sharedMemory )
		{
			this->sharedMemory = sharedMemory ;
			this->sharedMemory->value		= 0 ;

			ptrsembuf = (struct sembuf*)new( struct sembuf ) ;
			ptrsembuf->sem_num = 0 ;
			ptrsembuf->sem_flg = 0 ;
		
		}

		//destructor
		~Semaphore()
		{
			sharedMemory = 0 ;
			
			//free up some memory
			delete ptrsembuf ;
		}

		void processI( void )
		{
			unsigned int line = 0 ;

			while( line < 50000 )
			{
           line++;
           
			  //p sem
				pOperation() ;

				//critical section
				sharedMemory->value++ ;

				//v sem
				vOperation() ;

			}//end while loop
		}
		  

		void processJ( void )
		{
			unsigned int line = 0 ;

			while( line < 50000 )
			{
           line++;

			  //p sem
				pOperation() ;	

				//critical section
				sharedMemory->value++ ;

				//v sem
				vOperation() ;	

			}//end while
		}//end processJ


		//return value of the shared memory
		int getValue()
		{
			return sharedMemory->value ;
		}


	private :
		//the shared memory
		SharedMemory *sharedMemory ;

		//structure for semaphore operations
		struct sembuf *ptrsembuf ;

		const int numelem = 1 ;

		//P operation
		void pOperation( void )
		{
			ptrsembuf->sem_op = -1 ;
         if( semop( semid, ptrsembuf, numelem ) == -1 )
         {
            cerr << "semop" ;
            exit( -1 ) ;
         }
		}

		//V operation		
		void vOperation( void )
		{
			ptrsembuf->sem_op = 1 ;
			if( semop( semid, ptrsembuf, numelem ) == -1 )
			{
				cerr << "semop" ;
				exit( -1 ) ;
			}
		}

} ;


int main( void )
{
	//structure which will hold shared memory variables
	SharedMemory *sMemory ;
	
	int shmid ;	//shared memory ID
	int pid1 ;  //process id for child 1
	int pid2 ;  //process id for child 2

	union semun initvar ;
	int semnum = 0 ;
	int semval ;
	initvar.val = 1 ;
        

	//get semphore
	if( ( semid = semget( IPC_PRIVATE, NUM_OF_SEM, SEM_MODE ) ) == -1 )
	{
		cerr << "semget" ;
		exit( -1 ) ;
	}

	//init count to 1
	if( semctl( semid, semnum, SETVAL, initvar ) == -1 )
	{
		cerr << "semctl" ;
		exit( -1 ) ;
	}

	//check count is = to 1
	if( ( semval = semctl( semid, semnum, GETVAL, initvar ) ) == -1 )
	{
		cerr << "semctl" ;
		exit( -1 ) ;
	}
	cout << "semaphore value is = " << semval << endl ;


	//attempt to attach to an existing memory segment
	// the size of SharedMemory structure
	if( ( shmid = shmget( IPC_PRIVATE, sizeof( SharedMemory ), IPC_CREAT | 0666 ) ) < 0 ) 
	{
		cerr << "shmget" ;
		exit( 1 ) ;
	}

	//attach the shared memory segment
	//get address of sMemory
	sMemory =(SharedMemory*)shmat( shmid,NULL,0 ) ;
	if( sMemory ==(SharedMemory *) -1 ) 
	{
		cerr << "shmat" ;	
		exit( 1 );
	}


	//send sMemory address to pA's sharedMemory 
	//create object of petersonsAlgorithm class
	Semaphore sPh( sMemory ) ;
	

	//zero it, finished with pointer
	sMemory = 0 ;
	
	

	//create first process, processI
   if( ( pid1 = fork() ) == 0 )
 		sPh.processI() ;
	
	//create second process, processJ
   if( ( pid1 != 0 )&&( pid2 = fork() ) == 0 )
		sPh.processJ() ;


	//only need one output to screen
   if( ( pid1 != 0 )&&( pid2 != 0 ) )
	{
		//block the parent for 2 seconds
	wait(NULL);
	wait(NULL);  
	cout << "the final value is..... " << sPh.getValue() << endl ;
	cout << "\t\t fin" << endl ;
	

		//remove shared memory
		if( shmctl( shmid, IPC_RMID, 0 ) == -1 )
		{
			cerr << "shmctl" ;
			exit( -1 ) ;
		}

		//remove semaphore
		if( semctl( semid, NUM_OF_SEM, IPC_RMID ) == -1 )
		{
			cerr << "semctl" ;
			exit( -1 ) ;
		}
	}

	//all done
	return 0 ;
}