SOURCE FILE: protocol.cpp


/* 
   The set-up:  two user processes write packets to two protocol
   buffers.  Each user writes to both buffers. Two agents of
   transmission serve the two protocol buffers.  Each serves both
   buffers.
*/

#include <iostream>
#include <sched.h>
#include <time.h>
#include <pthread.h>
#include <string>
#include "sem.h"
#include "protocol.h"
#include <string>

using namespace std;

      /* We need to use this lock to get intelligible printouts
         of what the various threads are doing.  Warning:  Don't
         change how this is done until you've thought a WHOLE lot
         about the consequences. */

pthread_mutex_t stdoutLock ;

      /* Shared var pktBuf is an array of bufferType indexed by
         the set {0,1} of protocols.  */

bufferType pktBuf[2] ;    
   
     /* global variables to represent threads created
        dynamically. */

pthread_t user_t[2], agent_t[2] ;

      /* Set checking to 1 if you want messages from the
          functions below and from sem.cpp, else set to 0.  */

int  checking ;      
                     
      /* Use this flag to turn on checking in your main program file. */

int  my_checking ;

/* ################################################## */
/*                         init                       */
/* ################################################## */
void init() 
{
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
          /* (Initialize the flags and semaphores used for 
              synchronization.) */
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */

      /* Set checking to 1 if you want messages from the
          functions below and from sem.cpp, else set to 0.  */

  checking = 0 ;  
  my_checking = 0 ;  

  if ( 0!=pthread_mutex_init(&stdoutLock, NULL) )
  {  cout << "MUTEX INITIALIZATION FAILURE!" << endl ;
     exit(-1) ;}

      /* initialize random number generator */ 
  srandom(time((time_t *) 0));
}

/* ################################################## */
/*                  userMessage                       */
/* ################################################## */
void userMessage (int n, int packetNum, int protocol)
{
   pthread_mutex_lock(&stdoutLock) ;
   cout << "Copy IN:        Packet #" << packetNum 
   << " of USER #" << n << " into buffer #" << protocol 
    << "." << endl ; 
   pthread_mutex_unlock(&stdoutLock) ;
}

/* ################################################## */
/*                       user                         */
/* ################################################## */
void * user (void * N)
{
  int n = (int) N ;
  int i, packetNum = 0, protocol, delay ;
  do
  {
     protocol = (random() % 2 ) ;

   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
            /* perform synchronization action */
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */

            /* simulate the writing of a packet 
               into the buffer */

     pktBuf[protocol].info.userID = n ;
     pktBuf[protocol].info.packetNum = packetNum ;
     delay = random() % 10 ;
     /*
     if (n==0)  delay = random() % 100;
     else delay = random() % 1000 ;
     */
       /* THIS DELAY SIMULATES THE WORK REQUIRED TO 
          COPY WHAT MIGHT BE A LARGE PACKET INTO THE
          BUFFER.  IT COULD BE A LONG DELAY.  */
     for (i=0; i<delay; i++) sched_yield();
     userMessage (n, packetNum, protocol) ;
     packetNum++ ;

   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
        /* perform more synchronization work */
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */

     delay = random() % 10 ;
     /*
     if (n==0)  delay = random() % 100;
     else delay = random() % 1000 ;
     */
       /* THIS DELAY SIMULATES THE TIME THAT ELAPSES
          BEFORE THE USER HAS ANOTHER PACKET READY TO 
          SEND. IT COULD BE A LONG DELAY.  */
     for (i=0; i<delay; i++) sched_yield();
  }
  while (1) ;
}

/* ################################################## */
/*                agentMessage                        */
/* ################################################## */
void agentMessage (int n, int packetNum,
                   int userID, int protocol)
{
   pthread_mutex_lock(&stdoutLock) ;
   cout << "AGENT #" << n << " copies packet #" << packetNum 
   << " of USER #" << userID << " from buffer #" << protocol
   << "." << endl ;
   pthread_mutex_unlock(&stdoutLock) ;
}

/* ################################################## */
/*                        agent                       */
/* ################################################## */
void * agent (void * N)
{ 
  int n = (int) N ;
  int i, packetNum, protocol, userID, delay ;

      /* Pick either protocol to start with. */

  protocol = (random() % 2 ) ;
  do
  {  
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
        /* Do some synchronization work and if certain conditions
           are true then do the block of instructions that follow
        */
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
  /*  if (???????)  */
     { 

   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
           /* Do some additional work associated with 
              synchronization */
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */

       packetNum = pktBuf[protocol].info.packetNum ;
       userID    = pktBuf[protocol].info.userID ;
/*       delay = random() % 1000 ; */
       delay = random() % 100 ;
       /*
       if (n==0)  delay = random() % 100;
       else delay = random() % 1000 ;
       */
       /* THIS DELAY SIMULATES THE WORK REQUIRED TO 
          COPY OUT WHAT MIGHT BE A LARGE PACKET.  IT
          COULD BE A LONG DELAY.  */
       for (i=0; i<delay; i++) sched_yield();
       agentMessage (n, packetNum, userID, protocol) ;
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
          /* More synchronization code */
   /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
     }

/*     else    */
     {  
           /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
           /* This block would get executed instead of the one above
              if there was a reason not to let the agent touch the buffer.
              This block just does some synchronization tasks. /*
          /* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
     }
          /* Get set to check the other buffer */
     protocol = (protocol + 1) % 2 ;
/*       delay = random() % 1000 ; */
       delay = random() % 100 ;
     /*
     if (n==0)  delay = random() % 100;
     else delay = random() % 1000 ;
     */
       /* THIS DELAY SIMULATES THE WORK REQUIRED TO 
          TRANSMIT ONTO THE NETWORK WHAT MIGHT BE A 
          LARGE PACKET.  IT COULD BE A LONG DELAY.  */
     for (i=0; i<delay; i++) sched_yield();

  }
  while (1) ;
}

/* ################################################## */
/*                        main                        */
/* ################################################## */
main() 
{ 
  int thrNum ;

  init() ;  

  for (thrNum=0; thrNum<2; thrNum++)
  {
    if (0!=pthread_create(&user_t[thrNum], NULL, user, (void *) thrNum ))
    {  cout << "THREAD CREATION FAILURE!" << endl ;
       exit(-1) ; }
     
    if (0!=pthread_detach(user_t[thrNum]))
    {  cout << "THREAD DETACHMENT FAILURE!" << endl ;
       exit(-1) ;}
  }

  if (0!=pthread_create(&agent_t[0], NULL, agent, (void *) 0 ))
  {  cout << "THREAD CREATION FAILURE!" << endl ;
     exit(-1) ; }
     
  if (0!=pthread_detach(agent_t[0]))
  {  cout << "THREAD DETACHMENT FAILURE!" << endl ;
     exit(-1) ;}

  agent((void *) 1) ;
  exit(0)  ;
}