

/* these routines are called by TupleDSM application programs 

   list of tuple types:

   ("var",name of variable,array index,value of variable,# of readers)
   ("mutex",mutexID)
   ("bar",barrierID,even or odd value,# remaining) */


/* concerned with command-line arguments: */
#define DSM_MAX_ARGS 20
#define DSM_MAX_ARG_LENGTH 20
int DSMArgc;  /* command-line argument count */
char DSMArgv[DSM_MAX_ARGS][DSM_MAX_ARG_LENGTH];  /* command-line arguments */


/* concerned with  node numbers and total number of nodes: */
int DSMNodeNum,  /* i.d. number of this node */
    DSMTotNodes;  /* total number of nodes */ 


/* concerned with cleanup at exit: */
/* used only by node 0: */
int DSMNVars = 0, /* number of "var" tuples */
    DSMNMutexs = 0, /* number of "mutex" tuples */
    DSMNBars = 0; /* number of "bar" tuples */
/* note:  tuples created by the front end program will be removed
   by that program */


/* *********************  DSMEnvInit()  *********************

   external view:

      must be called by all nodes at the outset of an application
      program; gets node number, number of workers, number of
      command-line arguments, and those arguments themselves

   internal operation:

      does rd() (except for the use of in() in the case of DSMNodeNum) 
      on tuples set by the front-end program */

DSMEnvInit()

{  int I,TmpI; char *TmpS;

   in(lstring("whoami"),qlint(&DSMNodeNum));
   rd(lstring("number of workers"),qlint(&DSMTotNodes));
   rd(lstring("number of arguments"),qlint(&DSMArgc));
   for (I = 1; I <= DSMArgc; I++)  {
      rd(lstring("argument"),lint(I),qlnchar(&TmpS,&TmpI)); 
      strcpy(DSMArgv[I],TmpS);
   }
   if (DSMNodeNum == 0) DSMBarrierCreate("DSM exit barrier"); 
}


/* *********************  DSMVarInit(S,N)  *********************

   external view:

      must be called, by node 0, for each shared variable (scalar
      or array); called AFTER DSMEnvInit()

      S is a string containing the name of the shared variable

      set N = 1 for a scalar; for arrays, N = array length

   internal operation:

      uses out() to create tuples ("var",S,I,0,0), I = 0,1,2,...,N-1
      (see tuple type list at top of this file) */

DSMVarInit(S,N)
   char *S; int N;

{  int I;

   if (DSMNodeNum != 0)  {
      printf("vars may be created only by node 0\n");
      exit(1);
   }
   for (I = 0; I < N; I++)  {
      out(lstring("var"),lstring(S),lint(I),lint(0),lint(0));
      DSMNVars++;
   }
}


/* *********************  DSMNonExclWriteRequest()  *********************

   external view:

      request permisson for nonexclusive write access to a shared 
      variable; no new reads or other writes allowed, but old ones 
      could be in progress (they will continue to use the old value 
      of the variable)

      access is to the I-th element of the array named in S (or
      in the case of a scalar (I = 0), the scalar named in S); P is 
      a pointer giving the address in the application program of
      the array/scalar named in S; returns the current number of
      readers

   internal operation:

      search through tuple space for a match on "var", S, I; 
      assign the value to *(P+I) */

int DSMNonExclWriteRequest(S,P,I)
   char *S; int *P,I;

{  int NR;

   in(lstring("var"),lstring(S),lint(I),qlint(P+I),qlint(&NR));
   return NR;
}


/* *********************  DSMNonExclWriteRelease()  *********************

   external view:

      release exclusive write access; last argument is the number
      of readers

   internal operation:

      write out the tuple, including its new value for the variable */

DSMNonExclWriteRelease(S,P,I,NR)
   char *S; int *P,I,NR;

{  out(lstring("var"),lstring(S),lint(I),lint(*(P+I)),lint(NR));  }


/* *********************  DSMReadRequest()  *********************
 
   external view:
 
      request permission for read access to a variable
 
      note:  there is no corresponding release call
 
   internal operation:
 
      does rd() to read the tuple */ 
 
DSMReadRequest(S,P,I)
   char *S; int *P,I;
   
{  int NReaders;  
 
   rd(lstring("var"),lstring(S),lint(I),qlint(P+I),qlint(&NReaders));
}


/* *********************  DSMExclWriteRequest()  *********************

   external view:

      request permisson for exclusive write access to a variable; no 
      reads or other writes allowed 

      access is to the I-th element of the array named in S (or
      in the case of a scalar (I = 0), the scalar named in S); P is a
      pointer giving the address in the application program of
      the array/scalar named in S 

   internal operation:

      search through tuple space for a match on "var", S, I and
      a 0-readers condition; assign the value to *(P+I) */

DSMExclWriteRequest(S,P,I)
   char *S; int *P,I;

{  in(lstring("var"),lstring(S),lint(I),qlint(P+I),lint(0));  }


/* *********************  DSMExclWriteRelease()  *********************

   external view:

      release exclusive write access

   internal operation:

      write out the tuple, including its new value for the variable */

DSMExclWriteRelease(S,P,I)
   char *S; int *P,I;

{  out(lstring("var"),lstring(S),lint(I),lint(*(P+I)),lint(0));
}


/* *********************  DSMSharedReadRequest()  *********************

   external view:

      request permission for shared read access to a variable;
      return value is (new) number of readers

   internal operation:

      does in() to remove the tuple, increment the number of readers,
      and then out() to replace it */
      
int DSMSharedReadRequest(S,P,I)
   char *S; int *P,I;

{  int NReaders;  

   in(lstring("var"),lstring(S),lint(I),qlint(P+I),qlint(&NReaders));
   NReaders++;
   out(lstring("var"),lstring(S),lint(I),lint(*(P+I)),lint(NReaders));
   return NReaders; 
}


/* *********************  DSMSharedReadRelease()  *********************

   external view:

      release shared read access

   internal operation:

      do in() to get current number of readers, decrement, out() */

DSMSharedReadRelease(S,P,I)
   char *S; int *P,I;

{  int NReaders;  

   in(lstring("var"),lstring(S),lint(I),qlint(P+I),qlint(&NReaders));
   NReaders--;
   out(lstring("var"),lstring(S),lint(I),lint(*(P+I)),lint(NReaders));
}


/* *********************  DSMMutexCreate()  ***********************

   external view:

      sets up a mutex

   internal operation:

      does out() to create a mutex tuple, unlocked */

DSMMutexCreate(MutexID)
   char MutexID[];

{  if (DSMNodeNum != 0)  {
      printf("mutexes may be created only by node 0\n");
      exit(1);
   }
   out(lstring("mutex"),lstring(MutexID));  
   DSMNMutexs++;
}


/* *********************  DSMMutexBegin()  ***********************

   external view:

      waits for and acquires exclusive access to a critical section

   internal operation:

       does in() to remove the associated lock tuple, requiring a 0
       in the lock component of the tuple */

DSMMutexBegin(MutexID)
   char MutexID[];

{  in(lstring("mutex"),lstring(MutexID));  }


/* *********************  DSMMutexEnd()  ***********************

   external view:

      waits for and acquires exclusive access to a critical section

   internal operation:

      does in() to remove the associated lock tuple, requiring a 0
      in the lock component of the tuple */

DSMMutexEnd(MutexID)
   char MutexID[];

{  out(lstring("mutex"),lstring(MutexID));  }


/* *********************  DSMBarrierCreate()  ***********************

   external view:

      sets up a barrier

   internal operation:

      does out() to create a barrier tuple, initialized to NPartic; the
      last component is the number of nodes which have NOT reached the
      barrier yet */

DSMBarrierCreate(BarrierID)
   char BarrierID[];

{  if (DSMNodeNum != 0)  {
      printf("barriers may be created only by node 0\n");
      exit(1);
   }
   out(lstring("bar"),lstring(BarrierID),lint(0),lint(0));  
   out(lstring("bar"),lstring(BarrierID),lint(1),lint(0));  
   DSMNBars++;
}


/* *********************  DSMBarrier()  ***********************

   external view:

      waits until all required nodes have reached this point in the code

   internal operation:

      does in() to get the specified barrier tuple, increments the
      barrier count, and does out() back to the tuple space; checks
      to see whether done */

DSMBarrier(BarrierID)
   char BarrierID[];

{  int NHit;  static int EvenOdd = 0;

   in(lstring("bar"),lstring(BarrierID),lint(EvenOdd),qlint(&NHit));  
   NHit++;
   if (NHit == DSMTotNodes+1) NHit = 1;
   out(lstring("bar"),lstring(BarrierID),lint(EvenOdd),lint(NHit));  
   if (NHit < DSMTotNodes)  
      rd(lstring("bar"),lstring(BarrierID),lint(EvenOdd),lint(DSMTotNodes));  
   EvenOdd = 1 - EvenOdd;
}


/* *********************  DSMExit()  *********************

   external view:

      required call for all nodes, the last-executed line in the
      application source code

   internal operation:

      does out() of the string "front end may exit"; when the front-end
      program receives this from all nodes, it will exit; */

DSMExit()

{  int I,A[10];

   if (DSMNodeNum != 0) out(lstring("front end may exit"));  
   DSMBarrier("DSM exit barrier");
   if (DSMNodeNum == 0)  {
      for (I = 0; I < DSMNVars; I++) 
         in(lstring("var"),
            qlstring(&A[0]),qlint(&A[1]),qlint(&A[2]),qlint(&A[3]));
      for (I = 0; I < DSMNMutexs; I++) 
         in(lstring("mutex"),qlstring(&A[0]));
      for (I = 0; I < DSMNBars; I++)  {
         in(lstring("bar"),qlstring(&A[0]),lint(0),qlint(&A[1]));
         in(lstring("bar"),qlstring(&A[0]),lint(1),qlint(&A[1]));
      }
      out(lstring("front end may exit"));  
   }
}


