//-------------------------------------------------
//          TestSuite: GabageCollection
//-------------------------------------------------

#include "lcd.h"
#include "util.h"
#include "os_core.h"
#include "os_scheduler.h"
#include "os_memory.h"

#include <avr/interrupt.h>

#define DELAY 100

#define RUNS 400

#define DRIVER intHeap

uint8_t volatile minispace = 0;

PROGRAM(1, AUTOSTART) {
  lcd_clear();
  lcd_writeProgString(PSTR("Test overalloc"));
  ProcessID const miniProc = os_exec(3,1);
  while (!minispace);
  uint16_t const total = os_getUseSize(DRIVER);
  if (os_malloc(DRIVER,total)) {
    os_enterCriticalSection();
    lcd_clear();
    lcd_writeProgString(PSTR("Overalloc failure!"));
    for (;;);
  }
  uint8_t const defaultProcs = os_getNumberOfActiveProcs();
  lcd_clear();
  lcd_writeProgString(PSTR("Testing gc"));
  // let's start the actual test
  while (os_getNumberOfActiveProcs() < MAX_NUMBER_OF_PROCESSES) {
    os_exec(2,DEFAULT_PRIORITY);
  }
  uint16_t runs;
  uint16_t const totalRuns = RUNS;
  for (runs = 0; runs < totalRuns; runs++) {
    while (os_getNumberOfActiveProcs() == MAX_NUMBER_OF_PROCESSES);
    os_exec(2,DEFAULT_PRIORITY);
    delayMs(DELAY);
    lcd_drawBar((100*runs)/totalRuns);
    lcd_goto(2,6);
    lcd_writeDec(runs+1);
    lcd_writeChar('/');
    lcd_writeDec(totalRuns);
  }
  lcd_clear();
  lcd_writeProgString(PSTR("finalisation ..."));
  delayMs(5*DELAY);
  while (os_getNumberOfActiveProcs() != defaultProcs);
  lcd_clear();
  os_kill(miniProc);
  if (os_malloc(DRIVER,total)) {
    lcd_writeProgString(PSTR("Test complete"));
  } else {
    lcd_writeProgString(PSTR("Huge alloc fail!"));
  }
}

PROGRAM(2, DONTSTART) {
  // The number 4 is a heuristic. We expect the ram not to be that fragmented.
  uint16_t max = os_getUseSize(DRIVER)/(MAX_NUMBER_OF_PROCESSES - 3)/4;
  while (max) {
    uint16_t const sz = (max+1)/2;
    max -= sz;
    os_malloc(DRIVER, sz);
  }
}

PROGRAM(3, DONTSTART) {
  os_malloc(DRIVER,4);
  minispace = 1;
  for (;;);
}
