/*-=-=-=-=-=-=-=-=-=-=-=- 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.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#if defined(LINUX_CFG)

#include <stdio.h>
#include <signal.h>
#include <varargs.h>
#include <setjmp.h>
#include <signal.h>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/prctl.h>

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

#include "../rci/firstAlloc.h"

extern int rciCpu;
extern int rciTaskId;
extern unsigned char *rciIOpage;

extern int rciMainTaskPid;
extern int rciIsOpen;
extern FILE *rciStdout;

long rciTraceOffset;	/* INIT (from param file?) */
char rciTraceBit;	/* INIT (from param file?) */

/* RCI is in kernel mode in Linux */
rciInKernelMode()
{
 return (0);

}

rciSignal(s)
int s;
{
	/* Just do a regular signal issue. Signal won't be delivered 
	   right away because control task has a higher priority */

	
  if (s <= 0 || s >= NSIG)
    { return (-1);
    }
  if (rciCpu == ARBITER_CPU)
    { 
      
      /* if (!rciInKernelMode())  Linux always in kernel mode 
	 { */
      
      /* MS Former code for reference only
	 { 
	 sigsetmask (sigblock(0) | sigmask(s)); 
	 }
	 kill (getpid(), s); 
	 }
	 else
	 { kill(rciMainTaskPid, s); 
	 }
      */
      /* MS In Linux, lets kill ourselves and our parent so we don't hang around
       */

      kill (getpid(), s); 
      kill(rciMainTaskPid, s); 
      exit(0);
      /*	} */
    }
  else
    { printf ("Fatal: rciSignal() called with rciCpu != ARBITER\n");
    exit (-1);
    }
  
  return (1);
}

rciPrintToTerminal(set)
int set;
{
	/* ignored under IRIX */
}

#define MAX_PMSG	512

extern char *rciPrintfBufp;

rciPrintf (va_alist)
va_dcl
{
	va_list ap;
	char *fmt;

	va_start(ap);
	fmt = va_arg(ap, char*);
	if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { vprintf (fmt, ap);
	 }
	else 
	 { 
	   vsprintf (rciPrintfBufp, fmt, ap);
	   rciPrintfBufp += strlen (rciPrintfBufp);
	 }
	va_end(ap);
}

rciKPrintf (va_alist)
va_dcl
{
	va_list ap;
	char *fmt;

	va_start(ap);
	fmt = va_arg(ap, char*);
	if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { vprintf (fmt, ap);
	 }
	else 
	 { vfprintf (rciStdout, fmt, ap);
	 }
	va_end(ap);
}

static jmp_buf env;
void
onBadAddr()
{

  longjmp (env, 1); 
  rciPrintf("on Bad Addr encountered\n");

}

rciBadAddr (address, size)
void *address;
int size;
{
	void (*oldOnSigbus)();
	void (*oldOnSigsegv)();

	int code = 0;

	if (size != 1 && size != 2 && size != 4)
	 { return (-1);
	 }

	oldOnSigbus  = signal (SIGBUS, onBadAddr);
	oldOnSigsegv = signal (SIGSEGV, onBadAddr);

	if (setjmp (env) != 0)
	 { code = 1;
	 }
	else
	 { char c;
	   int k;
	   for (k=0; k<size; k++)
	    { c = ((char*)address)[k];
	    }
	 }

	signal (SIGBUS, oldOnSigbus);
	signal (SIGSEGV, oldOnSigsegv);

	return (code);
}

struct timeval rciWallClock()
{
	/* use system clock */

	struct timeval tv;

	gettimeofday (&tv, (struct timezone*)0);
	return (tv);
}

rciSetTrace(c)
int c;
{
	if (!rciIsOpen || !rciTraceBit)
	 { return (-1);
	 }
	else
	 { *(rciIOpage + rciTraceOffset) |= rciTraceBit;
	   return (1);
	 }
}

rciClearTrace(c)
int c;
{
	if (!rciIsOpen || !rciTraceBit)
	 { return (-1);
	 }
	else
	 { *(rciIOpage + rciTraceOffset) &= ~rciTraceBit;
	   return (1);
	 }
}


/* Assumptions: rciMalloc pool per CPU, and &fad is lower than
   anything we are likely to allocate */
static FIRST_ALLOC_DESC fad;
static rciMallocInitDone;	/* safety check */

void *rciMallocInit (morecore, blkSize, pool, poolsize)
void *(*morecore)();
int blkSize;
void *pool;
int poolsize;
{
	/* Called by monitor initialization code to set up the
	   appropriate entry points and pool areas for rciMalloc().
	 */

	firstAllocInit (&fad, morecore, blkSize, pool, poolsize);	
	rciMallocInitDone = rciCpu;
}

void *rciMalloc (size)
int size;
{
	extern char *malloc();

	if (rciMallocInitDone != rciCpu)
	 { return (NULL);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return (malloc(size));
	 }
	else
	 { return ((char*)firstAlloc(&fad, size));
	 }
}

rciFree (mem)
void *mem;
{
	if (rciMallocInitDone != rciCpu)
	 { return (0);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return (free(mem));
	 }
	else
	 { return (firstFree (&fad, mem));
	 }
}

/* This function is used internally ... */

rciSignalAux (cpu, sig)
int cpu;
int sig;
{
	/* Not implemented on IRIX */
}

#else /* !defined(SGI_CFG) */

static int keepRanlibHappy;

#endif
