/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1991 by John E. Lloyd.				    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	hashRef
 *
 * DESCRIPTION:	Routines for referencing information in the global
 *		memory hash table.
 *
 *		These routines may be called from either the control
 *		or planning levels.
 *
 * AUTHOR/DATE:	John Lloyd, Fall 1989
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/

#include "../h/cdefs.h"
#include "../h/rciTask.h"
#include "../h/errorCodes.h"

#include "../h/rciConfig.h"
#include "../rci/hashTable.h"

extern void *locateSharedMem();

static HASH_LINK **hashTable;
static int tableOffset;
static int tableSet = UNDEF;
extern int rciCpu;

/* ----- Error Messages. Defined externally to save space ----- */

static char *cantLocateMemMsg	= "%s -- can't locate shared memory\n";
static char *bogusCpuMsg	= "%s -- obj %s: bogus cpu no. %d\n";

static hashTableImport();

static int initDone = 0;
#define INIT_CHECK()	if (!initDone) doInit();
static doInit()
{
	initDone = 1;
	tableSet = UNDEF;
	requestFlagInit (&initDone);
}

hashTableFxn (name, id)
char *name;
int id;
{
	/* The hashing function itself. Items are hashed by both
	   a string name and a distinguishing 'id' value.
	 */
	register int x;
	register char *cp = name;

	/* add up all the characters */
	
	x = 0;
	while (*cp)
	 { x += *cp++;
	 }
	x += id*17;	/* 17 is a nice prime number to use */
	return (x % HASHTAB_SIZE);
}

static hashTableImport()
{
	/* Import, if necessary, the address of the hash table 
	   valid for the current CPU, and compute the offset between
	   this address and the one seen by the planning task.
	 */

	char *fxnName = "hashTableImport()";
	extern char *hashTableTask0Addr;
	extern int rciTaskId;

	if (hashTableTask0Addr == NULL)
	 { return (0);				/* table not set up */
	 }
	if (rciTaskId == 0)			/* if planning task ... */
	 { hashTable = (HASH_LINK**)hashTableTask0Addr;
	   tableOffset = 0;
	 }
	else
	 { void *mem;
	   if ((mem = locateSharedMem (hashTableTask0Addr)) == NULL)
	    { rciAbort (EInternal, cantLocateMemMsg, fxnName);
	      return (-1);
	    }
	   hashTable = (HASH_LINK**)mem;
	   tableOffset = (char*)hashTable - hashTableTask0Addr;
	 }
	tableSet = rciCpu;
	return (1);
}

#define NEXT(h)		(HASH_LINK *)( (char*)((h)->next) + offset )

hashTableLookup(name, id, addr, cpu)
char *name;
int id;
void **addr;
int *cpu;
{
	/* Lookup a given ('name','id') pair in the hash table.

	   When searching the hash table, it is necessary to allow
	   for offsets in the values of the pointers. This is because
	   the hash table is maintained by code on the ARBITER CPU,
	   but its base address there might not correspond to the
	   base address on the current CPU. This means that all
	   pointer references can be subject to offset values.
	 */

	char *fxnName = "hashTableLookup()";
	register int offset;
	register HASH_LINK *hlink;

	INIT_CHECK();

	if (tableSet != rciCpu)
	 { int status;
	   if ((status = hashTableImport()) < 0)
	    { return (-1);
	    }
	   else if (status == 0)
	    { return (0);
	    }
	 }

	offset = tableOffset;
	hlink = (HASH_LINK*)((char*)hashTable[hashTableFxn(name,id)]+offset);
	while (hlink != (HASH_LINK*)(NULL + offset))
	 { if (id == hlink->id && 
	       strcmp ((char*)hlink+sizeof(HASH_LINK), name) == 0)
	    { break;	      
	    }
		   hlink = NEXT(hlink);
	 }
	if (hlink == (HASH_LINK*)(NULL + offset))
	 { return (0);
	 }
	if (hlink->cpu < 0 || hlink->cpu >= MAX_CPUS)
	 { rciAbort (EInternal, bogusCpuMsg, fxnName, name, cpu);
	   return (-1);
	 }
	*addr = hlink->addr;
	*cpu = hlink->cpu;
	return (1);
}
