home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_09_11
/
9n11043a
< prev
next >
Wrap
Text File
|
1991-09-25
|
8KB
|
299 lines
/* -- exec.h --
*/
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#ifndef STRATOM_H
#include "stratom.h"
#endif
#ifndef YES
#define YES 1
#define NO 0
typedef int BOOL;
#endif
#ifndef BIT
#define BIT(i) (1 << (i))
#endif
/* different perfixes for EXEC_ID
*/
#define PORT_PREFIX BIT(15)
#define SEMAPHORE_PREFIX BIT(14)
#define TIMER_PREFIX BIT(13)
#define MONOSTABLE_PREFIX BIT(12)
#define TRIGGER_PREFIX BIT(11)
#define BAD_EXEC_ID 0
typedef int EXEC_ID;
typedef unsigned char THREAD_ID;
typedef unsigned int PORT;
typedef unsigned int SEMAPHORE;
/* process type. Not used yet
*/
typedef enum
{ NORMAL_PROC = 10, HALTABLE_PROC, INHIBITABLE_PROC }
PROCESS_TYPE;
void *ExecAlloc(unsigned int size);
THREAD_ID ExecCreateThread(PROCESS_TYPE procType,
void (*pFunction)(void), unsigned int stackSize,
unsigned long arg0, unsigned long arg1);
THREAD_ID ExecGetThreadID(void);
void ExecInit(void);
void ExecStart(void);
void MsgClearSemaphore(STRING_ATOM semaphoreAtom);
BOOL MsgConnectPorts(STRING_ATOM sourceAtom,
STRING_ATOM destinationAtom);
void MsgDeleteTimer(EXEC_ID watchID);
EXEC_ID MsgGetMsg(void);
BOOL MsgInhibitPorts(STRING_ATOM sourceAtom,
STRING_ATOM destinationAtom);
void *MsgOpenPort(STRING_ATOM nameAtom, PORT *pPortValue);
PORT MsgPeekPort(STRING_ATOM, PORT *);
void MsgSetSemaphore(STRING_ATOM semaphoreAtom);
BOOL MsgSuppressPorts(STRING_ATOM sourceAtom,
STRING_ATOM destinationAtom);
EXEC_ID MsgWatchPort(STRING_ATOM portAtom, PORT *pPortValue);
EXEC_ID MsgWatchSemaphore(STRING_ATOM semaphoreAtom, BOOL detectOn);
EXEC_ID MsgWatchTimer(unsigned int interval);
void MsgWriteToPort(STRING_ATOM portAtom, PORT portValue);
#define MsgWatchTrigger(portAtom) MsgWatchPort(portAtom, NULL)
void SysLEDs(int i);
typedef unsigned
#ifdef HC11
int
#else
long
#endif
EXEC_ARG;
extern EXEC_ARG ExecArg0, ExecArg1;
/* -- exec.c --
*/
#include <stdlib.h>
#include <string.h>
#include "exec.h"
#include "execpriv.h"
/* arguments to threads
*/
EXEC_ARG ExecArg0;
EXEC_ARG ExecArg1;
/* number of possible threads
*/
#ifndef NUMBER_OF_THREADS
#define NUMBER_OF_THREADS 34
#endif
/* process state
*/
typedef enum
{ INIT_STATE = 20, RUNNING_STATE, WAIT_STATE }
PROCESS_STATE;
/* context for thread
*/
typedef struct
{
THREAD_ID threadID;
void (*pFunction)(void);
PROCESS_TYPE procType;
PROCESS_STATE procState;
jmp_buf exitContext;
jmp_buf switchContext;
char *stackTop;
char *stackBottom;
EXEC_ARG arg0;
EXEC_ARG arg1;
} THREAD_CONTEXT;
/* file static variables
*/
static BOOL hasCreatedThreads;
static THREAD_CONTEXT threadTable[NUMBER_OF_THREADS];
static THREAD_ID execCurrentThreadID;
static void execRunNewThread(void);
/* allocate a block of memory, zeroed out
*/
void *ExecAlloc(unsigned int size)
{
void *p;
p = calloc(1, size);
if (!p)
{
#ifndef HC11
printf("no memory\n");
#endif
exit(1);
}
return (p);
}
/* thread function returns here, jump to exit context
*/
void ExecCallReturn(void)
{
longjmp(threadTable[execCurrentThreadID].exitContext,
execCurrentThreadID);
}
/* create a thread context
*/
THREAD_ID ExecCreateThread(PROCESS_TYPE procType, void (*pFunction)(void),
unsigned int stackSize, unsigned long arg0, unsigned long arg1)
{
char *stack;
THREAD_ID i;
/* find the next free entry in table
*/
for (i = 0; i < NUMBER_OF_THREADS && threadTable[i].procState; ++i)
;
if (i == NUMBER_OF_THREADS)
return (BAD_EXEC_ID);
hasCreatedThreads = YES;
/* clear entry and allocate stack
*/
memset(&threadTable[i], '\0', sizeof (THREAD_CONTEXT));
/* stack space used by the executive, i.e. by the functions MsgGetMsg()
* and ExecSwitch()
*/
stackSize &= ~0x3; /* quad byte aligned */
#define EXEC_STACK_SIZE 40
stackSize += EXEC_STACK_SIZE;
stack = SysGetStack(stackSize);
threadTable[i].procType = procType;
threadTable[i].pFunction = pFunction;
threadTable[i].stackBottom = stack;
threadTable[i].stackTop = stack + stackSize;
threadTable[i].procState = INIT_STATE;
/* memorize the initail arguments to function
*/
threadTable[i].arg0 = arg0;
threadTable[i].arg1 = arg1;
/* put this on the runnable queue
*/
MsgEnQueue(i, i);
return (i);
}
/* return a new id
*/
EXEC_ID execExecID(unsigned int prefix)
{
static unsigned int i;
return (prefix | (++i));
}
/* return the current thread id
*/
THREAD_ID ExecGetThreadID(void)
{
return (execCurrentThreadID);
}
/* initialize the system
*/
void ExecInit(void)
{
SysInit();
}
/* take the first thread off the runnable queue and give execution to it
*/
static
void execRunNewThread(void)
{
EXEC_ID returnID;
PROCESS_STATE procState;
/* take the first thread off the queue
*/
execCurrentThreadID = MsgDeQueue(&returnID);
SysLEDs(execCurrentThreadID);
/* set process state
*/
procState = threadTable[execCurrentThreadID].procState;
threadTable[execCurrentThreadID].procState = RUNNING_STATE;
/* procState == WAIT_STAT - use longjmp() to switch back to the old
* execution context
*/
if (procState != INIT_STATE)
longjmp(threadTable[execCurrentThreadID].switchContext, returnID);
else
{
/* initial call to a thread. Put thread arguments
in the external
* variables and call an assembly routine to call the thread
*/
if (setjmp(threadTable[execCurrentThreadID].exitContext) == 0)
{
ExecArg0 = threadTable[execCurrentThreadID].arg0;
ExecArg1 = threadTable[execCurrentThreadID].arg1;
ExecCall(threadTable[execCurrentThreadID].pFunction,
threadTable[execCurrentThreadID].stackTop);
}
/* thread dies, reclaim thread table entry (but
not stack space)
* and run the next available thread
*/
threadTable[execCurrentThreadID].procState = 0;
/* need to delete from all queues and ports
*/
execRunNewThread();
}
}
/* start the system.
*/
void ExecStart(void)
{
if (hasCreatedThreads)
execRunNewThread();
}
/* switch to a new thread
*/
EXEC_ID ExecSwitch(void)
{
EXEC_ID watchID;
/* check for stack overflow
*/
if ((char *)&watchID < threadTable[execCurrentThreadID].stackBottom)
{
#ifndef HC11
printf("stack overflow\n");
#endif
exit(1);
}
/* set up our return context and switch
*/
if ((watchID = setjmp(threadTable[execCurrentThreadID].switchContext)) == 0)
{
threadTable[execCurrentThreadID].procState = WAIT_STATE;
execRunNewThread();
}
return (watchID);
}