/*
**	$RCSfile: sysinfo.c,v $
**	$Filename: sysinfo.c $
**	$Revision: 1.0 $
**	$Date: 1996/08/20 15:35:37 $
**
**	sysinfo.library interface to sysmon.library features (version 1.0) 
**	
**	(C) Copyright 1995-1997 by Etienne Vogt <Etienne.Vogt@obspm.fr>
**	SysInfo API by Petri Nordlund <petrin@megabaud.fi>
*/

#include <exec/libraries.h>
#include <exec/memory.h>
#include <exec/alerts.h>
#include <exec/execbase.h>
#include <devices/timer.h>
#define __USE_SYSBASE
#include <proto/exec.h>
#include <proto/timer.h>
#include "/sysmon.h"
#include "/sysmon_protos.h"
#include "/sysmon_pragmas.h"
#include "sysinfo.h"

struct SysmonBase *SysmonBase = NULL;
struct Library *TimerBase = NULL;
struct timerequest timereq;

int  __saveds __asm __UserLibInit(register __a6 struct Library *libbase);
void __saveds __asm __UserLibCleanup(register __a6 struct Library *libbase);
static struct EClockVal subEClockVal(struct EClockVal e2, struct EClockVal e1);

int  __saveds __asm __UserLibInit(register __a6 struct Library *libbase)
{ int rc = 0;

  SysBase = *(struct ExecBase **)4;
  if (SysmonBase = (struct SysmonBase *)OpenLibrary("sysmon.library",1))
  { if (OpenDevice("timer.device",UNIT_ECLOCK,(struct IORequest *)&timereq,0) == 0)
    { TimerBase = (struct Library *)timereq.tr_node.io_Device;
    }
    else
    { CloseLibrary((struct Library *)SysmonBase);
      Alert(AT_Recovery|AG_OpenDev|AO_TimerDev);
      rc = 1;
    }
  }
  else rc = 1;

  return rc;
}

void __saveds __asm __UserLibCleanup(register __a6 struct Library *libbase)
{ if (TimerBase) CloseDevice((struct IORequest *)&timereq);
  if (SysmonBase) CloseLibrary((struct Library *)SysmonBase);
}

__saveds struct SysInfo *InitSysInfo(void)
{ struct SysInfo *si;

  if (si = AllocMem(sizeof(struct SysInfo), MEMF_PUBLIC | MEMF_CLEAR))
  { si->loadavg_type = LOADAVG_NONE;
    si->cpu_usage_implemented = CPU_USAGEF_TOTAL_IMPLEMENTED | CPU_USAGEF_TOTALCSW_IMPLEMENTED;
    si->task_cpu_usage_implemented = TASK_CPU_USAGEF_TOTAL_IMPLEMENTED | TASK_CPU_USAGEF_TOTALCSW_IMPLEMENTED;
  }

  return si;
}

__asm __saveds void FreeSysInfo(register __a0 struct SysInfo *si)
{ if (si) FreeMem(si, sizeof(struct SysInfo));
}

__asm __saveds void GetLoadAverage(register __a0 struct SysInfo *si, register __a1 struct SI_LoadAverage *la)
{
}

__asm __saveds LONG GetPid(register __a0 struct SysInfo *si)
{ return (LONG)FindTask(NULL);
}

__asm __saveds LONG GetPpid(register __a0 struct SysInfo *si)
{ return -1L;
}

__asm __saveds LONG GetPgrp(register __a0 struct SysInfo *si)
{ return -1L;
}

__asm __saveds LONG GetNice(register __a0 struct SysInfo *si, register __d0 LONG which, register __d1 LONG who)
{ si->errno = WHICH_EINVAL;
  return -1L;
}

__asm __saveds LONG SetNice(register __a0 struct SysInfo *si, register __d0 LONG which, register __d1 LONG who, register __d2 LONG nice)
{ si->errno = WHICH_EINVAL;
  return -1L;
}

__asm __saveds struct SI_Notify *AddNotify(register __a0 struct SysInfo *si, register __d0 WORD flags, register __d1 LONG safety_limit)
{ return NULL;
}

__asm __saveds void RemoveNotify(register __a0 struct SysInfo *si, register __a1 struct SI_Notify *notify)
{
}

__asm __saveds void GetCpuUsage(register __a0 struct SysInfo *si, register __a1 struct SI_CpuUsage *usage)
{ struct EClockVal uptime;
  ULONG clockrate;

  clockrate = ReadEClock(&uptime) >> 12;
  usage->total_used_cputime = (SysmonBase->sb_CPUTime.ev_hi << 20 | SysmonBase->sb_CPUTime.ev_lo >> 12) / clockrate;
  usage->total_elapsed_time = (uptime.ev_hi << 20 | uptime.ev_lo >> 12) / clockrate;
  usage->total_csw = SysBase->DispCount;
}

__asm __saveds LONG GetTaskCpuUsage(register __a0 struct SysInfo *si, register __a1 struct SI_TaskCpuUsage *usage, register __a2 struct Task *task)
{ struct TaskInfo *tinfo;
  struct EClockVal uptime, elapsed;
  ULONG clockrate;

  clockrate = ReadEClock(&uptime) >> 12;
  if (tinfo = smGetTaskInfo(task))
  { usage->total_used_cputime = tinfo->ti_CPUTime.ev_hi << 20 | tinfo->ti_CPUTime.ev_lo >> 12;
    usage->total_used_time_hz = clockrate;
    elapsed = subEClockVal(uptime, tinfo->ti_StartTime);
    usage->total_elapsed_time = (elapsed.ev_hi << 20 | elapsed.ev_lo >> 12) / clockrate;
    usage->total_csw = tinfo->ti_DispCount;
    return 0;
  }
  else return 1;
}

static __inline struct EClockVal subEClockVal(struct EClockVal e2, struct EClockVal e1)
{ BOOL carry = (e1.ev_lo > e2.ev_lo);

  e2.ev_lo -= e1.ev_lo;
  e2.ev_hi -= e1.ev_hi;
  if (carry) e2.ev_hi -= 1;
  return e2;
}
