CIS 307: Homework 4: Hints

[Introduction], [RAND_PROC], [HMW_MAIN], [STOREPTR]

Introduction

We have processes RAND_PROC1, RAND_PROC2 created by the parent process HMW_MAIN. Their code will be respectively in files rand_proc1.c, rand_proc2.c, and hmw_main.c which will be compiled separately and linked together.

A shared memory segment holds a STORE with at least 10 [STORE_SIZE] pairs (STORE_ID, STORE_ELEM); you choose an initial list of pairs. STORE_ID and STORE_ELEM are strings of, respectively, 9 [STORE_ID_SIZE] and 8 [STORE_ELEM_SIZE] characters. STORE_ID represents a social security number [for example "155243352"] and STORE_ELEM represents the corresponding balance [for example " 4563750"].

The RAND_PROC processes execute the functions STORE_UPDATE and STORE_READ on the STORE. These are slow operations [assume that they involve IO], taking one second.

   function STORE_UPDATE (WHO : STORE_ID;
    			   WHAT  : STORE_ELEM) return INTEGER;
    {It updates the value of WHO to be WHAT. It returns 0 iff successful}
    {Note that WHO denotes the pair with first element equal to WHO.}

   function STORE_READ (WHO : STORE_ID;
    			  var WHAT  : STORE_ELEM) return INTEGER;
    {It retrieves the value of WHO and stores it in WHAT. 
     It returns 0 iff successful}

HMW_MAIN executes the STORE_BALANCE function on the STORE. It is a slow operation.

   function STORE_BALANCE return INTEGER;
    {It returns the sum of the STORE_ELEMs (seen as integers) in the STORE}

RAND_PROC

RAND_PROC1 and RAND_PROC2 have the same form [but use different seeds for the random number generator]. RAND_PROC1 and RAND_PROC2 should respond within callbacks to the signals from HMW_MAIN.

   RAND_PROCi:
       initialization;
       Establish the signal handlers. For example:
          signal(SIGUSR1, dostats);
          signal(SIGUSR2, doexit);
          [of course you have to write the functions dostats, doexit]
       segmentid = ObtainSegment(size of STORE);
       Attach to segmentid and set STOREPTR to value returned by Attach;
       [All access to STORE is done through STOREPTR]
       loop
	    Select at random STORE_READ or STORE_UPDATE 
	    [in both operations the STORE_ID should be selected 
	     at random from a list maintained at RAND_PROCi; in the 
             STORE_UPDATE operation STORE_ELEM should be created using 
	     a random number generator] and execute the corresponding
            function and log the call and result;
	    wait some random time;
	end loop
        conclusion;
   function dostats(int s): print out statistics of RAND_PROCi;
   function doexit(int s): detach from shared memory segment and exit;
   function ObtainSegment(int StoreSize)
   begin
    Open (creating if necessary) the (initially empty) file SHMIDFILE
      for reading and writing;
    Obtain an exclusive lock on SHMIDFILE;
    if ISEMPTY(SHMIDFILE) then  { shared memory segment not created yet }
    begin
      Invoke shmget as 
        shmid := shmget(IPC_PRIVATE,StoreSize,SHM_R|SHM_W);
      Invoke shmat to attach segment to address space as 
        StartAddressOfSTORE := shmat(shmid,0,0);
      Initialize STORE;
      Write shmid into SHMIDFILE;
    end
    else { shared memory segment already created }
    begin
      Read shmid from SHMIDFILE;
      Invoke shmat to attach segment to addres space as 
        StartAddressOfSTORE := shmat(shmid,0,0);
    end
    Release lock on SHMIDFILE;
   end { ObtainSegment }
   function STORE_READ (storeid id, storeelem *elem) return integer:
     use filerwreadlock to lock the id entry in the store;
     sleep(1);
     set elem to the value of the elem field in the id entry of the store;
     use filerwunlock to unlock the id entry of the store
     write appropriate information to log;
     update statistics;
     return appropriate result code;
   function STORE_UPDATE(storeid id, storeelem elem) return integer:  
     use filerwwritelock to lock the id entry in the store;
     sleep(1);
     set the elem field in the id entry of the store to elem;
     use filerwunlock to unlock the id entry of the store
     write appropriate information to log;
     update statistics;
     return appropriate result code;

HMW_MAIN

HMW_MAIN, after starting the other processes, in a loop prompts the users to ask if they want to see statistical information from RAND_PROC1 and RAND_PROC2.

   HMW_MAIN:
       pid_t pids[3];
       initialization;
       Create filelocks fl;
       if ((pids[0]=fork())<0) {perror("fork"); exit(1);}
       else if (pids[1]==0) RAND_PROC1();
       if ((pids[2]=fork())<0) {perror("fork"); exit(1);}
       else if (pids[2]==0) RAND_PROC2();
       segmentid = ObtainLateSegment();
       Attach to segmentid and set STOREPTR to value returned by Attach;
       [All access to STORE is done through STOREPTR]
       loop
	   Prompt the User;
	   If the answer is "1" then
		send a signal to RAND_PROC1 [RAND_PROC1 
		will write to the screen the number of Read and 
		Update messages that it has executed [different 
		numbers represents the Reads started and completed, 
		and the Updates started and completed]].
	   else if the answer is "2", then
		the same is done with RAND_PROC2
           else if the answer is "3", then
                Call STORE_BALANCE and print out result
	   else 
		send signals to RAND_PROC1, RAND_PROC2 
		requesting that they terminate;
		wait that they all exit and exit the loop;
	end loop
        Delete the shared memory segment;
        Delete the filelocks;
        Conclusion;
   function ObtainLateSegment(void) return segmentid:
     repeat
       open the agreed "shmidfile.dat" file;
       if it exists, read from it the segmentid 
       else sleep(1) and repeatloop
   function STORE_BALANCE(): 
     let sum be an integer initialized to 0;
     filelongrwlock(fl);
     sleep(1);
     for each index i of a storepair in the store
       add to sum the integer value of storeptr[i]->elem;
     filelongrwunlock(fl);
     return sum;

STOREPTR

This code shows how we may use the STORE through a pointer. Note that I have used malloc instead of shmat so as to simplify the example. Also STOREIDSIZE is 10 and STORELEMSIZE is 9 so as to allow space for null terminator of the string.

  #define STORESIZE 10
  #define STOREIDSIZE 10
  #define STORELEMSIZE 9
  typedef char storeid[STOREIDSIZE];
  typedef char storeelem[STORELEMSIZE];
  typedef struct {
    storeid id;
    storeelem elem;} storepair;
  typedef storepair storetype[STORESIZE];

  storetype * storeptr;

  void storeinit();

  int main () {
    storeptr = (storetype *) malloc(sizeof(storetype));
    storeinit();
    printf ("id of second entry: %s\n", storeptr[1]->id);
    exit(0);
  }

  void storeinit(){
    strcpy(storeptr[0]->id, "123456789");
    strcpy(storeptr[1]->id, "234567891");
    strcpy(storeptr[2]->id, "345678912");
    strcpy(storeptr[3]->id, "456789123");
    strcpy(storeptr[4]->id, "567891234");
    strcpy(storeptr[5]->id, "678912345");
    strcpy(storeptr[6]->id, "789123456");
    strcpy(storeptr[7]->id, "891234567");
    strcpy(storeptr[8]->id, "912345678");
    strcpy(storeptr[9]->id, "012345678");
    strcpy(storeptr[0]->elem, "  123451");
    strcpy(storeptr[1]->elem, "  123452");
    strcpy(storeptr[2]->elem, "  123453");
    strcpy(storeptr[3]->elem, "  123454");
    strcpy(storeptr[4]->elem, "  123455");
    strcpy(storeptr[5]->elem, "  123456");
    strcpy(storeptr[6]->elem, "  123457");
    strcpy(storeptr[7]->elem, "  123458");
    strcpy(storeptr[8]->elem, "  123459");
    strcpy(storeptr[9]->elem, "  123450");
  }

ingargiola@cis.temple.edu