/*
    LWTest.c, Copyright  (c) by Claudio Jeker,
    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.
*/
/*
	
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/ThreadsLight/LWTest.c,v $
	Author(s):             Claudio Jeker
	Affiliation:           ETH Zuerich, TIK
	Version:               $Revision: 2922 $
	Creation Date:         
	Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $      by: $Author: baderma $
	
*/

/* test following functions:
	lwInit(); lwDestroy(); lwMsgSend(); lwMsgRecv(); 
	lwStart(); lwKill(); lwExit(); lwYield();
	THIS IS FOR TESTING PURPOSES ONLY SO IT'S NOT NICE PROGRAMMED. --cjeker
*/

#include "LWThreads.h"
#include "Support.h"
#include "Syscall.h"

ThreadId lwThreadId;
LWPool lw;
extern int BC;

void lwtest1()
{
  printf("TEST1: lwInit -> lwDestroy\n");

  if ( lwInit(&lw, 16) == LW_OK )
  {
    printf("\t%s: OK\n", "lwInit");
  }
  else
  {
    printf("\t%s: FAILED\n", "lwInit");
    return ;
  }

  printf("\t%s: testing\n", "lwDestroy");
  lwDestroy(lw) ;
  printf("\t%s: FAILED\n", "lwDestroy");
}

void test2main(LWPool lw, ThreadArg a)
{
  printf("\tchild is running\n\t  ThreadArg = %i\n", (int)a);

  printf("\tdoing yield\n");
  lwYield(lw);
  printf("\tyield done back in child thread\n");

  lwDestroy(lw) ;
  printf("\t%s: FAILED\n", "lwDestroy");
}

void lwtest2()
{
  ThreadId id;

  printf("TEST2: lwInit -> lwStart -> lwYield -> lwDestroy\n");

  if ( lwInit(&lw, 16) == LW_OK )
  {
    printf("\t%s: OK\n", "lwInit");
  }
  else
  {
    printf("\t%s: FAILED\n", "lwInit");
    return ;
  }

  if ( lwStart(lw, &id, test2main, (ThreadArg) 6, 0) == LW_OK )
  {
    printf("\t%s: OK ID %li\n", "lwStart", id);
  }
  else
  {
    printf("\t%s: FAILED\n", "lwStart");
    return ;
  }

  printf("\tparent is running\n");
  lwYield(lw);
  while(1)
    printf("\tparent is running but shouldn't\n");
}

void test3main(LWPool lw, ThreadId *m)
{
  ThreadId mySelf = *m, from;
  Message msg;
  int i = 0;

  printf("\t\tThread %li: waiting for message\n", mySelf);
  lwMsgRecv(lw, &from, 0, &msg, 0);
  printf("\t\tThread %li: message %i recieved\n", mySelf, (int)msg.msg.userMsg.p1);
  for( i = 0; i < 5; i++ )
  {
    printf("\t\tThread %li: running the %i time\n", mySelf, i);
    lwYield(lw);
  }
  printf("\t\tThread %li: finished, sending message to parent\n", mySelf);
  lwMsgSend(lw, from /* parent */, &msg);
  printf("\t\tThread %li: Message sent\n", mySelf);
}


void lwtest3()
{
  ThreadId id[16], from;
  Message msg;
  int i;

  printf("TEST3: lwInit -> lwStart 16 Threads -> lwDestroy\n");

  if ( lwInit(&lw, 16) == LW_OK )
  {
    printf("%s: OK\n", "lwInit");
  }
  else
  {
    printf("%s: FAILD\n", "lwInit");
    return ;
  }

  for ( i=0; i<15; i++)
  {
    if ( lwStart(lw, &id[i], (LWThreadMainFunction)test3main, (ThreadArg)&(id[i]), 0) == LW_OK )
    {
      printf("\tMain Thread: %s OK ID %li\n", "lwStart", id[i]);
    }
    else
    {
      printf("\tMain Thread: %s FAILED\n", "lwStart");
    }
  }
  for ( i = 14; i >= 0; i--)
  {
    printf("\tMain thread: sending message to Thread %li\n", id[i]);
    msg.msg.userMsg.p1 = (void *)i;
    if( lwMsgSend(lw, id[i] /* child */, &msg) == LW_OK )
      printf("\tMain thread: lwMsgSend OK\n");
    else
      printf("\tMain thread: lwMsgSend FAILED\n");
  }
  printf("\tMain thread: all Messages sent\n");

  printf("\tMain thread: waiting for message\n");
  lwMsgRecv(lw, &from, 0, &msg, 0);
  printf("\tMain thread: message recieved, goodby\n");

  lwDestroy(lw) ;
  printf("\t%s: FAILD\n", "lwDestroy");
}

void test4main(LWPool lw, ThreadId *m)
{
  ThreadId mySelf = *m, from;
  Message msg;

  printf("\t\tThread %li: waiting for message\n", mySelf);
  lwMsgRecv(lw, &from, 0, &msg, 0);
  printf("\t\tThread %li: message recieved\n", mySelf);

  printf("\t\tThread %li: calling lwExit()\n", mySelf);
  lwExit(lw);
  printf("\t\tThread %li: lwExit() failed\n", mySelf);

}

void lwtest4()
{
  ThreadId id[16];
  Message msg;
  int i;

  printf("TEST4: lwInit -> lwStart 16 Threads -> lwKill / lwExit\n");

  if ( lwInit(&lw, 16) == LW_OK )
  {
    printf("%s: OK\n", "lwInit");
  }
  else
  {
    printf("%s: FAILD\n", "lwInit");
    return ;
  }

  for ( i=0; i<16; i++)
  {
    if ( lwStart(lw, &(id[i]), (LWThreadMainFunction) test4main, (ThreadArg) &(id[i]), 0) == LW_OK )
    {
      printf("\tMain Thread: %s OK ID %li\n", "lwStart", id[i]);
    }
    else
    {
      printf("\tMain Thread: %s FAILED\n", "lwStart");
    }
  }
  for ( i = 0; i < 8; i++)
  {
    printf("\tMain thread: killing Thread %li\n", id[i]);
    if( lwKill(lw, id[i]) == LW_OK )
      printf("\tMain thread: lwKill OK\n");
    else
      printf("\tMain thread: lwKill FAILED\n");
  }
  for ( i = 14; i >= 0; i--)
  {
    printf("\tMain thread: sending message to Thread %li\n", id[i]);
    if( lwMsgSend(lw, id[i] /* parent */, &msg) == LW_OK )
      printf("\tMain thread: lwMsgSend OK\n");
    else
      printf("\tMain thread: lwMsgSend FAILED\n");
  }
  printf("\tMain thread: all Messages sent\n");

  printf("\tMain thread: doing a exit\n");
  lwExit(lw);
  printf("\tMain thread: lwExit FAILED\n");

  lwDestroy(lw) ;
  printf("\t%s: FAILD\n", "lwDestroy");
}

static void test5main(LWPool lw, ThreadId *m)
{
  ThreadId from;
  Message msg;
  unsigned long pat[10] = { 0xDEADBEEF, 0x01010101, 0x02020202, 0x03030303, 0x04040404, 0x05050505, 0x06060606, 0x07070707, 0x08080808, 0x09090909 };

  for (;;)
  {
    printf("printf test:\t%#lX %#lX %#lX %#lX %#lX\n\t\t%#lX %#lX %#lX %#lX %#lX\n",
           pat[0], pat[1], pat[2], pat[3], pat[4], pat[5], pat[6], pat[7], pat[8], pat[9] );
    lwMsgRecv(lw, &from, 0, &msg, 0 );
    lwMsgSend(lw, from, &msg);
  }
}

void lwtest5()
{
  ThreadId id, from;
  Message msg;
  int i;

  printf("TEST4: lwInit -> lwStart 16 Threads -> lwKill / lwExit\n");

  if ( lwInit(&lw, 16) == LW_OK )
  {
    printf("%s: OK\n", "lwInit");
  }
  else
  {
    printf("%s: FAILD\n", "lwInit");
    return ;
  }
  if ( lwStart(lw, &id, (LWThreadMainFunction) test5main, (ThreadArg) &id, 0) == LW_OK )
  {
    printf("\tMain Thread: %s OK ID %li\n", "lwStart", id);
  }
  else
  {
    printf("\tMain Thread: %s FAILED\n", "lwStart");
  }

  for ( i = 0; i < 16 ; i++ )
  {
    lwMsgSend(lw, id, &msg);
    lwMsgRecv(lw, &from, 0, &msg, 0 );
  }
  lwDestroy(lw);
}


void lwtestmain()
{
  ThreadId testId = ANY;
  Message dummy;


  tmMsgRecv(&testId, ANYMSGTYPE, &dummy, INFINITY);
  printf("starting TEST1\n");
  if ( tmStart(&testId, lwtest1, 0, "test 1") != TM_STARTOK )
  {
    printf("error while starting testing thread\n");
    return;
  }
  printf("waiting for TEST1\n");
  tmMsgRecv(&testId, ANYMSGTYPE, &dummy, INFINITY);
  printf("starting TEST2\n");
  if ( tmStart(&testId, lwtest2, 0, "test 2") != TM_STARTOK )
  {
    printf("error while starting testing thread\n");
    return;
  }
  printf("waiting for TEST2\n");
  tmMsgRecv(&testId, ANYMSGTYPE, &dummy, INFINITY);
  printf("starting TEST3\n");
  if ( tmStart(&testId, lwtest3, 0, "test 3") != TM_STARTOK )
  {
    printf("error while starting testing thread\n");
    return;
  }
  printf("waiting for TEST3\n");
  tmMsgRecv(&testId, ANYMSGTYPE, &dummy, INFINITY);
  printf("starting TEST4\n");
  if ( tmStart(&testId, lwtest4, 0, "test 4") != TM_STARTOK )
  {
    printf("error while starting testing thread\n");
    return;
  }
  printf("waiting for TEST4\n");
  tmMsgRecv(&testId, ANYMSGTYPE, &dummy, INFINITY);
  printf("starting TEST5\n");
  if ( tmStart(&testId, lwtest5, 0, "test 5") != TM_STARTOK )
  {
    printf("error while starting testing thread\n");
    return;
  }
  printf("waiting for TEST5\n");
  tmMsgRecv(&testId, ANYMSGTYPE, &dummy, INFINITY);

}
