/*
    TMError.c, Copyright  (c) by George Fankhauser,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public Licence.
 
    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/

#include "TMError.h"


static void tmReservedInstructionError(ThreadId currentThread);
static void tmSignalInterruptError(ThreadId currentThread);
static void tmSignalEMT(ThreadId currentThread);

void tmInstallErrorHandlers(void)
{
  /* Vital for correct operations
   */
  tmSetExceptionHandler(SEND, syscallExceptionHandler);
  tmSetExceptionHandler(RECV, syscallExceptionHandler);
  tmSetExceptionHandler(ALARM, tmClockHandler);

  /* Error handling for faulting threads
   */
  tmSetExceptionHandler(RESERVEDINSTRUCTION, tmReservedInstructionError);
  tmSetExceptionHandler(INTERRUPTSIGNAL, tmSignalInterruptError);
#ifdef linux

  tmSetExceptionHandler(SIGUNUSED, tmSignalEMT);
#else

  tmSetExceptionHandler(SIGEMT, tmSignalEMT);
#endif
}


void tmError(ThreadId currentThread, char* errorString)
{
  Message msg;

  msg.id = TM_KILL;
  msg.from = TMTHREADID;
  msg.msg.tmKill.id = currentThread;

  ERROR(errorString);
  printRegisters();

  /* immediate in-kernel delivery without syscall
   * kSend does a schedule after the message arrived
   */
  kSend(TMTHREADID, &msg);
}

static void tmReservedInstructionError(ThreadId currentThread)
{
  tmError(currentThread, "reserved instruction");
}

static void tmSignalInterruptError(ThreadId currentThread)
{
  tmError(currentThread, "sig int, exiting...");
  exit(0);
}

// used in unix for a simple exit on stack underflow
// on native systems this is usually  a little more complex using
// exit code and an exit message on the stack...

static void tmSignalEMT(ThreadId currentThread)
{
  Message msg;

  msg.id = TM_KILL;
  msg.from = TMTHREADID;
  msg.msg.tmKill.id = currentThread;

  kSend(TMTHREADID, &msg);
}
