#include <sys/lock.h>
#include <sys/reent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <math.h>

#include "bool.h"
#include "test_setjmp.h"
#include "func_io.h"
#include "func_test_io.h"
#include "func_test_lock.h"
#include "func_integrity.h"
#include "thread_info.h"
#include "cpu_info.h"
#include "uncached_mask.h"
#include "bottles.h"

#include "workload.h"

#define verbose_none      0
#define verbose_low       1
#define verbose_medium    2
#define verbose_high      3
#define VERBOSE_SYSTEM    verbose_none
#define HAVE_SYSTEM       1

void init_thread  ();
void exit_thread  ();
#if (HAVE_SYSTEM != 0)
void init_system  ();
void exit_system  ();
#endif //HAVE_SYSTEM

//~~~~~[ global variable ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

__LOCK_INIT(static,system_lock);

#if (HAVE_SYSTEM != 0)
static volatile bool         system_init   = false;
#endif //HAVE_SYSTEM
static volatile unsigned int nb_thread_run = 0;

//=====[ main ]=================================================================
/*
 * All thread execute this routine
 * Initialize the thread and attribute a Workload at each thread
 */

int main()
{
  init_thread();

/*   test_integrity (); */
/*   test_setjmp(); */
/*   func_test_io(); */
/*   test_lock1(); */
/*   test_lock2(); */
/*   test_lock_recursive1(); */
/*   test_lock_recursive2(); */

  /*
   * Lunch thread with a Workload
   */
#if (VERBOSE_SYSTEM >= verbose_medium)
  printf("<main> : lunch workload\n");
#endif //VERBOSE_SYSTEM

  {
   int pid = (int)getpid();

   if (pid < NB_WORKLOAD)
     (*WorkLoad[pid])();
   else
     printf("<main> pid is %d but the number of function in the workload is %d\n",pid,(int)NB_WORKLOAD);
  }
  
#if (VERBOSE_SYSTEM >= verbose_medium)
  printf("<main> : exit workload\n");
#endif //VERBOSE_SYSTEM
  
  exit (0);
}

//-----[ init_thread ]----------------------------------------------------------
/*
 * Initialize all thread
 */

void init_thread()
{
  unsigned int pid;

  set_uncached_mask (0x80000000);
  
  __lock_init    (system_lock);

  // Test if is the first thread -> initialization of system
  __lock_acquire (system_lock);
  pid = nb_thread_run ++;
  __lock_release (system_lock);
  
  // Change parameters of thread
  //  * Identificator
  //  * Priority
  set_thread_id       (pid);
  set_thread_priority (0xF);

  // Initialize Reentrant structure
  _REENT_INIT_PTR(_REENT);

#if (HAVE_SYSTEM != 0)
  if (pid == 0)
    init_system();
  
  while (system_init == false);
#endif //HAVE_SYSTEM


  // Test if is the first thread -> initialization of system
  atexit (exit_thread);

  print((get_thread_id() << 16) | get_cpu_id());
  
#if (VERBOSE_SYSTEM >= verbose_low)
  printf("<init_thread> Thread[%d] executed on CPU[%d]\n",getpid(),get_cpu_id());
#endif //VERBOSE_SYSTEM
}

//-----[ exit_thread ]----------------------------------------------------------
/*
 * Free all ressource
 */

void exit_thread()
{
  bool last = false;

#if (VERBOSE_SYSTEM >= verbose_low)
  printf("<exit_thread> Thread[%d] is finish\n",getpid());
#endif //VERBOSE_SYSTEM
  
  __lock_acquire (system_lock);
  
  nb_thread_run --;
  last = (nb_thread_run == 0)?true:false;
  
  __lock_release (system_lock);

#if (HAVE_SYSTEM != 0)
  if (last == true)
    exit_system();
#endif //HAVE_SYSTEM

  quit(getpid());

  while(1);
}


#if (HAVE_SYSTEM != 0)
//-----[ init_system ]----------------------------------------------------------
/*
 * Initialize all system
 */

void init_system()
{
#if (VERBOSE_SYSTEM >= verbose_high)
  time_t * my_time = (time_t *) malloc (sizeof (time_t));

  if (my_time == NULL)
    {
      printf("<init_system> {error} malloc\n");
      exit(-1);
    }
  
  if (time(my_time) == ((time_t)-1))
    {
      printf("<init_system> {error} time\n");
      exit (-1);
    }
  
  printf("<init_system> System boot     - %s",ctime(my_time));

  free(my_time);
#else
#if (VERBOSE_SYSTEM >= verbose_low)
  printf("<init_system> System boot\n");
#endif //VERBOSE_SYSTEM
#endif //VERBOSE_SYSTEM

#if (VERBOSE_SYSTEM >= verbose_medium)
  printf("\n");
  printf("@     @    @@@@    @@@@@    @@@@@    @    @   @@@@@@    @@@@     \n");
  printf("@@   @@   @    @   @    @   @    @   @    @   @        @    @    \n");
  printf("@ @@@ @   @    @   @@@@@    @@@@@    @@@@@@   @@@@     @    @    \n");
  printf("@     @   @    @   @    @   @        @    @   @        @    @    \n");
  printf("@     @    @@@@    @    @   @        @    @   @@@@@@    @@@@     \n");
  printf("@     @utiple ORganization for a Processor HEterogenous and Open.\n");
  printf("\n");
#endif //VERBOSE_SYSTEM

  system_init = true;
}

//-----[ exit_system ]----------------------------------------------------------
/*
 * Free all ressource
 */

void exit_system()
{
#if (VERBOSE_SYSTEM >= verbose_high)
  time_t * my_time = (time_t *) malloc (sizeof (time_t));
  
  if (my_time == NULL)
    {
      printf("<exit_system> {error} malloc\n");
      exit(-1);
    }
  
  if (time(my_time) == ((time_t)-1))
    {
      printf("<exit_system> {error} time\n");
      exit (-1);
    }
  
  printf("<exit_system> System shutdown  - %s",ctime(my_time));

  free (my_time);
#else
#if (VERBOSE_SYSTEM >= verbose_medium)
  printf("<exit_system> System shutdown\n");
#endif //VERBOSE_SYSTEM
#endif //VERBOSE_SYSTEM
}
#endif //HAVE_SYSTEM
