Listing 4

// npx.cpp - Non-Preemptive eXecutive
//           Copyright 1990 by Cnapse
//           Written by: M. de Champlain

#include <stdio.h>
#include <stdlib.h>

#include "npx.hpp"

Task   *running;

// ---- base class StateQ -------------------
class StateQ {
Friend class ReadyQ;
    Task      *header;
    taskState  state;
public:
    StateQ(int nTasks, taskState st);
    void Insert(Task *thisTask);
    void Transfer(Task *thisTask);
    ~StateQ( );
};

inline StateQ::$tateQ(int nTasks, taskState st)
    {
    header = List_Allocate(nTasks, sizeof(Task));
    state = st;
    }

inline void StateQ::Insert(Task *thisTask)
    {
    thisTask->state = state;
    List_InsertTail(thisTask, header);
    }

inline void StateQ::Transfer(Task *thisTask)
    {
    thisTask->state = state;
    List_Remove(thisTask);
    List_InsertTail(thisTask, header);
    }

inline StateQ::~StateQ()
    {
    List_Free( header );
    }
// ---- derived class ReadyQ -------------------

class ReadyQ : StateQ {
public:
    ReadyQ() : StateQ(0, READY) {}
    void GetNextRunning(void);
};

inline void ReadyQ::GetNextRunning(void)
    {
    (running = List_RemoveHead(header))->state = RUNNING;
    }

StateQ *terminatedQ, *suspendedQ;
ReadyQ *readyQ;
Task *Task::Start(void)
    {
    if (stackBase = new word[stackSizeInBytes/2])
       {
       /*  establish new task's SP */
       sp = (reg)((word)stackBase + stackSizeInBytes);
       *--sp = (word) taskStartingAddress;
       --sp;                     /* push bp */
       parent = running;
       self = this;
       readyQ->Insert(this);
       return self;
      }
    else
      return 0;
    }
Task *Task::Self(void)
    {
    return self;
    }
Task *Task::Parent(void)
    {
    return parent;
    }
void Task::Schedule(void)
    {
    readyQ->GetNextRunning(); // assume at least one task is READY
    }
extern void ContextSwitch(void);
extern void RunNext(void);
reg *addrRunningTcbSp;

void Task::ReSchedule(void)
    {
    // save the address of the runningTcb's stack ptr for ContextSwitch.
    addrRunningTcbSp = &running->sp;
    // put the running task in the READY queue
    readyQ->Insert(running);
    Schedule();
    ContextSwitch();
    }
void Task::Terminate(Task *id)
    {
    if ( id->state != TERMINATED )
       {
       delete id->stackBase;
       terminatedQ->Transfer(id);
       delete id;
       if ( id == running )
          {
          Schedule();
          RunNext();
          // should never back here
          }
       }
    }
void Task::Suspend(Task *id)
    {
    if ( id->state != SUSPENDED )
       {
       suspendedQ->Transfer(id);
       if ( id == running )
          {
          // save address of the runningTcb's stack ptr for ContextSwitch.
          addrRunningTcbSp = &running->sp;
          Schedule();
          ContextSwitch();
          // will come back here after a Resume
          }
       }
    }
void Task::Resume(Task *id)
    {
    if ( id->state == SUSPENDED )
        readyQ->Transfer(id);
    }
extern void StartUpUserTasks(void);
main(void)
{
printf("Non-Preemptive executive, Copyright 1990 by Cnapse\n\n");
terminatedQ = new StateQ(10, TERMINATED );
suspendedQ  = new StateQ( 0, SUSPENDED );
readyQ      = new ReadyQ();

// Make StartUpUserTasks RUNNING
(new Task(StartUpUserTasks, 1024))->Start();
readyQ->GetNextRunning();
RunNext();
}