/*
 * $RCSfile: event_monitor.c,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Log: event_monitor.c,v $
 * Revision 1.2  1996/01/29 19:46:05  slm
 * Updated copyright and version.
 *
 * Revision 1.1  1995/07/28  21:41:44  slm
 * Initial revision
 *
 * Revision 1.11.2.2  1994/11/22  20:50:49  hkaram
 * Added localEventMap
 *
 * Revision 1.11.2.1  1994/10/27  20:51:46  hkaram
 * New branch
 *
 * Revision 1.11  1994/04/15  21:18:42  davidm
 * (sortFunc): Don't define/declare it if XKMACHKERNEL is defined.
 *
 * Revision 1.10  1994/02/05  00:08:56  menze
 *   [ 1994/01/31          menze ]
 *   assert.h renamed xk_assert.h
 *
 * Revision 1.9  1994/01/25  05:58:15  davidm
 * evDump: if the localEventMap was empty, a core dump was produced to to
 * attempting to free (sort) a null pointer.
 *
 * dispEvent: pointers are now printed as longs.
 *
 * Revision 1.8  1993/12/13  19:07:32  menze
 * Fixed #endifs
 * Modified prototypes
 */

/*
 * Code supporting ps-like tracing for x-kernel events.  Some of this
 * support is in the platform-specific event code.
 */

#include "event.h"
#include "event_i.h"
#include "xk_assert.h"
#include "x_libc.h"
#include "xk_debug.h"

#ifdef XK_THREAD_TRACE

#ifdef __STDC__

static char *evStateStr(EvState);
static int  xTime2sec(XTime);
static void dispEvent(Event, XTime);
static int  findEvents(VOID *, VOID *, VOID *);
# ifndef XKMACHKERNEL
static int  sortFunc(Event *, Event *);
# endif

#else

static char *evStateStr();
static int  xTime2sec();
static void dispEvent();
static int  findEvents();
#ifndef XKMACHKERNEL
static int  sortFunc();
#endif

#endif /* __STDC__ */

extern Map localEventMap;

static char *
evStateStr(s)
EvState s;
{
    switch (s) {
      case E_PENDING:   return "PENDING";
      case E_SCHEDULED: return "SCHED";
      case E_RUNNING:   return "RUNNING";
      case E_FINISHED:  return "FINISH";
      case E_BLOCKED:   return "BLOCKED";
      default:          return "UNKNOWN";
    }
}

static int
xTime2sec(t)
XTime t;
{
    t.usec += 500 * 1000;
    t.sec += t.usec / (1000 * 1000);
    return t.sec;
}

static void
dispEvent(ev, now)
Event ev;
XTime now;
{
    XTime diff;

    xAssert(ev);
    printf("%8lx  ", (u_long)ev->func);
    printf("%8lx\t", (u_long)ev->arg);
    printf("%s\t", evStateStr(ev->state));
    switch (ev->state) {
        case E_PENDING:
	    xSubTime(&diff, ev->startTime, now);
	    printf("%8d", xTime2sec(diff));
	    break;
        case E_SCHEDULED:
        case E_RUNNING:
	    xSubTime(&diff, now, ev->startTime);
	    printf("%8d", xTime2sec(diff));
	    break;
        case E_FINISHED:
        case E_BLOCKED:
	    xSubTime(&diff, now, ev->stopTime);
	    printf("%8d", xTime2sec(diff));
	    break;
    }
    printf("\t");
    if (ev->flags & E_DETACHED_F)
	printf("%c", 'D');
    if (ev->flags & E_CANCELLED_F)
	printf("%c", 'C');
    printf("\n");
}

#define MAX_EVENTS 128	/* just a suggestion */

typedef struct {
    Event *arr;
    int   i;
    int   max;
} EvArray;

static int
findEvents(key, val, arg)
VOID *key, *val, *arg;
{
    EvArray *eva = (EvArray *)arg;
    Event   *newArray;
    int     newSize;

    if (eva->i >= eva->max) {
	newSize = eva->max ? eva->max * 2 : MAX_EVENTS;
	newArray = (Event *)xMalloc(sizeof(Event) * newSize);
	bzero((char *)newArray, sizeof(Event) * newSize);
	bcopy((char *)eva->arr, (char *)newArray, sizeof(Event) * eva->max);
	if (eva->arr)
	    xFree((char *)eva->arr);
	eva->arr = newArray;
	eva->max = newSize;
    }
    eva->arr[eva->i++] = (Event)val;
    return TRUE;
}

#ifndef XKMACHKERNEL
static int
sortFunc(e1, e2)
Event *e1, *e2;
{
    if ((*e1)->state != (*e2)->state)
	return (u_int)(*e1)->state - (u_int)((*e2)->state);
    if ((*e1)->func != (*e2)->func)
	return (u_int)(*e1)->func - (u_int)(*e2)->func;
    if ((*e1)->arg != (*e2)->arg)
	return (u_int)(*e1)->arg - (u_int)(*e2)->arg;
    return 0;
}
#endif /* XKMACHKERNEL */

void
evDump()
{
    XTime   now;
    EvArray evArray;
    int     i;

    xGetTime(&now);
    evArray.arr = 0;
    evArray.max = 0;
    evArray.i = 0;
    mapForEach(localEventMap, findEvents, &evArray);
#ifndef XKMACHKERNEL
    if (evArray.arr)
	qsort((char *)evArray.arr, evArray.i, sizeof(Event),
	      (QSortFunc)sortFunc);
#endif
    printf("   Func      arg\tstate\t  seconds\tflags\n\n");
    for (i=0; i < evArray.i; i++)
	dispEvent(evArray.arr[i], now);
    if (evArray.arr)
	xFree((char *)evArray.arr);
}

#else	/* ! XK_THREAD_TRACE */

void
evDump()
{
}

#endif /* XK_THREAD_TRACE */
