//assignment# 3
//cop6611
//compile: g++ mutex.cpp


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


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

#define SIZE 10

const int mutex = 0 ;
const int empty = 1 ;
const int full  = 2 ;


//printout of out buffer
char textOut[ 37 ] ;




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


typedef struct
{
   char boundedBuffer[ SIZE ] ;
} SharedMemory ;

int semid ;


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

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

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

		void producer( void )
		{
		
			int count = 0 ;
			
			//array of 40 characters
			char textIn[ 40 ] = "abcdefghijklmnopqrstuvwxyz0123456789abcd" ;


			cout << "\n producer contains\n" << endl ;
			for( int i=0; i<40; i++ )
				cout << textIn[ i ] ;
			cout << "\n\n finished with initial input to producer.  wait ~40secs...\n\n" ;
			
			
			do
			{

           			//p sem
				pOperation( empty ) ;

				pOperation( mutex ) ;

				//critical section
				sharedMemory->boundedBuffer[ count % SIZE ] = textIn[ count ] ;
			

				//v sem
				vOperation( mutex ) ;
				
				vOperation( full ) ;

			
			}while( ++count < 40 ) ;
		}
		  

		void consumer( void )
		{
			int count = 0 ;


			do
			{
			
			  	//p sem
				pOperation( full ) ;	
				
				pOperation( mutex ) ;	
				
				//critical section
				textOut[ count ] = sharedMemory->boundedBuffer[ count % SIZE ] ;
				sleep( 1 ) ;//sleep for one second


				//v sem
				vOperation( mutex ) ;	
				
				vOperation( empty ) ;

			}while( ++count < 40 ) ;
			
			cout << "\n\n consumer now contains\n" << endl ;
			for( int i=0; i<40; i++ )
				cout << textOut[ i ] ;
			cout << "\n\n end consumer" << endl ;
			
		}//end consumer




	private :
		//the shared memory
		SharedMemory *sharedMemory ;

		//structure for semaphore operations
		struct sembuf *ptrsembuf ;



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

		//V operation		
		void vOperation( int semaphoreID )
		{
			ptrsembuf->sem_num = semaphoreID ;
			ptrsembuf->sem_op = 1 ;
			if( semop( semid, ptrsembuf, 1 ) == -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 semval ;


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




	//start with mutex semaphore
	//init var to 1
	initvar.val = 1 ;
	if( semctl( semid, mutex, SETVAL, initvar ) == -1 )
	{
		cerr << "semctl" ;
		exit( -1 ) ;
	}

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






	//do the same for empty semaphore
	//init var to 10
	initvar.val = 10 ;
	if( semctl( semid, empty, SETVAL, initvar ) == -1 )
	{
		cerr << "semctl" ;
		exit( -1 ) ;
	}

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






	//now the same for full semaphore
	//init var to 0
	initvar.val = 0 ;
	if( semctl( semid, full, SETVAL, initvar ) == -1 )
	{
		cerr << "semctl" ;
		exit( -1 ) ;
	}

	//check var is = to 1
	if( ( semval = semctl( semid, full, GETVAL, initvar ) ) == -1 )
	{
		cerr << "semctl" ;
		exit( -1 ) ;
	}
	cout << "the full 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
	BoundedBuffer bb( sMemory ) ;
	

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

	//create the producer
   	if( ( pid1 = fork() ) == 0 )
 		bb.producer() ;
	
	//create the consumer
   	if( ( pid1 != 0 )&&( pid2 = fork() ) == 0 )
		bb.consumer() ;


	//only need one output to screen
   	if( ( pid1 != 0 )&&( pid2 != 0 ) )
	{
		//block the parent for 2 seconds
		wait(NULL);
		wait(NULL);  
	


		//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 ) ;
		}
		
		
		
		//print textOut
		cout << endl ;
		for( int i=0; i<37; i++ )
			cout << textOut[ i ] ;				

		cout << "\nend parent\n" ;
	}

	//all done
	return 0 ;
}