/*****************************************************************

    SystemIdler V1.0 (Idle counter module for TinyMeter 3.6)  by
    Tinic Urou in 1995, FreeWare, orginal code by Thomas Radtke.
    Use this at your own risk. Please leave me a mail if you are
    using this code in your programs:

	EMail: tinic@tinic.mayn.sub.de

    I modified the code from cpuload2. The routines to count the
    maximum  are  much  more  better I think, since they use the
    exact same  number  of  cycles  as  the  normal  idle  count
    routine.
    On a A4000/030, disabling the startup-sequence, you will now
    get  1%  usage.  With  all my tools I get 9-12% usage. These
    results should be correct.

    Bugs: None known.
    ŻŻŻŻ
    Invoking:
    ŻŻŻŻŻŻŻŻ
    init_idle(); to setup the idle task
    free_idle(); to remove the idle Task

    unsigned long idle;      is the actual idlecount
    unsigned long maximum;   is the maximum idlecount

    To get f.ex. the percentage of system usage simply use:

    __________________________________________________________

	extern unsigned long maximum,idle;

	showusage()
	{
	    int percent,n;

	    if(init_idle())
	    {
		for(n=0;n<25;n++)
		{
		    percent=(int)((idle*100)/maximum);
		    printf("%d percent free\n",percent);
		    Delay(50L);
		}
		free_idle();
	    }
	}

    ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ

    Used compiler:  gcc  2.7.0  with  libnix  1.0  Look  at  the
    makefile for the used options.

*******************************************************************/

#include <intuition/IntuitionBase.h>
#include <exec/nodes.h>
#include <exec/tasks.h>
#include <libraries/dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <stdlib.h>
#include <signal.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <clib/all_protos.h>

struct          Task *task2,*met;

BOOL            quit_setidle,
		quit_getidle,
		start_count=TRUE;

unsigned long   maximum,
		cnt,
		idle;

__saveds void getidle(void)
{
    struct          timeval updateval;
    struct MsgPort  *timerport;
    struct          timerequest *tr;
    struct          Task *met2;

    /* use "__geta4 getidle()" for DICE or SAS and remove geta4(); */

    met2=FindTask(NULL);

    if ((timerport=(struct MsgPort *)CreatePort (0,0)))
    {
	if ((tr=(struct timerequest *)CreateExtIO(timerport,sizeof(struct timerequest))))
	{
	    if ((OpenDevice (TIMERNAME,UNIT_MICROHZ,(struct IORequest *)tr,0))!=0)
	    {
		DeleteExtIO((struct IORequest *)tr);
		DeletePort(timerport);
		goto error;
	    }
	}
	else
	{
	    DeletePort(timerport);
	    goto error;
	}
    }
    else goto error;

    updateval.tv_secs =1;
    updateval.tv_micro=0;

    while((met2->tc_SigRecvd & SIGBREAKF_CTRL_D)==0)
    {
	/* signal setidle()-task, that we can start counting */

	start_count=FALSE;

	cnt=0;
	tr->tr_node.io_Command=TR_ADDREQUEST;
	tr->tr_time=updateval;
	DoIO((struct IORequest *)tr);
	idle=cnt;

	/* check if we have to setup maximum */
	if(maximum==0)
	{
	    maximum=idle;
	    Signal(met,SIGBREAKF_CTRL_D);
	}
    }

    CloseDevice((struct IORequest *)tr);
    DeleteExtIO((struct IORequest *)tr);
    DeletePort(timerport);

    error:

    quit_getidle=FALSE;
    start_count =FALSE;

    idle   =100000;    /* to avoid divisions by zero from the application */
    maximum=100000;

    /* Do nothing and wait for DeleteTask() */

    Wait(0L);

}

__saveds void setidle(void)
{
    char *taskname_1 = "CPU_GET";
    struct Task *task;

    /* use "__geta4 setidle()" for DICE or SAS and remove geta4(); */

    if(met=FindTask(NULL))
    if(task=(struct Task *)CreateTask(taskname_1,127,getidle,4096))
    {
	quit_getidle=TRUE;

	/* Wait for beginning. Allocating a timerequest may take a while */

	while (start_count) cnt=0;                                         

	/* maximum counter */
	while ((met->tc_SigRecvd & SIGBREAKF_CTRL_D)==0) cnt++;
	SetSignal(0,SIGBREAKF_CTRL_D);

	met->tc_Node.ln_Pri=-127;

	/* idle counter */
	while ((met->tc_SigRecvd & SIGBREAKF_CTRL_D)==0) cnt++;

	met->tc_Node.ln_Pri=0;

	Signal(task,SIGBREAKF_CTRL_D);
	while(quit_getidle) cnt=0;

	/* remove getidle()-task */

	Forbid();
	DeleteTask(task);
	Permit();
    }

    idle   =100000;    /* to avoid divisions by zero from the       */
    maximum=100000;    /* application, if creation of task failed.  */

    quit_setidle=FALSE;
    Wait(0L);
}

struct Task *init_idle(void)
{
    char *taskname_2 = "CPU_SET";
    if( task2=(struct Task *)CreateTask(taskname_2,126,setidle,4096))
    {
	Delay(50L); /* To avoid the use of idle and maximum before they're initialized */
    }
    return(task2);
}

void free_idle(void)
{
    quit_setidle=TRUE;
    Signal(task2,SIGBREAKF_CTRL_D);
    while(quit_setidle) Delay(10L);

    /* remove setidle()-task */

    Forbid();
    DeleteTask(task2);
    Permit();
}
