/*---------------------------------------------
                 S I M P A C K
            Simulation Tool Package
        Copyright 1990, Paul A. Fishwick
---------------------------------------------*/

/* NOTE: This program is the SimPack equivalent
of an SMPL program by M. H. MacDougall, "Simulating
Computer Systems", MIT Press, 1987 */


#include "../queuing/queuing.h"

#define n0 6         /* no. class 0 tasks  */
#define n1 3         /* no. class 1 tasks  */
#define nt n0+n1     /* total no. of tasks */
#define nd 4         /* no. of disk units  */
#define qd 1         /* queued req. return */

#define BEGIN_TOUR 1
#define REQUEST_CPU 2
#define RELEASE_CPU 3
#define REQUEST_DISK 4
#define RELEASE_DISK 5

struct token
  {
    int cls;         /* task's class (& priority) */
    int un;          /* disk for current IO req.  */
    double ts;         /* tour start time stamp     */
  } task[nt+1];

TOKEN a_token;

int
  disk[nd+1],        /* disk facility descriptors */
  cpu,               /* cpu facility descriptor   */
  nts=500;           /* no. of tours to simulate  */

double
  tc[2]={10.0,5.0},  /* class 0,1 mean cpu times  */
  td=30.0, sd=2.5;   /* disk time mean, std. dev. */

main()
  {
    int icount,i,j,event,n[2]; double t,s[2],rn;
    struct token *p;

    n[0]=n[1]=0; s[0]=s[1]=0.0;
    for (i=1; i<=nt; i++) task[i].cls=(i>n0)? 1:0;
    init_simpack(LINKED);
    cpu=create_facility("CPU",1);
    for (i=1; i<=nd; i++) disk[i]=create_facility("disk",1);
    for (i=1; i<=nt; i++) {
     a_token.attr[0] = (float) i;
     schedule(BEGIN_TOUR,0.0,a_token);
    } /* end for */
    icount = 0;
    while (nts)
      {
        icount++;
        next_event(&event,&a_token);
        i = (int) a_token.attr[0];
        p = &task[i];
        switch(event)
          {
            case BEGIN_TOUR:  /* begin tour */
              a_token.attr[0] = (float) i;
              p->ts=sim_time(); schedule(REQUEST_CPU,0.0,a_token);
              update_arrivals();
              break;
            case REQUEST_CPU:  /* request cpu */
              j=p->cls;
              a_token.attr[0] = (float) i;
              if (preempt(cpu,a_token,j) == FREE) {
                rn = expntl(tc[j]);
                a_token.attr[0] = (float) i;
                schedule(RELEASE_CPU,(float) rn,a_token);
              }
              break;
            case RELEASE_CPU:  /* release cpu, select disk */
              a_token.attr[0] = (float) i;
              release(cpu,a_token); p->un=random(1,nd);
              schedule(REQUEST_DISK,0.0,a_token);
              break;
            case REQUEST_DISK:  /* request disk */
              a_token.attr[0] = (float) i;
              if (request(disk[p->un],a_token,0) == FREE) {
                rn = erlang(td,sd);
                a_token.attr[0] = (float) i;
                schedule(RELEASE_DISK,(float) rn ,a_token);
              }
              break;
            case RELEASE_DISK:  /* release disk, end tour */
              a_token.attr[0] = (float) i;
              release(disk[p->un],a_token); j=p->cls;
              t=sim_time(); s[j]+=t-p->ts; p->ts=t; n[j]++;
              update_completions();
              a_token.attr[0] = (float) i;
              schedule(BEGIN_TOUR,0.0,a_token); nts--;
              break;
          }
      }
    report_stats(); printf("\n\n");
    printf("class 0 tour time = %.2f\n",s[0]/n[0]);
    printf("class 1 tour time = %.2f\n",s[1]/n[1]);
  }



