 
#include "mon_linda.h"
 
int t_match();
 
slave() 
{ 
    work('s'); 
} 
 

/* Function RESET is an optional parameter to askfor. It is not
used in the implementation */

reset() 
{ 
}
 
 
/* Function GETFUNC is used by askfor.  It is the logic required to
take an unevaluated function from the function queue (glob->pool)
*/

getfunc(p) 
int *p; 
{ 
    int rc = 1; 
 
    if (glob->pool != NULL) 
    { 
        /* return function from pool */
        *p = (int) glob->pool; 
        glob->pool = glob->pool->next; 
        rc = 0; 
    } 
    else 
    { 
        glob->pool_tail = NULL; 
        glob->pool = NULL; 
    } 
    return (rc); 
 
} 
 
/* Function WORK iteratively calls an askfor that attempts to take
an unevaluated function from the function queue.  If the queue is
empty, askfor provides the logic to suspend the process.  If askfor
returns success, then the function pulled from the queue is
evaluated */

work(who) 
char who; 
{ 
    int rc; 
    struct work_struct *eval_tuple; 
    int value; 
 
    int i, found;
    int (*int_func_ptr) (); 
    char proc_name_char[80];
    char key[80]; 
 
    rc = p4_askfor(&(glob->TS), glob->numprocs, getfunc, &value, reset); 
    while ((rc == 0) || ((rc != -1) && (who == 's'))) 
    { 
        if (rc == 0) 
        { 
            eval_tuple = (struct work_struct *) value; 
    
            if (strcmp(eval_tuple->mask, "%s") == 0) 
                sscanf(eval_tuple->work, "%s", proc_name_char); 
	    found = 0;
	    for (i=0; !found && mon_linda_functions_table[i].ptr != NULL; i++)
	    {
		if (strcmp(proc_name_char,mon_linda_functions_table[i].name) == 0)
		{
		    found = 1;
		    int_func_ptr = mon_linda_functions_table[i].ptr;
		    break;
		}
	    }
	    if (!found)
	    {
		p4_error("work: attempting to execute unknown procedure",0);
	    }
            (*int_func_ptr)(); 
        } 
        rc = p4_askfor(&(glob->TS), glob->numprocs, getfunc, &value, reset); 
    } 
} 
 
 
/* Function OUT passes a variable length argument list to PARSE,
which returns the tuple elements in hanger. OUT then enters the
monitor, hashes the tuple structure (space_node) to an appropriate
linked list, and exits the monitor with a continue statement */

out(tuple_mask,va_alist) 
char tuple_mask[80]; 
va_dcl
{ 
    va_list tuple_list; 
    int hashnum, type; 
    char hanger[HANGER_SIZE], key[KEY_SIZE]; 
    struct space_q *space_node; 
    struct space_q *alloc_tuple_struct(); 
 
    type = OUT; 
    va_start(tuple_list); 
    parse(tuple_mask, type, hanger, tuple_list); 
    va_end(tuple_list); 
 
    stok(key, hanger); 
    hashnum = thash(key); 
    p4_menter(&((glob->TS).m)); 
    if (glob->tuple_space[hashnum] == NULL) 
    { 
        space_node = alloc_tuple_struct(); 
        strcpy(space_node->hanger, hanger); 
        strcpy(space_node->mask, tuple_mask); 
        space_node->next = NULL; 
        glob->tuple_space[hashnum] = space_node; 
        glob->space_tails[hashnum] = space_node; 
    } 
    else 
    { 
        space_node = alloc_tuple_struct(); 
        strcpy(space_node->hanger, hanger); 
        strcpy(space_node->mask, tuple_mask); 
        space_node->next = NULL; 
        glob->space_tails[hashnum]->next = space_node; 
        glob->space_tails[hashnum] = space_node; 
    } 
    p4_mcontinue(&((glob->TS).m), 0); 
    return(0);
}

 
/* Like OUT, function IN first calls PARSE, which returns a
template for matching.  IN then invokes askfor, which either
returns in hanger the matched tuple or suspends the process if no
match occurs.  If askfor succeeds, INSTANTIATE does the actual to
formal assignments. */

in(tuple_mask,va_alist) 
char tuple_mask[80]; 
va_dcl
{ 
 
    va_list tuple_list; 
    int rc, type; 
    char template[HANGER_SIZE]; 
    char hanger[HANGER_SIZE]; 
 
    type = global.type = IN; 
 
    va_start(tuple_list); 
    parse(tuple_mask, type, template, tuple_list); 
    va_end(tuple_list); 
    strcpy(global.template, template); 
    strcpy(global.mask, tuple_mask); 
    rc = 1; 
    while ((rc != -1) && (rc != 0)) 
    { 
        rc = p4_askfor(&(glob->TS),glob->numprocs,t_match,hanger, reset); 
    } 
 
    if (rc == 0) 
        instantiate(tuple_mask, template, hanger); 
    return(0);
} 


/* Function RD is identical to IN, except that askfor does not
remove the matched tuple from tuple space */

rd(tuple_mask,va_alist) 
char tuple_mask[80]; 
va_dcl 
{ 
    va_list tuple_list; 
    int rc, type; 
    char hanger[HANGER_SIZE]; 
    char template[HANGER_SIZE]; 
 
    type = global.type = RD; 
 
    va_start(tuple_list); 
    parse(tuple_mask, type, template, tuple_list); 
    va_end(tuple_list); 
    strcpy(global.template, template); 
    strcpy(global.mask, tuple_mask); 
    rc = 1; 
    while ((rc != -1) && (rc != 0)) 
        rc = p4_askfor(&(glob->TS),glob->numprocs,t_match,hanger,reset); 
    instantiate(tuple_mask, template, hanger); 
    return(0);
}                    


/* Function EVAL places a pointer to an (unevaluated) function on
a function queue (glob->pool) protected by a monitor. */
 
eval(tuple_mask,proc_name_char) 
char tuple_mask[]; 
char proc_name_char[];
{ 
    char *mask_ptr, *key; 
    int *int_func_ptr; 
    char buffer[80]; 
    struct work_struct *alloc_eval_node(); 
    struct work_struct *eval_node; 
 
    eval_node = alloc_eval_node(); 
    strcpy(eval_node->mask, "%s"); 
    sprintf(eval_node->work, "%s ", proc_name_char); 
 
    /****
    sprintf(buffer, "%s ", int_func_ptr); 
    strcat(eval_node->work, buffer); 
    ****/
    p4_menter(&((glob->TS).m)); 
 
    eval_node->next = NULL; 
    if (glob->pool == NULL) 
    { 
        glob->pool = eval_node; 
        glob->pool_tail = eval_node; 
    } 
    else 
    { 
        glob->pool_tail->next = eval_node; 
        glob->pool_tail = eval_node; 
    } 
    p4_mcontinue(&((glob->TS).m), 0); 
    return(0);
} 


/* Function T_MATCH provides the logic to compare actuals in a
template with actuals in a tuple structure's hanger.  If the
template matches some tuple, T_MATCH returns success to askfor
along with the matched hanger; otherwise T_MATCH returns failure to
askfor. T_MATCH calls MATCH, which actually performs the
comparison. */
 
t_match(hanger) 
char *hanger; 
{ 
    int rc; 
    struct space_q *space_node, *pred; 
    struct aggregate *agnode; 
    int stok(); 
    int hashnum; 
    int found; 
    char key[80], tuple_tok[80]; 
 
 
    found = 0; 
    rc = 1; 
    stok(key, global.template); 
    hashnum = thash(key); 
    pred = space_node = glob->tuple_space[hashnum]; 
    while ((!found) && (space_node != NULL)) 
    { 
     if (match(space_node->hanger, global.template, 
           global.mask)) 
     { 
         found = 1; 
     } 
     else 
     { 
         pred = space_node; 
         space_node = space_node->next; 
     } 
    }                    /* end while !NULL */ 
    if (found) 
    { 
     strcpy(hanger, space_node->hanger); 
     if (global.type == IN) 
     { 
         if (space_node == glob->tuple_space[hashnum]) 
          glob->tuple_space[hashnum] = space_node->next; 
         else if (space_node->next == NULL) 
         { 
          pred->next = NULL; 
          glob->space_tails[hashnum] = pred; 
         } 
         else 
          pred->next = space_node->next; 
         space_node->next = head_avl_nodeq; 
         head_avl_nodeq = space_node; 
     } 
     rc = 0; 
    } 
    return (rc); 
} 
 

/* Function PARSE builds the tuple structure's hanger using
information supplied by the tuple mask.  PARSE pops arguments off
the argument list (tuple_list) and converts the argument into a
formatted string.  The string is formatted according to the type
information found in the mask. */

parse(tuple_mask, type, buffer, tuple_list) 
char *tuple_mask, *buffer; 
int type; 
va_list tuple_list; 
{ 
    int rc; 
    char *mask_ptr; 
    struct aggregate *ag_ptr; 
    double flt, *flt_ptr; 
    int *int_ptr, size, integer; 
    char *char_ptr; 
    char tok[80]; 
    rc = 1; 
    char_ptr = va_arg(tuple_list, char *); 
    sprintf(buffer, "%s ", char_ptr); 
    for (mask_ptr = tuple_mask + 2; *mask_ptr; mask_ptr++) 
    { 
     if (*mask_ptr == '%') 
         switch (mask_ptr[1]) 
         { 
         case 's': 
          char_ptr = va_arg(tuple_list, char *); 
          sprintf(tok, "%s ", char_ptr); 
          strcat(buffer, tok); 
          break; 
 
         case 'd': 
          integer = va_arg(tuple_list, int); 
          sprintf(tok, "%d ", integer); 
          strcat(buffer, tok); 
          break; 
 
         case 'f': 
          flt = va_arg(tuple_list, double); 
          sprintf(tok, "%f ", flt); 
          strcat(buffer, tok); 
          break; 
         } 
     else if (*mask_ptr == '?') 
         switch (mask_ptr[1]) 
         { 
         case 'd': 
          int_ptr = va_arg(tuple_list, int *); 
          /* need to try %p here */ 
          sprintf(tok, "%d ", int_ptr); 
          strcat(buffer, tok); 
          break; 
 
         case 's': 
          char_ptr = va_arg(tuple_list, char *); 
          sprintf(tok, "%d ", char_ptr); 
          strcat(buffer, tok); 
          break; 
 
         case 'f': 
          flt_ptr = va_arg(tuple_list, double *); 
          sprintf(tok, "%d ", flt_ptr); 
          strcat(buffer, tok); 
          break; 
         } 
     else if (*mask_ptr == ':') 
     { 
 
         if (type == OUT) 
         { 
          switch (mask_ptr[1]) 
          { 
 
          case 'd': 
              int_ptr = va_arg(tuple_list, int *); 
              size = va_arg(tuple_list, int); 
              ag_ptr = (struct aggregate *) 
                       p4_shmalloc((sizeof(int) * size) + sizeof(int)); 
              if (ag_ptr == NULL) 
              { 
               printf("agmal failed\n"); 
               exit(1); 
              } 
              ag_ptr->size = size; 
              bcopy(int_ptr, &(ag_ptr->data), (sizeof(int) *
                    size)); 
              sprintf(tok, "%d ", ag_ptr); 
              strcat(buffer, tok); 
              break; 
 
          case 's': 
              char_ptr = va_arg(tuple_list, char *); 
              size = va_arg(tuple_list, int); 
              ag_ptr = (struct aggregate *)                       
                       p4_shmalloc((sizeof(char) * size) + sizeof(int)); 
              if (ag_ptr == NULL) 
              { 
               printf("agmal failed\n"); 
               exit(1); 
              } 
              ag_ptr->size = size; 
              bcopy(char_ptr, &(ag_ptr->data), (sizeof(char)
                    * size)); 
              sprintf(tok, "%d ", ag_ptr); 
              strcat(buffer, tok); 
              break; 
 
          case 'f': 
              flt_ptr = va_arg(tuple_list, double *); 
              size = va_arg(tuple_list, int); 
              ag_ptr = (struct aggregate *) 
                        p4_shmalloc((sizeof(double) * size) +  sizeof(int)); 
              if (ag_ptr == NULL) 
              { 
               printf("agmal failed\n"); 
               exit(1); 
              } 
              ag_ptr->size = size; 
              bcopy(flt_ptr, &(ag_ptr->data),                     
             (sizeof(double) * size)); 
              sprintf(tok, "%d ", ag_ptr); 
              strcat(buffer, tok); 
              break; 
          } 
         }               /* end if type out */ 
         else 
         { 
          switch (mask_ptr[1]) 
          { 
          /* pinum2 stores the global ptr to size */
          case 'd': 
              int_ptr = va_arg(tuple_list, int *); 
              pinum2 = va_arg(tuple_list, int *); 
              sprintf(tok, "%d ", int_ptr); 
              strcat(buffer, tok); 
              break; 
 
          case 's': 
              char_ptr = va_arg(tuple_list, char *); 
              pinum2 = va_arg(tuple_list, int *); 
              sprintf(tok, "%d ", char_ptr); 
              strcat(buffer, tok); 
              break; 
 
          case 'f': 
              flt_ptr = va_arg(tuple_list, double *); 
              pinum2 = va_arg(tuple_list, int *); 
              sprintf(tok, "%d ", flt_ptr); 
              strcat(buffer, tok); 
              break; 
 
          }          
         }           
     }               
    }                
} 

 

/* Function INSTANTIATE does actual to formal assignments. It
assigns actuals in hanger to appropriate formals in template. */
 
instantiate(tuple_mask, template, hanger) 
char *tuple_mask, *template, *hanger; 
{ 
    int rc; 
    char *mask_ptr; 
    struct space_q *space_node;
    struct aggregate *aggr_node; 
    int stok(); 
    int tokint; 
    int *int_ptr; 
    char *string_ptr, *char_ptr; 
    char template_tok[80], hanger_tok[80], tokchr[80]; 
    char *pout, *pin; 
    int *generic_ptr; 
    double *flt_ptr, tokflt; 
 
    pin = template; 
    pout = hanger; 
 
    for (mask_ptr = tuple_mask + 2, stok(template_tok, pin),
           stok(hanger_tok, pout); *mask_ptr; mask_ptr += 2)
    { 
     pout = pout + strlen(hanger_tok) + 1; 
     pin = pin + strlen(template_tok) + 1; 
     stok(template_tok, pin); 
     stok(hanger_tok, pout); 
     if (*mask_ptr == '%') 
     { 
     } 
     else if (*mask_ptr == '?') 
         switch (mask_ptr[1]) 
         { 
         case 's': 
          printf("found ?s\n"); 
          sscanf(template_tok, "%d", &generic_ptr); 
          sscanf(hanger_tok, "%s", tokchr); 
          char_ptr = (char *) generic_ptr; 
          strcpy(char_ptr, tokchr); 
          break; 
 
         case 'd': 
          sscanf(template_tok, "%d", &generic_ptr); 
          sscanf(hanger_tok, "%d", &tokint); 
          *generic_ptr = tokint; 
          break; 
 
         case 'f': 
          sscanf(template_tok, "%d", &generic_ptr); 
          sscanf(hanger_tok, "%lf", &tokflt); 
          flt_ptr = (double *) generic_ptr; 
          *flt_ptr = tokflt; 
          break; 
         } 
 
     else if (*mask_ptr == ':') 
         switch (mask_ptr[1]) 
         { 
         case 'd': 
          sscanf(hanger_tok, "%d", &generic_ptr); 
          aggr_node = (struct aggregate *) generic_ptr; 
          sscanf(template_tok, "%d", &generic_ptr); 
          bcopy(&(aggr_node->data), generic_ptr,
                 (sizeof(generic_ptr) * aggr_node->size)); 
          *pinum2 = aggr_node->size; 
          p4_shfree(aggr_node); 
          break; 
 
         case 's': 
          sscanf(hanger_tok, "%d", &generic_ptr); 
          aggr_node = (struct aggregate *) generic_ptr; 
          sscanf(template_tok, "%d", &generic_ptr); 
          char_ptr = (char *) generic_ptr; 
          bcopy(&(aggr_node->data), char_ptr, (sizeof(char)       
           * aggr_node->size)); 
          *pinum2 = aggr_node->size; 
          p4_shfree(aggr_node); 
          break; 
 
         case 'f': 
          sscanf(hanger_tok, "%d", &generic_ptr); 
          aggr_node = (struct aggregate *) generic_ptr; 
          sscanf(template_tok, "%d", &generic_ptr); 
          flt_ptr = (double *) generic_ptr; 
          bcopy(&(aggr_node->data), flt_ptr, (sizeof(double)      
          * aggr_node->size)); 
          *pinum2 = aggr_node->size; 
          p4_shfree(aggr_node); 
          break; 
         }           
    } 
 
} 
 
 
 
/* Function STOK picks a space-delimited token off a source string
and returns it in tok.  It is primarily used during the
instantiation phase in IN and RD, where the actuals embedded in a
hanger and the formals embedded in a template are stripped off a
string buffer before the actual is assigned to the formal. */
 
int stok(tok, source) 
char *tok, *source; 
 
{ 
    int i; 
 
    for (i = 0; (source[i] != ' ') && (source[i] != '\0');        
   i++) 
     tok[i] = source[i]; 
    tok[i] = '\0'; 
    if (source[i] == '\0') 
     return (1); 
    else 
     return (0); 
} 
 


/* ALLOC_TUPLE_STRUCT dynamically allocates a node for a tuple
structure. */
 
struct space_q *alloc_tuple_struct() 
{ 
    struct space_q *node; 
 
    if ((node = head_avl_nodeq) == NULL) 
    { 
     node = (struct space_q *) p4_shmalloc(sizeof(struct space_q)); 
     if (node == NULL) 
         printf("Malloc failed for space_q\n"); 
    } 
    else 
    { 
     head_avl_nodeq = node->next; 
    } 
 
    return (node); 
} 

/* ALLOC_EVAL_NODE dynamically allocates a node for a work
structure in the pool of unevaluated functions. */
 
struct work_struct * alloc_eval_node() 
{ 
    struct work_struct *node; 
 
    node = (struct work_struct *) p4_shmalloc(sizeof(struct work_struct)); 
    if (node == NULL) 
     printf("malloc failed for worknode\n"); 
 
    return (node); 
} 

/* THASH is the hashing function used by OUT */

int t[256] = {1,87,49,12,176,178,102,166,121,193,6,84,249,230,44,163,14,197,
213,181,161,85,218,80,64,239,24,226,236,142,38,200,110,177,104,103,141,253,
255,50,77,101,81,18,45,96,31,222,25,107,190,70,86,237,240,34,72,242,20,214,
244,227,149,235,97,234,57,22,60,250,82,175,208,5,127,199,111,62,135,248,
174,169,211,58,66,154,106,195,245,171,17,187,182,179,0,243,132,56,148,75,
128,133,158,100,130,126,91,13,153,246,216,219,119,68,223,78,83,88,201,99,
122,11,92,32,136,114,52,10,138,30,48,183,156,35,61,26,143,74,251,94,129,
162,63,152,170,7,115,167,241,206,3,150,55,59,151,220,90,53,23,131,125,173,
15,238,79,95,89,16,105,137,225,224,217,160,37,123,118,73,2,157,46,116,9,
145,134,228,207,212,202,215,69,229,27,188,67,124,168,252,42,4,29,108,21,247,
19,205,39,203,233,40,186,147,198,192,155,33,164,191,98,204,165,180,117,76,
140,36,210,172,41,54,159,8,185,232,113,196,231,47,146,120,51,65,28,144,254,
221,93,189,194,139,112,43,71,109,184,209};


thash(word) 
char word[80]; 
 
{ 
    int h; 
    int i; 
 
    h = 0; 
    for (i = 1; word[i] != '\0'; i++) 
    { 
     h = t[h ^ word[i]]; 
    } 
    return (h); 
} 

/* MON_LINDA_INIT initializes the environment, and creates the
appropriate number of slaves. */

mon_linda_init(ac, av, functions_table) 
int *ac; 
char **av; 
struct linda_eval_table functions_table[];
{ 
    int i; 
 
    for (i=0; functions_table[i].ptr != NULL; i++)
    {
	mon_linda_functions_table[i].ptr = functions_table[i].ptr;
	strcpy(mon_linda_functions_table[i].name,functions_table[i].name);
    }
    mon_linda_functions_table[i].ptr = NULL;  /* mark end of the table */

    p4_initenv(ac, av); 
    glob = (struct globmem *) p4_shmalloc(sizeof(struct globmem)); 

    for (i = 0; i < 256; i++) 
    { 
        glob->tuple_space[i] = NULL; 
        glob->space_tails[i] = NULL; 
    } 
    glob->pool = NULL; 
    glob->pool_tail = NULL; 
    head_avl_nodeq = NULL; 
    p4_askfor_init(&(glob->TS)); 
    p4_create_procgroup();
    if (p4_get_my_id() == 0)
    {
	glob->numprocs = p4_num_total_ids();
    }
    else
    {
	slave();
	exit(0);
    }
}

 
/* Function MATCH returns success if a template matches a hanger */
 
match(template, hanger, mask) 
char *template, *hanger, *mask; 
 
{ 
    int i, k, j, count; 
    int flag = 1; 
 
    count = 0; 
    k = 0; 
    j = 0; 
    for (i = 0; (*(mask + i) != '\0') && flag; i += 2) 
    { 
     if (*(mask + i) == '%') 
     { 
         for (; (*template != ' ') || (*hanger != ' ');           
           template++, hanger++) 
         { 
          if (*template != *hanger) 
          { 
              flag = 0; 
              break; 
          } 
         } 
     } 
     else 
     { 
 
         for (; *template != ' '; template++); 
         for (; *hanger != ' '; hanger++); 
     } 
     template++; 
     hanger++; 
    } 
    return (flag); 
}


/* The termination procedure */
 
mon_linda_end() 
{ 
    p4_progend(&((glob->TS).m)); 
    p4_wait_for_end(); 
} 
