/* 
 * machine.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1996,1993,1991,1990  Arizona Board of Regents
 *
 * $Revision: 1.2 $
 * $Date: 1996/04/25 20:55:35 $
 * 
 * HISTORY 
 * $Log: machine.c,v $
 * Revision 1.2  1996/04/25 20:55:35  slm
 * Updated copyright and version.
 *
 * Revision 1.1  1995/07/28  22:50:43  slm
 * Initial revision
 *
 * Revision 1.2  1994/11/22  23:18:57  hkaram
 * Changed Pfi to Ptrfi
 *
 * Revision 1.1  1994/10/26  20:41:50  hkaram
 * Initial revision
 */

#include "xtype.h"
#include "xk_debug.h"
#include "platform.h"
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
#include <signal.h>

#include "machine.h"

/* sparc changes */
#ifdef sparc
#include "process.h"
#include "assert.h"
void signal_handler();
extern pthread_mutex_t master_monitor;
#endif sparc


int tracesystem=0;
extern int SignalsPossible;

struct	int_vector {
    Ptrfi	handler;
    VOID	*arg;
/* device is now given by the index
   int	device;
*/
};


int inInterrupt;
int	dispatch();

/* don't know how many sockets we should allow for */
/* update this in [udp,tcp].c too */
#define NUMSOCKETSICANUSE 30
struct	int_vector  ivec[NUMSOCKETSICANUSE+1];
int                 ivec_in_use_mask;
extern	int	errno;

void
cancelSignalHandler(sock)
    int sock;
{
  ivec_in_use_mask &= ~(1 << sock);
  xTrace2(system, TR_MAJOR_EVENTS, "Cancelling handler for %d mask = %x", sock, ivec_in_use_mask);
}


void
installSignalHandler( sock, f, arg )
    int 	sock;
    Ptrfi 	f;
    VOID	*arg;
{
    ivec[sock].handler = f;
    ivec[sock].arg = arg;
    ivec_in_use_mask |= (1 << sock);
    SignalsPossible = 1;
    xTrace3(system, TR_MAJOR_EVENTS,
	    "Setting handler for %d, arg = %x, mask = %x",
	    sock, arg, ivec_in_use_mask);
}

static unsigned int heldmask = 0;


xholdsignals(sock)
{
  xTrace1(system, TR_EVENTS, "Holding file descriptor %d", sock);
  heldmask |= (1 << sock);
}

xreleasesignals(sock)
int sock;
{
  xTrace1(system, TR_EVENTS, "Releasing file descriptor %d", sock);
  heldmask &= ~(1 << sock);
}

/*
 *
 *  Interrupt Handler
 *
 *  The handler is now invoked with a single integer argument
 *  identifying the socket to service, so that more than one
 *  socket may use the same handler.
 */
findsocket()
{
  int	mask, i, n;
  static struct timeval zero = {0, 0};
  for (i = 0; i < 32; i++) {
    mask = (1 << i);
    n = select(32, (fd_set *)&mask, (fd_set *)0, (fd_set *)0, &zero);
    if (n == 1) {
      return (i);
    }
  }
  return(33);
}

fixFileMask()
{
  int	mask, i;
  static struct timeval zero = {0, 0};
  for (i = 0; i < 32; i++) {
    if (ivec_in_use_mask & (1 << i)) {
      mask = (1 << i);
      if (select(32, (fd_set *)&mask, (fd_set *)0, (fd_set *)0, &zero) < 0 && errno == EBADF) {
	xTrace1(system, TR_MAJOR_EVENTS, "Turning off socket #%d", i);
	ivec_in_use_mask &= ~(1 << i);
      }
    }
  }
}

/*ARGSUSED*/
dispatch(interruptNo)
int interruptNo;
{
  register int i;
  int	mask, n, foundany=0;
  static struct timeval zero;

  inInterrupt++;
  while (1) {
    mask = ivec_in_use_mask & ~heldmask;
    if((n = select(NUMSOCKETSICANUSE, (fd_set *)&mask, (fd_set *)0, (fd_set *)0, &zero)) == -1) {
      if (errno == EBADF) {
	xTrace0(system, TR_MAJOR_EVENTS, "EBADF on select in dispatch");
	fixFileMask();
	continue;
      } else {
	perror("select");
	inInterrupt--;
	return;
      }
    } else if(!n) {
      xTrace0(system, TR_MAJOR_EVENTS, "dispatch: can't find any input");
      break;
    } else if(!mask) {
      printf("select returns a zeroed mask! ivecmask %#x, n is %d\n",
	     ivec_in_use_mask, n);
      break;
    } else {
      for(i=0;i<NUMSOCKETSICANUSE;i++){
	if(mask & (1 << i)) {
	  if (! ivec[i].handler) {
	    printf("Null handler for sock %d\n", i);
	  } else {
	    xTrace1(system, TR_MAJOR_EVENTS, "Calling handler for sock %d", i);
	    (*ivec[i].handler)(ivec[i].arg);
	    foundany ++;
	  }
	}
      }
    }
  }
  if(!foundany){
    xTrace4(system, TR_MAJOR_EVENTS,
      "unknown interrupt %d (mask %#x ivec %#x real %d) in dispatch\n", 
      interruptNo, mask, ivec_in_use_mask, findsocket());
  }
  inInterrupt--;
}

/********************************************
 *
 *  Clock Device
 *
 *********************************************/

struct itimerval i_value, i_zero;

#define handlerresulttype void
typedef handlerresulttype (*handlertype)();

onfault(h)
handlertype h;
{
  struct sigvec vec;

  vec.sv_mask         = 0;
  vec.sv_onstack      = 1;
  vec.sv_handler = h;
  sigvec(SIGINT, &vec, (struct sigvec *)0);
  sigvec(SIGSEGV, &vec, (struct sigvec *)0);
  sigvec(SIGBUS, &vec, (struct sigvec *)0);
}
  
int sig_int_handler();
void event_handler();

void
init_clock()
{
  errno = 0;

/*
  definehandler(SIGPIPE, SIG_IGN);
  definehandler(SIGINT, (handlertype) sig_int_handler);
  definehandler(SIGIO,  (handlertype) dispatch);
  definehandler(SIGURG,  (handlertype) dispatch);
*/

  /* start event processor */
  CreateProcess((Ptrfi)event_handler, 5 /*LWP_MAXPRIO-1*/, 1, 0);

  if (errno)
    perror("init_clock:");
  return;
}


/*
sig_int_handler()
{
  pod_exit(0);
}
*/


read_clock(msec)	/* returns the number of msec */
long	*msec;     	/* since sometime in late 1986 */
{
  struct  timeval   time;
  struct  timezone  zone;

  gettimeofday(&time, &zone);
  *msec = (time.tv_sec - 500000000)*1000 + (time.tv_usec / 1000);
  return(0);
}


definehandler(sig, handler)
int sig;
handlertype handler;
{
  struct sigvec lvec;
  pthread_t tid;
  int thr_status=0;
  int detach_state = 1;
  pthread_attr_t thr_attr;
  int *args;

  if (handler == SIG_IGN) {
    lvec.sv_mask = -1;
    lvec.sv_onstack = 1;
    lvec.sv_handler = SIG_IGN;
    sigvec(sig, &lvec, (struct sigvec *)NULL);
  } else {
    pthread_attr_init(&thr_attr);
    detach_state = 1;
    pthread_attr_setdetachstate(&thr_attr, &detach_state);
    pthread_attr_setprio(&thr_attr, THREAD_MAXPRIO);

    args = (int *)xMalloc(2*sizeof(int));
    args[0] = sig;
    args[1] = handler;

    thr_status=pthread_create(&tid, &thr_attr, (pthread_func_t)signal_handler,
			      (void *)args);
  }
}

void signal_handler(args)
int *args;
{
/*
  eventinfo_t sigmem;
  char *arg;
  int asz;
  pthread_t sender;
  int sigid = args[0];
  handlertype handler = (handlertype)args[1];

  agt_create(&sender, sigid, (char *)&sigmem);
  
  for (;;) {
    (void) msg_recv(&sender, &arg, &asz, 0, 0, INFINITY);

    pthread_mutex_lock(&master_monitor);
    (void) msg_reply(sender);

    /* printf("."); fflush(stdout);

    (handler)(sigid);

    /* printf("-"); fflush(stdout);

    pthread_mutex_unlock(&master_monitor);
  }
*/
}


int state;
int state_int;

void event_handler()
{
  /* --- Next sleep is to give other initialization process time to execute */
  xk_master_unlock();

  for (;;) {
    xk_master_lock();
    clock_ih();
    xk_master_unlock();
  }
}
