#define ExecutiveG
#include "Executive.h"
/* some constants which comply with SYSTEM.def and general Modula-2 */
#define NULL (void *)0
#define TRUE (1==1)
#define FALSE (1==0)
#define STRING char *, const unsigned int
#define VARSTRING char *, const unsigned int
#define VARPROCESS void**
#define PARAMS(X) X
typedef enum {On, Off} OnOrOff;
/*
* start of interface with microkernel functions
*/
extern OnOrOff SYSTEM_TurnInterrupts (OnOrOff);
extern void SYSTEM_IOTRANSFER (VARPROCESS, VARPROCESS, int);
extern void SYSTEM_TRANSFER (VARPROCESS old, PROCESS new);
extern void SYSTEM_NEWPROCESS (void *, void *, unsigned int, VARPROCESS);
extern void SysStorage_ALLOCATE (void **, const int);
extern void SysStorage_DEALLOCATE (void *, const int);
extern void Debug_Halt (STRING, const unsigned int, STRING);
extern void Debug_DebugString (STRING);
extern void StrLib_StrCopy (STRING, VARSTRING);
extern void NumberIO_CardToStr (int, int, VARSTRING);
/*
* end of interface with microkernel
*/
/*
* forward declarations ignore (C compiler fodder)
*/
static void Reschedule PARAMS ((void));
static Descriptor *SubFromSemaphoreTop PARAMS ((Descriptor **Head));
static Descriptor *NextReady PARAMS ((void));
static void DisplayProcess PARAMS ((Descriptor *p));
static void WriteNSpaces PARAMS ((unsigned int n));
static void AddToExists PARAMS ((Descriptor *Item));
static void AddToSemaphore PARAMS ((Descriptor **Head, Descriptor *Item));
static Descriptor *SubFromSemaphoreTop PARAMS ((Descriptor **Head));
static void AddToSemaphoreExists PARAMS ((Semaphore *Item));
static void AddToReady PARAMS ((Descriptor *Item));
static void SubFromReady PARAMS ((Descriptor *Item));
static void SubFromSemaphore PARAMS ((Descriptor **Head, Descriptor *Item));
static void InitQueue PARAMS ((struct DesQueue *q));
static Descriptor *ExistsQueue; /* List of existing processes */
static Descriptor *RunQueue[3]; /* List of runnable processes */
static Descriptor *CurrentProcess;
static Semaphore *AllSemaphores; /* List of all semaphores */
static Descriptor *IdleProcess; /* Idle process always runnable */
/*
* simple utility function to help with converting M2->c conversion and string handling.
*/
static int strlen (char *s)
{
int i=0;
while (s[i] != (char)0) {
i++;
}
return( i );
}
/*
* Assert -
*/
static void Assert (BOOLEAN c,
char *file, unsigned int file_high, unsigned int line)
{
char db[81];
if (c)
return;
Debug_DebugString("IdleProcess = ", 13);
NumberIO_CardToStr((unsigned int)IdleProcess, 0, db, 80);
Debug_DebugString(db, 80);
Debug_DebugString("\\n", 2);
Debug_DebugString("Vols = ", 8);
NumberIO_CardToStr((unsigned int)IdleProcess->Volatiles, 0, db, 80);
Debug_DebugString(db, 80);
Debug_DebugString("\\n", 2);
Executive_Ps();
Debug_Halt("Assert failed", 13, line, file, file_high);
}
/*
* InitProcess - initializes a process which is held in the suspended
* state. When the process is resumed it will start executing
* procedure, p. The process has a maximum stack size of,
* StackSize, bytes and its textual name is, Name.
* The StackSize should be at least 5000 bytes.
*/
Descriptor *Executive_InitProcess (void (*p)(void), unsigned int StackSize,
char *Name, const int Name_High)
{
Descriptor *d;
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
SysStorage_ALLOCATE((void **)&d, sizeof(Descriptor));
d->Size = StackSize;
SysStorage_ALLOCATE((void **)&d->Start, StackSize);
/* allocate space for this processes stack */
SYSTEM_NEWPROCESS(p, d->Start, StackSize, &d->Volatiles); /* create volatiles */
InitQueue(&d->ReadyQ); /* not on the ready queue as suspended */
AddToExists(d); /* add process to the exists queue */
InitQueue(&d->SemaphoreQ); /* not on a semaphore queue yet */
d->Which = NULL; /* not on a semaphore queue yet */
StrLib_StrCopy(Name, Name_High, (char *)&d->RunName, MaxCharsInName);
/* copy name into descriptor for debugging */
d->Status = Suspended; /* this process will be suspended */
d->RunPriority = lo; /* all processes start off at lo priority */
d->Debugged = FALSE; /* no need to debug deadlock yet! */
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
return d; /* and return a descriptor to the caller */
}
/*
* Resume - resumes a suspended process. If all is successful then the process, p,
* is returned. If it fails then NIL is returned.
*/
void *Executive_Resume (Descriptor *d)
{
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
if (d->Status != Suspended) {
/* we are trying to Resume a process which is */
Debug_DebugString("trying to resume a process which is not suspended", 4
return NULL; /* not held in a Suspended state - error */
}
/* legal state transition */
d->Status = Runnable; /* change status */
AddToReady(d); /* add to run queue */
RunQueue[d->RunPriority] = d; /* make d at top of q */
Reschedule(); /* check whether this process has a higher run priority */
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
return d;
}
/*
* Suspend - suspend the calling process.
* The process can only continue running if another process
* Resumes it.
*/
void Executive_Suspend(void)
{
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
CurrentProcess->Status = Suspended;
SubFromReady(CurrentProcess);
Reschedule();
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
}
/*
* InitSemaphore - creates a semaphore whose initial value is, v, and
* whose name is, Name.
*/
Semaphore *Executive_InitSemaphore (unsigned int v,
char *Name, const int Name_HIGH)
{
Semaphore *s;
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
SysStorage_ALLOCATE((void **)&s, sizeof(Semaphore));
s->Value = v; /* initial value of semaphore */
StrLib_StrCopy(Name, Name_HIGH, (char *)&s->SemName, MaxCharsInName);
/* save the name for future debugging */
s->Who = NULL; /* no one waiting on this semaphore yet */
AddToSemaphoreExists(s); /* add semaphore to exists list */
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
return s;
}
/*
* Wait - performs dijkstra’s P operation on a semaphore.
* A process which calls this procedure will
* wait until the value of the semaphore is > 0
* and then it will decrement this value.
*/
void Executive_Wait (Semaphore *s)
{
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
if (s->Value > 0)
s->Value--;
else {
SubFromReady(CurrentProcess); /* remove from run q */
AddToSemaphore((Descriptor **)&s->Who, CurrentProcess);
/* add to semaphore q */
CurrentProcess->Status = WaitOnSem; /* set new status */
CurrentProcess->Which = s; /* debugging aid */
Reschedule(); /* find next process */
}
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
}
/*
* Signal - performs dijkstra’s V operation on a semaphore.
* A process which calls the procedure will increment
* the semaphores value.
*/
void Executive_Signal (Semaphore *s)
{
OnOrOff ToOldState;
Descriptor *d;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
if (s->Who == NULL) /* no process waiting */
s->Value++;
else {
d = SubFromSemaphoreTop(&s->Who); /* remove process from semaphore q */
d->Which = NULL; /* no longer waiting on semaphore */
d->Status = Runnable; /* set new status */
AddToReady(d); /* add process to the run queue */
/* find out whether there is a */
/* higher priority to run. */
Reschedule();
}
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
}
/*
* WaitForIO - waits for an interrupt to occur on vector, VectorNo.
*/
void Executive_WaitForIO (unsigned int VectorNo)
{
Descriptor *Calling;
PROCESS Next;
OnOrOff ToOldState;
Descriptor *WITH;
ToOldState = SYSTEM_TurnInterrupts(Off);
SubFromReady(CurrentProcess); /* remove process from run queue */
/*
alter run priority to hi as all processes waiting for an interrupt
are scheduled to run at the highest priority.
*/
CurrentProcess->Status = WaitOnInt; /* it will be blocked waiting for an interrupt. */
CurrentProcess->RunPriority = hi; /* this (hopefully) allows it to run as soon as */
/* the interrupt occurs. */
Calling = CurrentProcess; /* process which called WaitForIO */
CurrentProcess = NextReady(); /* find next process to run while we wait */
Next = CurrentProcess->Volatiles;
/*
This is quite complicated. We transfer control to the next process saving
our volatile environment into the Calling process descriptor volatiles.
When an interrupt occurs the calling process will be resumed and the
interrupted process volatiles will be placed into Next.
*/
SYSTEM_IOTRANSFER(&Calling->Volatiles, &Next, VectorNo);
/*
At this point the interrupt has just occurred and the volatiles of
the interrupted process are in Next. Next is the current process
and so we must save them before picking up the Calling descriptor.
*/
CurrentProcess->Volatiles = Next; /* carefully stored away */
CurrentProcess = Calling; /* update CurrentProcess */
CurrentProcess->Status = Runnable; /* add to run queue */
AddToReady(CurrentProcess);
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
}
/*
* Ps - displays a process list together with relevant their status.
*/
void Executive_Ps(void)
{
OnOrOff ToOldState;
Descriptor *p;
Semaphore *s;
char a[6];
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
p = ExistsQueue;
if (p != NULL) {
do {
DisplayProcess(p);
p = p->ExistsQ.Right;
} while (p != ExistsQueue);
}
s = AllSemaphores;
if (s != NULL) {
do {
Debug_DebugString(s->SemName, MaxCharsInName);
WriteNSpaces(MaxCharsInName - StrLib_StrLen(s->SemName, MaxCharsInName));
NumberIO_CardToStr(s->Value, 0, a, 5);
Debug_DebugString(a, 5);
Debug_DebugString("\\n", 1);
s = s->ExistsQ.Right;
} while (s != AllSemaphores);
}
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
}
/*
* WriteNSpaces - writes, n, spaces.
*/
static void WriteNSpaces(unsigned int n)
{
while (n > 0) {
Debug_DebugString(" ", 1);
n--;
}
}
/*
* DisplayProcess - displays the process, p, together with its status.
*/
static void DisplayProcess(Descriptor *p)
{
char a[5];
Debug_DebugString(p->RunName, MaxCharsInName);
WriteNSpaces(MaxCharsInName - StrLib_StrLen(p->RunName, MaxCharsInName));
switch (p->RunPriority) {
case idle:
Debug_DebugString(" idle ", 5);
break;
case lo:
Debug_DebugString(" lo ", 5);
break;
case hi:
Debug_DebugString(" hi ", 5);
break;
default:
break;
}
switch (p->Status) {
case Runnable:
Debug_DebugString("runnable ", 8);
break;
case Suspended:
Debug_DebugString("suspended", 8);
break;
case WaitOnSem:
Debug_DebugString("waitonsem (", 12);
Debug_DebugString(p->Which->SemName, MaxCharsInName);
Debug_DebugString(")", 0);
break;
case WaitOnInt:
Debug_DebugString("waitonint", 8);
break;
default:
break;
}
Debug_DebugString(" Stack usage (", 14);
if (p->Size == 0) {
Debug_DebugString(" 0%)\\n", 6);
return;
}
NumberIO_CardToStr(((unsigned int)p->Volatiles -
(unsigned int)p->Start) * 100 / p->Size, 3,
a, 4);
Debug_DebugString(a, 4);
Debug_DebugString("%)\\n", 3);
}
/*
* GetCurrentProcess - returns the descriptor of the current running
* process.
*/
Descriptor *Executive_GetCurrentProcess (void)
{
OnOrOff ToOldState;
Descriptor *p;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
p = CurrentProcess;
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
return p;
}
/*
* RotateRunQueue - rotates the process run queue.
*/
void Executive_RotateRunQueue (void)
{
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off); /* disable interrupts */
/* we only need to rotate the lo priority processes as:
idle - should only have one process (the idle process)
hi - are the device drivers which most of the time are performing
WaitForIO
*/
if (RunQueue[(int)lo] != NULL) {
RunQueue[(int)lo] = RunQueue[(int)lo]->ReadyQ.Right;
}
ToOldState = SYSTEM_TurnInterrupts(ToOldState); /* restore interrupts */
}
/*
* ProcessName - displays the name of process, d, through
* DebugString.
*/
void Executive_ProcessName (Descriptor *d)
{
Debug_DebugString(d->RunName, MaxCharsInName);
}
/*
* DebugProcess -
*/
void Executive_DebugProcess (Descriptor *d)
{
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(Off);
if (d->Status == WaitOnSem) {
Debug_DebugString("debugging process (", 18);
Debug_DebugString(d->RunName, MaxCharsInName);
Debug_DebugString(") was waiting on semaphore (", 27);
Debug_DebugString(d->Which->SemName, MaxCharsInName);
Debug_DebugString(")\\n", 2);
SubFromSemaphore(&d->Which->Who, d);
AddToReady(d);
d->Status = Runnable;
d->Debugged = TRUE;
Reschedule();
} else {
Debug_DebugString("can only debug deadlocked processes (", 36);
Debug_DebugString(d->RunName, MaxCharsInName);
Debug_DebugString(") which are waiting on a semaphore\\n", 35);
}
ToOldState = SYSTEM_TurnInterrupts(ToOldState);
}
/*
* CheckDebugged - checks to see whether the debugged flag has
* been set by the debugger.
* TRUE is returned if the process was debugged.
* FALSE is returned if the process was not debugged.
*/
static BOOLEAN CheckDebugged(void)
{
if (!CurrentProcess->Debugged)
return FALSE;
/*
You will see this comment after you have enabled a
deadlocked process to continue via the gdb command:
print Executive_DebugProcess(d)
debugger caused deadlocked process to continue
*/
gdb_breakpoint();
CurrentProcess->Debugged = FALSE;
SubFromReady(CurrentProcess);
AddToSemaphore(&CurrentProcess->Which->Who, CurrentProcess);
CurrentProcess->Status = WaitOnSem;
return TRUE;
}
/*
* ScheduleProcess - finds the highest priority Runnable process and
* then transfers control to it.
*/
static void ScheduleProcess(void)
{
Descriptor *From, *Highest;
Highest = NextReady();
/* rotate ready Q to ensure fairness */
RunQueue[Highest->RunPriority] = Highest->ReadyQ.Right;
/* no need to transfer if Highest=CurrentProcess */
if (Highest == CurrentProcess)
return;
From = CurrentProcess;
/* alter CurrentProcess before we TRANSFER */
CurrentProcess = Highest;
SYSTEM_TRANSFER(&From->Volatiles, Highest->Volatiles);
}
/*
Reschedule - reschedules to the highest runnable process.
*/
static void Reschedule(void)
{
/*
* the repeat loop allows us to debug a process even when it is
* technically waiting on a semaphore. We run the process into
* a breakpoint and then back into this schedule routine.
* This is really useful when trying to find out why processes have
* deadlocked.
*/
do {
ScheduleProcess();
} while (CheckDebugged());
}
/*
* NextReady - returns the highest priority Runnable process.
*/
static Descriptor *NextReady(void)
{
Descriptor *Highest;
Priority Pri;
Highest = NULL;
for (Pri = idle; Pri <= hi; Pri = Pri + 1) {
if (RunQueue[(int)Pri] != NULL)
Highest = RunQueue[(int)Pri];
}
Assert(Highest != NULL, __FILE__, strlen(__FILE__), __LINE__);
return Highest;
}
/*
* AddToExists - adds item, Item, to the exists queue.
*/
static void AddToExists (Descriptor *Item)
{
if (ExistsQueue == NULL) {
ExistsQueue = Item; /* Head is empty therefore make */
Item->ExistsQ.Left = Item; /* Item the only entry on this */
Item->ExistsQ.Right = Item; /* queue. */
} else {
Item->ExistsQ.Right = ExistsQueue; /* Add Item to the end of queue */
Item->ExistsQ.Left = ExistsQueue->ExistsQ.Left;
ExistsQueue->ExistsQ.Left->ExistsQ.Right = Item;
ExistsQueue->ExistsQ.Left = Item;
}
}
/*
* AddToSemaphore - adds item, Item, to the semaphore queue defined by Head.
*/
static void AddToSemaphore(Descriptor **Head, Descriptor *Item)
{
if (*Head == NULL) {
*Head = Item; /* Head is empty therefore make */
Item->SemaphoreQ.Left = Item; /* Item the only entry on this */
Item->SemaphoreQ.Right = Item; /* queue. */
return;
} else {
Item->SemaphoreQ.Right = *Head; /* Add Item to the end of queue */
Item->SemaphoreQ.Left = (*Head)->SemaphoreQ.Left;
(*Head)->SemaphoreQ.Left->SemaphoreQ.Right = Item;
(*Head)->SemaphoreQ.Left = Item;
}
}
/*
* AddToSemaphoreExists - adds item, Item, to the semaphore exists queue.
*/
static void AddToSemaphoreExists (Semaphore *Item)
{
if (AllSemaphores == NULL) {
AllSemaphores = Item; /* Head is empty therefore make */
Item->ExistsQ.Left = Item; /* Item the only entry on this */
Item->ExistsQ.Right = Item; /* queue. */
} else {
Item->ExistsQ.Right = AllSemaphores; /* Add Item to the end of queue */
Item->ExistsQ.Left = AllSemaphores->ExistsQ.Left;
AllSemaphores->ExistsQ.Left->ExistsQ.Right = Item;
AllSemaphores->ExistsQ.Left = Item;
}
}
/*
* AddToReadyQ - adds item, Item, to the ready queue defined by Head.
*/
static void AddToReadyQ(Descriptor **Head, Descriptor *Item)
{
if (*Head == NULL) {
*Head = Item; /* Head is empty therefore make */
Item->ReadyQ.Left = Item; /* Item the only entry on this */
Item->ReadyQ.Right = Item; /* queue. */
} else {
Item->ReadyQ.Right = *Head; /* Add Item to the end of queue */
Item->ReadyQ.Left = (*Head)->ReadyQ.Left;
(*Head)->ReadyQ.Left->ReadyQ.Right = Item;
(*Head)->ReadyQ.Left = Item;
}
}
/*
* AddToReady - adds item, Item, to the ready queue.
*/
static void AddToReady (Descriptor *Item)
{
AddToReadyQ(&RunQueue[Item->RunPriority], Item);
}
/*
* SubFromReadyQ - removes a process, Item, from a queue, Head.
*/
static void SubFromReadyQ (Descriptor **Head, Descriptor *Item)
{
if ((Item->ReadyQ.Right == *Head) && (Item == *Head)) {
*Head = NULL;
} else {
if (*Head == Item) {
*Head = (*Head)->ReadyQ.Right;
}
Item->ReadyQ.Left->ReadyQ.Right = Item->ReadyQ.Right;
Item->ReadyQ.Right->ReadyQ.Left = Item->ReadyQ.Left;
}
}
/*
* SubFromReady - subtract process descriptor, Item, from the Ready queue.
*/
static void SubFromReady(Descriptor *Item)
{
SubFromReadyQ(&RunQueue[Item->RunPriority], Item);
}
/*
* SubFromSemaphore - removes a process, Item, from a queue, Head.
*/
static void SubFromSemaphore (Descriptor **Head, Descriptor *Item)
{
if ((Item->SemaphoreQ.Right == *Head) && (Item == *Head)) {
*Head = NULL;
} else {
if (*Head == Item) {
*Head = (*Head)->SemaphoreQ.Right;
}
Item->SemaphoreQ.Left->SemaphoreQ.Right = Item->SemaphoreQ.Right;
Item->SemaphoreQ.Right->SemaphoreQ.Left = Item->SemaphoreQ.Left;
}
}
/*
* SubFromSemaphoreTop - returns the first descriptor in the
* semaphore queue.
*/
static Descriptor *SubFromSemaphoreTop(Descriptor **Head)
{
Descriptor *Top;
Top = *Head;
SubFromSemaphore(Head, Top);
return Top;
}
/*
* Idle - this process is only run whenever there is no other Runnable
* process. It should never be removed from the run queue.
*/
static void Idle(void)
{
OnOrOff ToOldState;
ToOldState = SYSTEM_TurnInterrupts(On); /* enable interrupts */
/*
Listen for interrupts.
We could solve chess endgames here or calculate PI etc.
We forever wait for an interrupt since there is nothing else
to do...
*/
while (1) ;
/* we must NEVER exit from the above loop */
}
/*
* InitIdleProcess - creates an idle process descriptor which
* is run whenever no other process is Runnable.
* The Idle process should be the only process which
* has the priority idle.
*/
static void InitIdleProcess(void)
{
char db[81];
SysStorage_ALLOCATE((void **)&IdleProcess, sizeof(Descriptor));
Debug_DebugString("IdleProcess = ", 13);
NumberIO_CardToStr((unsigned int)IdleProcess, 0, db, 80);
Debug_DebugString(db, 80);
Debug_DebugString("\\n", 1);
SysStorage_ALLOCATE(&IdleProcess->Start, (int)IdleStackSize);
IdleProcess->Size = IdleStackSize;
SYSTEM_NEWPROCESS(Idle, IdleProcess->Start,
IdleStackSize, &IdleProcess->Volatiles);
InitQueue(&IdleProcess->SemaphoreQ); /* not on a semaphore queue */
IdleProcess->Which = NULL; /* at all. */
StrLib_StrCopy("Idle", 3, (char *)&IdleProcess->RunName, MaxCharsInName);
/* idle process’s name */
IdleProcess->Status = Runnable; /* should always be idle */
IdleProcess->RunPriority = idle; /* lowest priority possible */
IdleProcess->Debugged = FALSE; /* should never be debugging */
AddToReady(IdleProcess); /* should be the only */
/* process at this run priority */
/* process now exists.. */
AddToExists(IdleProcess);
}
/*
* InitInitProcess - creates a descriptor for this running environment
* so it too can be manipulated by the Reschedule.
*
* This concept is important to understand.
* InitInitProcess is called by the startup code to this
* module. It ensures that the current stack and processor
* volatiles can be "housed" in a process descriptor and
* therefore it can be manipulated just like any other
* process.
*/
static void InitInitProcess(void)
{
SysStorage_ALLOCATE((void **)&CurrentProcess, sizeof(Descriptor));
CurrentProcess->Size = 0; /* init uses the default stack and */
CurrentProcess->Start = NULL; /* we don’t need to know where it is. */
/*
Volatiles - we will store the processor registers here when we
context switch - through Reschedule.
*/
InitQueue(&CurrentProcess->ReadyQ); /* assign queues to NIL */
InitQueue(&CurrentProcess->ExistsQ);
InitQueue(&CurrentProcess->SemaphoreQ); /* not waiting on a semaphore queue yet */
CurrentProcess->Which = NULL; /* at all. */
StrLib_StrCopy("Init", 3, (char *)&CurrentProcess->RunName, MaxCharsInName);
/* name for debugging purposes */
CurrentProcess->Status = Runnable; /* currently running */
CurrentProcess->RunPriority = lo; /* default status */
CurrentProcess->Debugged = FALSE; /* not deadlock debugging yet */
AddToExists(CurrentProcess);
AddToReady(CurrentProcess);
}
/*
* InitQueue - initializes a queue, q, to empty.
*/
static void InitQueue (struct DesQueue *q)
{
q->Right = NULL;
q->Left = NULL;
}
/*
* Init - initializes all the global variables.
*/
static void Init(void)
{
ExistsQueue = NULL;
RunQueue[(int)lo] = NULL;
RunQueue[(int)hi] = NULL;
RunQueue[(int)idle] = NULL;
AllSemaphores = NULL;
InitInitProcess();
InitIdleProcess();
}
void _M2_Executive_init(void)
{
Init();
}
/*
* Local variables:
* compile-command: "make"
* End:
*/
#ifndef SYSTEMH
#define SYSTEMH
/*
Author : Gaius Mulley
Title : SYSTEM
Date : 3/4/86
Description: Implements the SYSTEM dependant module
in the Modula-2 compiler.
Last update: 9/9/89 - types and pseudo procedures exported:
ADR, SIZE, TSIZE.
29/7/94 - started to add items to SYSTEM.mod
added In, Out.
3/8/94 - added TRANSFER
4/8/94 - added NEWPROCESS
10/8/94 - added IOTRANSFER
12/8/94 - added LISTEN
23/7/97 - removed port io and placed into separate module.
*/
typedef enum {
SYSTEM_On, SYSTEM_Off
} SYSTEM_OnOrOff;
#ifndef SYSTEMG
typedef void *SYSTEM_PROCESS; /* opaque type declaration */
#endif
/*
TRANSFER - save the current volatile environment into, p1.
Restore the volatile environment from, p2.
*/
extern void SYSTEM_TRANSFER(void **p1, void *p2);
/*
NEWPROCESS - p is a parameterless procedure, a, is the origin of
the workspace used for the process stack and containing
the volatile environment of the process. n, is the amount
in bytes of this workspace. new, is the new process.
*/
extern void SYSTEM_NEWPROCESS(void (*p)(void), void *a, unsigned long n,
void **new_);
/*
IOTRANSFER - saves the current volatile environment into, First,
and restores volatile environment, Second.
When an interrupt, InterruptNo, is encountered then
the reverse takes place. (The then current volatile
environment is shelved onto Second and First is resumed).
NOTE: that upon interrupt the Second might not be the
same process as that before the original call to
IOTRANSFER.
*/
extern void SYSTEM_IOTRANSFER(void **First, void **Second,
unsigned long InterruptNo);
/*
LISTEN - briefly listen for any interrupts.
*/
extern void SYSTEM_LISTEN(void);
/*
TurnInterrupts - switches interrupts on or off depending
on Switch. It returns the old value.
*/
extern SYSTEM_OnOrOff SYSTEM_TurnInterrupts(SYSTEM_OnOrOff Switch);
/*
Init - initialize SYSTEM data structures. IOTRANSFER process tables.
*/
extern void SYSTEM_Init(void);
extern void SYSTEM_CheckOff(void);
#endif /*SYSTEMH*/
/* Output from p2c, the Pascal-to-C translator */
/* From input file "ass2b.mod" */
/* some constants which comply with SYSTEM.def and general Modula-2 */
#define NULL (void *)0
#define TRUE (1==1)
#define FALSE (1==0)
#define STRING char *, const unsigned int
#define VARSTRING char *, const unsigned int
#define VARPROCESS void**
#define PARAMS(X) X
#define Colour int
typedef enum {On, Off} OnOrOff;
typedef void* Window;
#include "Executive.h"
#include "Colours.h"
#include "StdIO.h"
/*
* start of interface with microkernel functions
*/
extern OnOrOff SYSTEM_TurnInterrupts (OnOrOff);
extern void SYSTEM_IOTRANSFER (VARPROCESS, VARPROCESS, int);
extern void SYSTEM_TRANSFER (VARPROCESS old, PROCESS new);
extern void SYSTEM_NEWPROCESS (void *, void *, unsigned int, VARPROCESS);
extern void SysStorage_ALLOCATE (void **, const int);
extern void SysStorage_DEALLOCATE (void *, const int);
extern void Debug_Halt (STRING, const unsigned int, STRING);
extern void Debug_DebugString (STRING);
extern void StrLib_StrCopy (STRING, VARSTRING);
extern void NumberIO_CardToStr (int, int, VARSTRING);
extern void MonStrIO_WriteString (STRING);
extern Window WindowDevice_SetWindow (Window, Colour, Colour, int, int, int, int, int);
extern Window WindowDevice_InitWindow (void);
extern void WindowDevice_PutWindowOnTop (Window);
extern void MonStrIO_DebuggingStream (int (*p)(char));
extern void WindowDevice_WriteChar (Window, char);
/*
* and some C -> M2 interface macros (safe to ignore)
*/
#define STR(X) X,strlen(X)
#define C_MonStrIO_WriteString(X) MonStrIO_WriteString(STR(X))
#define C_WindowDevice_TitleWindow(X,Y) WindowDevice_TitleWindow(X,STR(Y))
#define C_Executive_InitProcess(X,Y,Z) Executive_InitProcess(X,Y,STR(Z))
#define C_Executive_InitSemaphore(X,Y) Executive_InitSemaphore(X,STR(Y))
/*
* simple utility function to help with converting strings from C into M2.
*/
static int strlen (char *s)
{
int i=0;
while (s[i] != (char)0)
i++;
return i;
}
#define StackSize 0x10000
static Semaphore ProcA, ProcB;
static Semaphore FromA, FromB;
static Window First, Second, Debugging;
/*
LocalWrite -
*/
static int LocalWrite(char ch)
{
if (Executive_GetCurrentProcess() == ProcA) {
WindowDevice_WriteChar(First, ch);
return;
}
if (Executive_GetCurrentProcess() == ProcB)
WindowDevice_WriteChar(Second, ch);
else
WindowDevice_WriteChar(Debugging, ch);
}
/*
SetupWindows - sets up three windows, First, Second and Debugging.
After this procedure has been called all StdIO
writes will go through LocalWrite.
*/
static void SetupWindows(void)
{
void (*TEMP)(char ch);
C_MonStrIO_WriteString("\\nBefore SetWindow");
/*
* first process window
*/
First = WindowDevice_SetWindow(WindowDevice_InitWindow(),
Colours_Blue, Colours_White,
38, 9, 1, 1, TRUE);
C_MonStrIO_WriteString("\\nBefore TitleWindow");
C_WindowDevice_TitleWindow(First, "Initial process");
/*
* second process window
*/
Second = WindowDevice_SetWindow(WindowDevice_InitWindow(),
Colours_Brown, Colours_White,
36, 9, 42, 1, TRUE);
C_WindowDevice_TitleWindow(Second, "Second process");
/*
* debugging window at the bottom
*/
Debugging = WindowDevice_SetWindow(WindowDevice_InitWindow(),
Colours_Red, Colours_White,
77, 11, 1, 12, TRUE);
C_WindowDevice_TitleWindow(Debugging, "Debugging output");
WindowDevice_PutOnTop(Debugging);
MonStrIO_DebuggingStream(LocalWrite);
StdIO_PushOutput(LocalWrite);
}
/*
ProcessA -
*/
static void ProcessA(void)
{
OnOrOff OldInts;
OldInts = SYSTEM_TurnInterrupts(On);
while (TRUE) {
Executive_Wait(FromB);
C_MonStrIO_WriteString("A: is this going to work? ");
Executive_Signal(FromA);
}
}
/*
ProcessB -
*/
static void ProcessB(void)
{
OnOrOff OldInts;
OldInts = SYSTEM_TurnInterrupts(On);
while (TRUE) {
Executive_Wait(FromA);
C_MonStrIO_WriteString("B: is this going to work? ");
Executive_Signal(FromB);
}
}
void _M2_ass2b_init (void)
{
char ch;
C_MonStrIO_WriteString("got to OS\\n");
ProcA = NULL;
ProcB = NULL;
SetupWindows();
FromA = C_Executive_InitSemaphore(0, "FromA");
FromB = C_Executive_InitSemaphore(1, "FromB");
C_MonStrIO_WriteString("lots of text to be displayed\\n");
C_MonStrIO_WriteString("now to create a process...\\n");
ProcA = Executive_Resume(C_Executive_InitProcess(ProcessA, StackSize, "Process1"));
C_MonStrIO_WriteString("process A running...\\n");
/* your code should go here */
/* and should end here */
Executive_Ps();
NumberIO_WriteHex(ProcA, 8);
WindowDevice_WriteChar(First, ’g’);
WindowDevice_WriteChar(Second, ’a’);
while (TRUE) {
TTIO_Read(&ch); /* was StdIO_Read(&ch) and it failed.. */
StdIO_Write(ch);
if (ch == ’p’)
Executive_Ps();
}
}
This document was produced using groff-1.19.