/*
 * event.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1996,1991  Arizona Board of Regents
 *
 * $Revision: 1.3 $
 * $Date: 1996/06/14 21:33:38 $
 * 
 * HISTORY
 * $Log: event.c,v $
 * Revision 1.3  1996/06/14 21:33:38  slm
 * Merged in brakmo's changes.
 *
 * Revision 1.2  1996/04/25  20:52:51  slm
 * Added exit call after printing help information.
 *
 * Revision 1.1  1995/07/28  22:50:43  slm
 * Initial revision
 *
 * Revision 1.3  1994/12/02  18:46:56  hkaram
 * Removed unused vars
 *
 * Revision 1.2  1994/11/22  23:19:32  hkaram
 * Changed return value of eventCancel to EvCancelReturn
 *
 * Revision 1.1  1994/10/26  20:41:50  hkaram
 * Initial revision
 */

/* #define DO_HOST_BLOCK */

#include "xk_debug.h"
#include "event.h"
#include "event_i.h"
#include "assert.h"
#include "xtype.h"
#include "sc.h"
#define DEFINE_VARS
#include "xsim.h"
#undef DEFINE_VARS
#include "evtrace.h"

#define E_DETACHED_F	(1 << 0)
#define E_CANCELLED_F 	(1 << 1)

#define THIS_IS_THE_HEADER ((EvFunc)-42)

/* BIG_N should be a function of the estimated number of scheduled events,
 * such that queues don't get too long, but with as little overhead as
 * possible. 128 is probably good for up to some 500-1000 events. [mats]
 */

#define BIG_N 128 

extern int	insque();
extern int	remque();
static void	stub(Event);

int traceevent;

/* static struct Event 	evHead[BIG_N]; */
/* static int 		tickmod; */

#ifdef XK_THREAD_TRACE
Map		localEventMap;
static Map	threadEventMap;
#else
Map		localEventMap;			/* NEED TO FIX THIS! */
#endif

/* ----- begin LSB */
#define MAX_HOSTS	1000

typedef struct hostArg {
  struct hostArg *next;
  int		host;
  void		*arg;
} HostArg;

struct host {
  struct Event 	*next, *prev;
  char		*name;
  int		busy;
  Semaphore	block_sem;
} Hosts[MAX_HOSTS];

int		CurHost=-1;
static int	hostCnt=0;

static Event 	freeEventList=NULL;
static int   	sizeEventAlloc=100;
static int   	sizeEventAllocInit=400; 
static HostArg 	*freeHostArgList=NULL;
/*        int   	xsimTimeGranularity=1; */
/* unsigned int 	xsimCurrentTime=0;	 */
static u_long	eventCnt=0, eventCntMax;
static struct	Event eventList;
/*        int	xsimDbgFlags=0; */
static Sc 	xsimAddrNameMap=NULL;
static char	*unknownName="????";

static struct Event eventCal2[2], eventCal4[4], eventCal8[8];
static struct Event eventCal16[16];
static struct Event eventCal32[32], eventCal64[64], eventCal128[128];
static struct Event eventCal256[256], eventCal512[512], eventCal1024[1024];
static struct Event *eventCals[10]={eventCal2, eventCal4, eventCal8,
		    eventCal16, eventCal32, eventCal64, eventCal128,
		    eventCal256, eventCal512, eventCal1024};
static Event  eventCalCur=eventCal64;
static int    eventCalIndx=5, eventCalSize=64, eventCalIndxMax=9;;
static int    eventCalCurIndx=0, eventCalGrowFlag=0;

static u_long us_histo[1000], ms_histo[1000], s_histo[1000], cnt_histo=0;
static u_long next_exec_histo[1000], next_exec_cnt=0;
static u_long   next_insert_histo[1000], next_insert_cnt=0;

static void e_remque(Event);
static void e_insque(u_long, Event);

int
xsimAddHost (char *name)
{
  struct host *hp;

  if (hostCnt >= MAX_HOSTS)
    Kabort("ERROR: Need to increase MAX_HOSTS!\n");
  hp = &Hosts[hostCnt];
  hp->next = hp->prev = (Event)hp;
  hp->name = xMalloc(strlen(name)+1);
  strcpy(hp->name, name);
  hp->busy = 0;
  semInit(&hp->block_sem, 0);
  return hostCnt++;
}

void
xsimSetCurHost (int host)
{
  CurHost = host;
}

int
xsimGetCurHost ()
{
  return CurHost;
}

static void 
setHostNotBusy(Event e, void *varg)
{
  HostArg 	*harg=(HostArg *)varg;
  struct host 	*hp=&Hosts[harg->host];
  int		Vall(Semaphore *);

  xsimDbg(EHT_FLAG, printf("[setHostNotBusy] h:%s, id:%d\n", hp->name,
			   harg->arg));
  if (!hp->busy) 
    Kabort("Host is not busy in setHostNotBusy");
  hp->busy = 0;
  VAll(&hp->block_sem);
}

void 
xsimSetHostBusy(int deltat)
{
  static int 	opId=0;
  int 		host=CurHost, id;

  Kabort("ERROR: using xsimSetHostBusy!\n");
  if (CurHost == 0) 
    Kabort("ERROR: CurHost is 0 in xsimSetHostBusy!");
  else if (Hosts[CurHost].busy)
    Kabort("ERROR: CurHost is busy in xsimSetHostBusy!");
  id = opId++;
  xsimDbg(EHT_FLAG, printf("[setHostBusy] h:%s, id:%d, deltat:%d\n",
			   (CurHost != -1) ? Hosts[CurHost].name : "", id, deltat));
  Hosts[CurHost].busy = 1;
  evDetach(evSchedule(setHostNotBusy, (void *)id, deltat));
  realPforHost(&Hosts[CurHost].block_sem);
  CurHost = host;
  xsimDbg(EHT_FLAG, printf("[setHostBusy] h:%s, id:%d WAKING!\n", 
			   Hosts[CurHost].name, id));
}

int 
xsimHostNotBusy(int host)
{
  return !Hosts[host].busy;
}

void
xsimWaitUntilHostNotBusy(int host)
{
  if (Hosts[host].busy) {
    CurHost = host;
    realPforHost(&Hosts[host].block_sem);
  }
}

/* ----- end LSB */

void
evInit()
{
  char  	*cp, c, str[20];
  int   	i, j, k, cnt=0;
  Event 	e;
  HostArg 	*hap;

  for (k=1; k<globalArgc; k++) {
    if (!strcmp(globalArgv[k], "-xsimdbg")) {
      while (k+1 < globalArgc  &&
	     (!strncmp(globalArgv[k+1], "E:", 2) || 
	      !strncmp(globalArgv[k+1], "S:", 2) ||
	      !strncmp(globalArgv[k+1], "T:", 2)) ) {
	cp = globalArgv[++k];
	c = *cp;
	cp += 2;
	while (*cp != '\0') {
	  str[0] = c;
	  str[1] = *cp++;
	  str[2] = *cp++;
	  str[3] = '\0';
	  for (i=0; i<NUM_FLAGS; i++) 
	    if (!strncmp(str, xsimDbgTable[i].id, 3)) {
	      xsimDbgFlags |= xsimDbgTable[i].flag;
	      printf("[evInit    ] found flag `%s'\n", str);
	      break;
	    }
	  if (*cp == ',')
	    cp++;
	}
      }
    }
    else if (!strcmp(globalArgv[k], "-h")) {
      for (i=0; xsimHelp[i] != NULL; i++)
	printf("%s\n", xsimHelp[i]);
      exit(0);
    }
  }
  if (xsimDbgFlags & EFN_FLAG) { /* get address-name map */
    char str[200], buf[1100], *cp, c, *namebuf, *namep;
    int  i, j, k, addr, n=1100, namebuflen=0;
    FILE *pin;

    sprintf(str, "nm -ph %s", globalArgv[0]);
    xsimAddrNameMap = ScCreate(2, 3000);
    if ((pin = popen(str, "r")) == NULL) {
      printf("ERROR evInit could not read nm output (%s)\n", str);
    }
    else {
      cp = buf;
      while (fread(cp, 1, n, pin) == n) {
/* 	printf("[evInit    ] fread %d\n", n); */
	cp = buf;
	while (cp-buf <= 1000) {
	  /* lines with type 's' have an empty str */
	  if (cp[11] == 't' || cp[11] == 'T')
	    sscanf(cp, "%10d %c %s", &addr, &c, str);
	  else
	    c = cp[11];
	  while (*cp != '\n')
	    cp++;
	  cp++;
	  if (c != 'T'  &&  c != 't')
	    continue;
	  if (strlen(str) >= namebuflen) {
	    namebuf = namep = (char *) malloc(4000);
	    namebuflen = 4000;
	  }
	  strcpy(namep, str);
	  namebuflen -= strlen(str) + 1;
	  ScInsert(xsimAddrNameMap, (void *)addr, (void *)namep);
	  cnt++;
	  namep += strlen(str) + 1;
	}
	bcopy(cp, buf, (j = 1100-(cp-buf)));
	n = cp - buf;
	cp = buf + j;
      }
      pclose(pin);
      printf("\n             Entries in map: %d\n", cnt);
/*       printf("\nPrinting Map:\n"); */
/*       ScPrint(xsimAddrNameMap); */
    }
  }
  xsimDbg(ALL_FLAGS, printf("[evInit]\n"));
  eventList.next = eventList.prev = &eventList;
  eventList.func = THIS_IS_THE_HEADER;

  for (k=0; k<eventCalSize; k++) {
    eventCalCur[k].next = eventCalCur[k].prev = &eventCalCur[k];
    eventCalCur[k].func = THIS_IS_THE_HEADER;
  }
  freeEventList = e = (Event) xMalloc(sizeof(struct Event)*sizeEventAllocInit);
  for (k=0; k<sizeEventAllocInit-1; k++) {
    e->next = e + 1;
    e++;
  }
  e->next = NULL;

  freeHostArgList = hap = (HostArg *) 
    xMalloc(sizeof(HostArg)*sizeEventAllocInit);
  for (k=0; k<sizeEventAllocInit-1; k++) {
    hap->next = hap + 1;
    hap++;
  }
  hap->next = NULL;

  traceInit();
}

#define PRINT_VAL(v)   \
  if (v >= 100000000) \
    fprintf(fout, "%5ldM ", v/1000000); \
  if (v >= 100000) \
    fprintf(fout, "%5ldK ", v/1000); \
  else  \
    fprintf(fout, "%5ld  ", v);

int
printEventMax()
{
  int          i, k;
  u_long n;
  FILE   *fout;

  printf("eventCntMax: %ld\n", eventCntMax);
  if ((fout=fopen("event.out", "w")) != NULL) {
    fprintf(fout, "eventCntMax: %ld\n", eventCntMax);
    fprintf(fout, "cnt_histo: %ld\n\n", cnt_histo);
    fprintf(fout, "us ..................\n");
    fprintf(fout, "%4d: ", 0);
    for (k=n=i=0; k<1000; k++) {
      n += us_histo[k];
      PRINT_VAL(us_histo[k]);
      if ((++i)%10 == 0)
        fprintf(fout, "\n%4d: ", k);
    }
    fprintf(fout, "\nTotal us events: %ld\n", n);
    fprintf(fout, "\nms ..................\n");
    fprintf(fout, "%4d: ", 0);
    for (k=n=i=0; k<1000; k++) {
      n += ms_histo[k];
      PRINT_VAL(ms_histo[k]);
      if ((++i)%10 == 0)
        fprintf(fout, "\n%4d: ", k);
    }
    fprintf(fout, "\nTotal ms events: %ld\n", n);
    fprintf(fout, "\ns ..................\n");
    fprintf(fout, "%4d: ", 0);
    for (k=n=i=0; k<1000; k++) {
      n += s_histo[k];
      PRINT_VAL(s_histo[k]);
      if ((++i)%10 == 0)
        fprintf(fout, "\n%4d: ", k);
    }
    fprintf(fout, "\nTotal s events: %ld\n", n);
    fprintf(fout, "\nnext_exec ..................\n");
    fprintf(fout, "%4d: ", 0);
    for (k=n=i=0; k<1000; k++) {
      n += next_exec_histo[k];
      PRINT_VAL(next_exec_histo[k]);
      if ((++i)%10 == 0)
        fprintf(fout, "\n%4d: ", k);
    }
    fprintf(fout, "\nTotal next_exec events: %ld\n", next_exec_cnt);
    fprintf(fout, "\nnext_insert ..................\n");
    fprintf(fout, "%4d: ", 0);
    for (k=n=i=0; k<1000; k++) {
      n += next_insert_histo[k];
      PRINT_VAL(next_insert_histo[k]);
      if ((++i)%10 == 0)
        fprintf(fout, "\n%4d: ", k);
    }
    fprintf(fout, "\nTotal next_insert events: %ld\n", next_insert_cnt);
    fclose(fout);
  }
  return 0;
}

static void
showEventQueue ()
{
  char  *cp;
  int   n=0;
  Event a;
  int hostid;

  if ((a=eventList.next) == &eventList) {
    printf("   Event Queue EMPTY\n");
      return;
  }
  printf("\n");
  for (a = eventList.next; a != &eventList; a = a->next) {
    if (xsimDbgFlags & EFN_FLAG) {
      cp = (char *) ScLookup(xsimAddrNameMap, (char *) a->func);
      if (cp == NULL)
	cp = unknownName;
    }
    else
      cp = " ";
    hostid = ((HostArg *)a->arg)->host;
/* HASNAIN    printf("       [%3d] (%d.%06d)  h:%s %8x  %s\n", n++, 
	   a->deltat/(1000000/xsimTimeGranularity),
	   xsimTimeGranularity*(a->deltat%(1000000/xsimTimeGranularity)), 
	   (hostid != -1) ? Hosts[hostid].name : "", a->func, cp); */
    printf("       [%3d] (%d.%06d)  h:%s %s\n", n++, 
	   a->deltat/(1000000/xsimTimeGranularity),
	   xsimTimeGranularity*(a->deltat%(1000000/xsimTimeGranularity)), 
	   (hostid != -1) ? Hosts[hostid].name : "", cp);
  }
}

static void
moveCal(void)
{
  int   k, calIndx=eventCalIndx, calSize=eventCalSize;
  Event a, evp=eventCalCur;

  if (eventCnt > 2*eventCalSize) {
    if (eventCalIndx >= eventCalIndxMax)
      return;
    eventCalGrowFlag = 1;
    eventCalIndx++;
  }
  else if (eventCnt < eventCalSize/2 &&  eventCnt > 4)
    eventCalIndx--;
  else
    return;

  eventCalSize = 1<<(eventCalIndx+1);
  eventCalCur = eventCals[eventCalIndx];
  for (k=0; k<eventCalSize; k++) {
    eventCalCur[k].next = eventCalCur[k].prev = &eventCalCur[k];
    eventCalCur[k].func = THIS_IS_THE_HEADER;
  }
  for (k=0; k<calSize; k++) {
    while ((a=evp[k].next) != &evp[k]) {
      e_remque(a);
      e_insque(a->deltat - xsimCurrentTimeFine, a);
    }
  }
}

static void
e_insque(unsigned long t, Event e)
{
  int    n=-1, i;
  Event a;

  if (++eventCnt > 2*eventCalSize  && eventCalIndx < eventCalIndxMax)
    moveCal();
  e->deltat = xsimCurrentTimeFine + t;
  i = (e->deltat >> SIM_CLOCK_POWER) % eventCalSize;
  for (a = eventCalCur[i].next; a != &eventCalCur[i]; a = a->next) {
    if (a->deltat <= e->deltat) {
      /* E goes after a */
       continue;
    } else {
      /* E goes just before a */
       insque(e, a->prev);
      return;
    }
  }
  /* E goes at the end */
  insque(e, eventCalCur[i].prev);
  return;

/*
  if (++eventCnt > eventCntMax) eventCntMax = eventCnt;
  e->deltat = t;
*/

  for (a = eventList.next; a != &eventList; a = a->next) {
    n++;
    if (a->deltat <= e->deltat) { /* LSB replaced < with <= */
      /* E goes after a */
       continue;
    } else {
      /* E goes just before a */
       if (n < 1000)
         next_insert_histo[n]++;
       else
         next_insert_histo[999]++;
       next_insert_cnt++;
       insque(e, a->prev);
       xsimDbg(EIQ_FLAG, printf("[e_insque m] eventList: "));
       xsimShowQueue(EIQ_FLAG);
      return;
    }
  }
  /* E goes at the end */
  insque(e, eventList.prev);
  xsimDbg(EIQ_FLAG, printf("[e_insque b] eventList: "));
  xsimShowQueue(EIQ_FLAG);
}

static void
e_remque(Event e)
{
  eventCnt--;
  remque(e);
  xsimDbg(ERQ_FLAG, printf("[e_remque  ] eventList: "));
  xsimShowQueue(ERQ_FLAG);
}

static void
stub(Event e)
{
    char 	*cp;
    /* HostArg 	*hap=(HostArg *)e->arg; */

    if ( e->flags & E_CANCELLED_F ) {
	xTrace1(event, TR_MORE_EVENTS,
		"event stub not starting cancelled event %x", e);
/* 	xFree((char *)e); */
	e->next = freeEventList;			/* LSB */
	freeEventList = e;				/* LSB */
/*	hap->next = freeHostArgList;
	freeHostArgList = hap;
*/
	return;
    }
    e->state = E_RUNNING;
    /* CurHost = hap->host; */
#ifdef XSIM_DEBUG
    if (xsimDbgFlags & ESE_FLAG) {
      if (xsimDbgFlags & EFN_FLAG) {
	cp = (char *) ScLookup(xsimAddrNameMap, (char *) e->func);
	if (cp == NULL)
	  cp = unknownName;
      }
      else
	cp = " ";
/* HASNAIN       printf("[stub      ] h:%s Exec: %s (%x)\n", (CurHost != -1) ? Hosts[CurHost].name : "",
	     cp, e->func);*/
      printf("[stub      ] h:%s Exec: %s ()\n", (CurHost != -1) ? Hosts[CurHost].name : "",
	     cp);
    }
#endif
/*    if (e->func != setHostNotBusy)
      e->func(e, hap->arg);
    else
      e->func(e, hap);
*/
    e->func(e, e->arg);
#ifdef XSIM_DEBUG
    if (xsimDbgFlags & ESE_FLAG) {
      if (xsimDbgFlags & EFN_FLAG) {
	cp = (char *) ScLookup(xsimAddrNameMap, (char *) e->func);
	if (cp == NULL)
	  cp = unknownName;
      }
      else
	cp = " ";
      printf("[stub done ] h:%s Exec: %s (%x event:%x)\n", (CurHost != -1) ? Hosts[CurHost].name : "",
	     cp, e->func, e);
    }
#endif
    e->state = E_FINISHED;
    if ( e->flags & E_DETACHED_F ) {
/* 	xFree((char *)e); */
      e->next = freeEventList;				/* LSB */
      freeEventList = e;				/* LSB */
/*      hap->next = freeHostArgList;
      freeHostArgList = hap;
*/
    }
}

Event
evSchedule( EvFunc func, void *arg, unsigned time)  /* time in usec */
{
  char  	*cp;
  Event 	e;
  HostArg 	*hap;
  u_long	delt;

  xTrace3(event, TR_GROSS_EVENTS, "evSchedule: f = %x, arg = %x, time = %d",
	  func, arg, time);
/*   e = (Event)xMalloc(sizeof(struct Event)); */

#ifdef XSIM_DEBUG
    if (xsimDbgFlags & EES_FLAG) {
      if (xsimDbgFlags & EFN_FLAG) {
	cp = (char *) ScLookup(xsimAddrNameMap, (char *) func);
	if (cp == NULL)
	  cp = unknownName;
      }
      else
	cp = " ";
/* HASNAIN       printf("[evSchedule] h:%s %s (%x), arg: %x, time: %d    ", 
	     (CurHost != -1) ? Hosts[CurHost].name : "", cp, func, arg, time);*/
       printf("[evSchedule] h:%s %s (), time: %d    ", 
	     (CurHost != -1) ? Hosts[CurHost].name : "", cp, time);
    }
#endif

  /* --- Get event structure LSB */
  if (freeEventList == NULL) {		
    int k;
    freeEventList = e = (Event) xMalloc(sizeof(struct Event)*sizeEventAlloc);
    for (k=0; k<sizeEventAlloc-1; k++) {
      e->next = e + 1;
      e++;
    }
    e->next = NULL;
  }
  /* --- Get hostArg entry
  if (freeHostArgList == NULL) {		
    int k;
    freeHostArgList = hap = (HostArg *) 
      xMalloc(sizeof(HostArg)*sizeEventAlloc);
    for (k=0; k<sizeEventAlloc-1; k++) {
      hap->next = hap + 1;
      hap++;
    }
    hap->next = NULL;
  }
*/

  e = freeEventList;
  freeEventList = e->next;
/*  hap = freeHostArgList;
  freeHostArgList = hap->next;
  hap->host = CurHost;
  hap->arg = arg;
*/
  e->func = func;
  e->arg = arg; /* (void *)hap; */

/*  delt = (time + xsimTimeGranularity/2) / xsimTimeGranularity; */
  delt = time << SIM_CLOCK_POWER;
/*  if (delt == 0 && time != 0) {
      delt = 1;
  }
*/
  xTrace1(event, TR_EVENTS, "event requires %d clock ticks", delt);
/*  if (delt < 1000)
    us_histo[delt]++;
  else if (delt < 1000000)
    ms_histo[delt/1000]++;
  else
    s_histo[delt/1000000]++;
  cnt_histo++;
*/
  e->flags = 0;
/*  if (0  &&  delt == 0  &&  !Hosts[CurHost].busy) { 
    --- Should not execute this, since I can get a stub waiting to
           execute and current process may set to busy!
    e->state = E_SCHEDULED;
    createprocess(stub, e);
    xsimDbg(EES_FLAG, printf("  EXECUTING NOW!\n"));
    CreateKernelProcess(stub, STD_PRIO, 1, e);
  } else { */
    xTrace0(event, TR_FUNCTIONAL_TRACE, "Placing event in queue");
    xsimDbg(EES_FLAG, printf("ENQUEING\n"));
/*    e_insque(xsimCurrentTime+delt, e); */
    e_insque(delt, e);
    e->state = E_PENDING;
/*  } */
  xTrace1(event, TR_MAJOR_EVENTS, "evSchedule returns event %x", e);
  return e;
}

void
evDetach(Event e)
{
/*  HostArg *hap=(HostArg *)e->arg; */

  xTrace1(event, TR_GROSS_EVENTS, "evDetach: event = %x", e);
  if ( e->state == E_FINISHED ) {
/*     xFree((char *)e); */
    e->next = freeEventList;				/* LSB */
    freeEventList = e;					/* LSB */
/*    hap->next = freeHostArgList;
    freeHostArgList = hap;
*/
  } else {
    e->flags |= E_DETACHED_F;
  }
}

/* cancel event e:
   returns -1 if it knows that the event has already executed to completion
   returns  0 if it can guarantee that either f is currently running or that
       it will run in the future
   returns  1 if it can guarantee that f has not run, and will not run in
       the future
 */
EvCancelReturn
evCancel(Event e)
{
  int 		ans;
/*  HostArg 	*hap=(HostArg *)e->arg; */

  xTrace1(event, TR_GROSS_EVENTS, "evCancel: event = %x", e);
  switch ( e->state ) {

    case E_SCHEDULED:
      e->flags |= ( E_DETACHED_F | E_CANCELLED_F );
      /* 
       * The stub routine will catch this event before it gets a chance to
       * run
       */
      ans = EVENT_CANCELLED;
      break;

    case E_RUNNING:
      e->flags |= ( E_DETACHED_F | E_CANCELLED_F );
      ans = EVENT_RUNNING;
      break;

    case E_FINISHED:
      ans = EVENT_FINISHED;
/*       xFree((char *)e); */
      e->next = freeEventList;				/* LSB */
      freeEventList = e;				/* LSB */
/*    hap->next = freeHostArgList;
      freeHostArgList = hap;
*/
      break;

    case E_PENDING:
      e_remque(e);
      ans = EVENT_CANCELLED;
/*       xFree((char *)e); */
      e->next = freeEventList;				/* LSB */
      freeEventList = e;				/* LSB */
/*    hap->next = freeHostArgList;
      freeHostArgList = hap;
*/
      break;
  }

  return ans;
}

int
evIsCancelled( e )
    Event	e;
{
    xAssert(e);
    return e->flags & E_CANCELLED_F;
}

static void
traceEvent (Event e, char *s)
{
  char *cp;
  int hostid;

  if (xsimDbgFlags & ECI_FLAG) {
    if (xsimDbgFlags & EFN_FLAG) {
      cp = (char *) ScLookup(xsimAddrNameMap, (char *) e->func);
      if (cp == NULL)
	cp = unknownName;
    }
    else
      cp = " ";
    hostid = ((HostArg *)e->arg)->host;
/* HASNAIN     printf("[clock_ih  ] (%d.%06d) h:%s%s Executing event: %s (%x)\n", 
	   e->deltat/(1000000/xsimTimeGranularity), 
	   xsimTimeGranularity*(e->deltat%(1000000/xsimTimeGranularity)), 
	   (hostid != -1) ? Hosts[hostid].name : "", s, cp, e->func); */
     printf("[clock_ih  ] (%d.%06d) h:%s%s Executing event: %s ()\n", 
	   e->deltat/(1000000/xsimTimeGranularity), 
	   xsimTimeGranularity*(e->deltat%(1000000/xsimTimeGranularity)), 
	   (hostid != -1) ? Hosts[hostid].name : "", s, cp);
  }
}

int
clock_ih()
{
    int     i, k, found=0;
    u_long  smallTimeVal=0xffffffffffffff, smallTimeIndx;
    Event   a, e;
    Event   head;
    HostArg *hap;
    
    xTrace0(event, TR_GROSS_EVENTS, "event clock interrupt");

    /* --- See if can execute events waiting for host not busy */
/*
    for (k=0; k<hostCnt; k++) {
      if (!Hosts[k].busy  &&  Hosts[k].next != (Event)&Hosts[k]) {
	found = 1;
	e = Hosts[k].next;
	remque(e);
	xsimDbg(ECI_FLAG, traceEvent(e, "(old)"));
	e->state = E_SCHEDULED;
	CreateProcess((int (*)())stub, STD_PRIO, 1, (int)e);
      }
    }
    if (found)
      return 0;
*/

    for (k=0; k<eventCalSize; k++) {
      e = (head = &eventCalCur[eventCalCurIndx])->next;
      if (e == head) {
        xsimCurrentTimeFine = (xsimCurrentTimeFine >> SIM_CLOCK_POWER) + 1;
        xsimCurrentTimeFine = (xsimCurrentTimeFine << SIM_CLOCK_POWER);
        eventCalCurIndx = (eventCalCurIndx + 1)%eventCalSize;
        continue;
      }
      else if (e->deltat < xsimCurrentTimeFine + SIM_CLOCK_MULT) {
        xsimCurrentTimeFine = e->deltat;
        xsimCurrentTime = xsimCurrentTimeFine >> SIM_CLOCK_POWER;
        while (e != head  &&  e->deltat == xsimCurrentTimeFine) {
          a = e->next;
          e_remque(e);
          e->state = E_SCHEDULED;
          /* createprocess(stub, e); */
          /* --- LSB: change so we don't have so many at one time! */
          /*          probably by picking at random! */
          CreateProcess((int (*)())stub, STD_PRIO, 1, (long)e);
          e = a;
        }
        if (eventCnt < eventCalSize/2  &&  eventCalGrowFlag)
          moveCal();
        return 0;
      }
      else if (smallTimeVal > e->deltat) {
        smallTimeVal = e->deltat;
        smallTimeIndx = eventCalCurIndx;
      }
      xsimCurrentTimeFine = (xsimCurrentTimeFine >> SIM_CLOCK_POWER) + 1;
      xsimCurrentTimeFine = (xsimCurrentTimeFine << SIM_CLOCK_POWER);
      eventCalCurIndx = (eventCalCurIndx + 1)%eventCalSize;
    }
    if (smallTimeVal == 0xffffffffffffff) {
      printf("\n[clock_ih] *** no more events to run, %s\n",
             "ending simulation!\n");
      Kabort("Simulation terminated!\n");
    }
    eventCalCurIndx = smallTimeIndx;
    xsimCurrentTimeFine = eventCalCur[eventCalCurIndx].next->deltat;
    clock_ih();
    return 0;

    /***** SHOULD NOT BE EXECUTED **/
    head = &eventList;
    e = head->next;
    if (e == head) {
/*       xsimDbg(ECI_FLAG,  */
      printf("\n[clock_ih] *** no more events to run, %s\n",
	     "ending simulation!\n");
/*       ); */
      /* return 1; */
      Kabort("Simulation terminated!\n");
    }

    k = e->deltat - xsimCurrentTime;
    if (k < 1000)
      next_exec_histo[k]++;
    else
      next_exec_histo[999]++;
    next_exec_cnt++;
    xsimCurrentTime = e->deltat;
    while (e != head  &&  e->deltat == xsimCurrentTime) {
      xsimDbg(ECI_FLAG, traceEvent(e, ""));
      a = e->next;
      e_remque(e);
/*
      hap = (HostArg *)e->arg;
      if (hap->host >= 0 && Hosts[hap->host].busy &&
	  e->func != setHostNotBusy) {
	xsimDbg(ECI_FLAG, printf("[clock_ih  ] HOST BUSY, enqueuing\n"));
	insque(e, Hosts[hap->host].prev);
      }
      else {
*/
	e->state = E_SCHEDULED;
	/* createprocess(stub, e); */
        /* --- LSB: change so we don't have so many at one time! */
	/*          probably by picking at random! */
	CreateProcess((int (*)())stub, STD_PRIO, 1, (int)e);
/*    } */
      e = a;
    }
    return 0;
}

void
evCheckStack(char *name)
{
}

void
evMarkBlocked( Semaphore *s )
{
}

void 
evMarkRunning()
{
}
