Listing 3 Using semaphores and critical sections to synchronize processes

//**************************************************
//  Listing 3
//
//  FILE NAME   : sema.cpp
//  AUTHOR      : Matt Weisfeld
//
//  DESCRIPTION : using semaphores and critical
//                     sections to synchronize processes.
//
//**************************************************
// Example : For 3 processes
//
// Pn - process (P0 is the master)
// T  - turn variable
// Sn - status
//
// P0 P1 P2 T S1 S2
//

#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include "sema.h"

// DESCRIPTION : constructor
semaphore::semaphore (long processes)
{
   strcpy (filename,FILENAME);

   // Initialize the number of processess and the
   // appropriate arrays.
   PROCESSES = processes;
   for (int loop_i = 0; loop_i < PROCESSES; loop_i++) {
      NODE[loop_i] = loop_i;
      LOC[loop_i] = PROCESSES+loop_i;
   };
};

// DESCRIPTION : dummy destructor
semaphore::~semaphore(void){};

// DESCRIPTION : synchronize using critical sections
void semaphore::synchronize(char *param) {
   // If the parameter is an 'i', simply initialize
   // the shared file then exit
   if (!strcmp (param, "i")) {
      initialize();
      exit(0);
   };

   node = atoi(param);     // identify the current node
   intro();        // print out informational messages
   i = node;          // use 'i' since algorithm does
   turn_num=0;
   flag_num=0;
   critical_status=NORMAL;

   // Perform critical function until exit condition exists
   while (critical_status == NORMAL) {
      perform();
   }
   return;
}

// DESCRIPTION : contains the CS algorithm
void semaphore::perform(void)
{
   //     A do-while (!expression) is the same as
   //       do-until (expression)

   // See algorithm for description of the code.
   do {
      cs_write ( i, WANT_IN);
      turn_num = cs_read ( LOC[0]);
      j = turn_num;
      while (j != i) {
         flag_num = cs_read ( j);
         if (flag_num != IDLE) {
            turn_num = cs_read ( LOC[0]);
            j = turn_num;
         } else {

            j = (j+1) % PROCESSES;

         }
      }
      cs_write ( i, IN_CS);

      j = 0;
      flag_num = cs_read ( j);
      while ( (j<PROCESSES-1) && (j==i || flag_num!=IN_CS) ) {
         j++;
         flag_num = cs_read ( j);
      }
      turn_num = cs_read ( LOC[0]);
      flag_num = cs_read ( turn_num);
   }while (!((j>=PROCESSES-1) &&
          ((turn_num == i) || flag_num == IDLE)));
   turn_num = i;
   cs_write ( LOC[0], turn_num);
   // enter critical section
   critical_status = critical_section();
   // leave critical section
   turn_num = cs_read ( LOC[0]);
   j = (turn_num+1) % PROCESSES;
   flag_num = cs_read ( j);
   while (flag_num == IDLE) {
      j = (j+1) % PROCESSES;
      flag_num = cs_read ( j);
   }
   turn_num = j;
   cs_write ( LOC[0], turn_num);
   flag_num = IDLE;
   cs_write ( i, flag_num);
   return;
};

// DESCRIPTION : identify the node
void semaphore::intro(void)
{
   printf ("PROCESSOR NODE %d\n", node);
   return;
};

// DESCRIPTION : initialize the shared data file
void semaphore::initialize(void)
{
   FILE *fp;
   long loc = 0, zero=0;
   printf ("Initialize\n");
   if ((fp = fopen(filename, "w+")) == NULL){
      printf ("initialize: can't open %s\n", filename);
      exit(0);
   };

   // Initialize all status variables and flags to zero
   for (loc = 0; loc < (PROCESSES + 1 + (PROCESSES-1)); loc++) {
      if (fseek (fp, loc*2, ORIGIN) != 0) {
         printf ("ERROR: fseek error in initialize\n");
         exit(0);
      };
      if (fprintf (fp, "%ld ", zero) < 0) {
         printf ("ERROR: initialize error\n");
         exit(0);
      };
   };
   // Simply for clarity, mark the end of the flags with
   // an 'X'
   if (fseek (fp, loc*2, ORIGIN) != 0) {
      printf ("ERROR: fseek error in initialize\n");
      exit(0);
   };
   if (fprintf (fp, "%c ", 'X') < 0) {
      printf ("ERROR: initialize error\n");
      exit(0);
   };
   fclose (fp);
};

// DESCRIPTION : actual critical section
long semaphore::critical_section(void)
{
   int loop_i;
   long status;
   // If the node is the master (node 0) then see if all
   // other nodes are ready. If they are, then clear all
   // appropriate variables and the shared file. If all
   // not ready, try again.
   if (node == 0) {
         status = READY;
         for (loop_i=1; loop_i<PROCESSES; loop_i++) {
            NODE_NUM[loop_i] = cs_read(LOC[loop_i]);
            if (NODE_NUM[loop_i] != READY)
               status=CLEAR;
         };
         if (status == READY) {
            for (loop_i=1; loop_i<PROCESSES; loop_i++) {
               NODE_NUM[loop_i] = CLEAR;
               cs_write(LOC[loop_i], NODE_NUM[loop_i]);
            }
            return(STOP);
         } else {
            return(NORMAL);
         }
   } else {         // if non-master node, mark node as ready
      NODE_NUM[node] = READY;
      cs_write(LOC[node], NODE_NUM[node]);
      return(STOP);
   }
};

// DESCRIPTION : write to the shared file
void semaphore::cs_write(long loc, long value)
{
   
   FILE *fp;
   if ((fp = fopen(filename, "r+")) == NULL){
      printf ("cs_write: can\'t open %s\n", filename);
      exit(0);
   };
   if (fseek (fp, loc*2, ORIGIN) != 0) {
      printf ("ERROR: fseek error in cs_write\n");
      exit(0);
   };
   if (fprintf (fp, "%ld ", value) < 0) {
      printf ("ERROR: cs_write error\n");
      exit(0);
   };
   fclose (fp);
   return;
};

// DESCRIPTION : read from the shared file
long semaphore::cs_read(long loc)
{
   FILE *fp;
   long value;
   if ((fp = fopen(filename, "r")) == NULL){
      printf ("cs_read: can't open %s\n", filename);
      exit(0);
   };
   if (fseek (fp, loc*2, ORIGIN) != 0)
      printf ("ERROR: fseek error in cs_read\n");
   if (fscanf (fp ,"%ld", &value) == EOF)
      printf ("ERROR: cs_read error\n"};
   fclose (fp);
   return(value);
};
//End of File