/* ------------------------------------------------------- */ /* PROGRAM mtp.c: */ /* This program shows a poorman's multithreaded kernel */ /* using setjmp() and longjmp(). */ /* */ /* Ching-Kuang Shene */ /* August 31, 1998 */ /* ------------------------------------------------------- */ #include #include #include #define MAX_COUNT 5 /* ------------------------------------------------------- */ /* Data Structures */ /* ------------------------------------------------------- */ typedef struct PCB_NODE *PCB_ptr; /* pointer to a PCB */ typedef struct PCB_NODE { /* a PCB: */ jmp_buf Environment; /* jump buffer */ int Name; /* thread name: unused*/ PCB_ptr Next; /* next PCB */ } PCB; /* ------------------------------------------------------- */ /* External Data */ /* ------------------------------------------------------- */ jmp_buf MAIN; /* jump buffer for main */ jmp_buf SCHEDULER; /* for the scheduler */ PCB_ptr Head; /* head of the PCBs */ PCB_ptr Current; /* current executing */ PCB_ptr work; /* working variable */ /* ------------------------------------------------------- */ /* Macro THREAD_CREATE */ /* This macro creates a thread. */ /* ------------------------------------------------------- */ #define THREAD_CREATE(function, name) { \ if (setjmp(MAIN) == 0) \ (function)(name); \ } /* ------------------------------------------------------- */ /* Macro THREAD_INIT */ /* This macro allocates a PCB for a thread and puts it */ /* into the scheduling chain, which is a circular list. */ /* ------------------------------------------------------- */ #define THREAD_INIT(name) { \ work = (PCB_ptr) malloc(sizeof(PCB)); \ work->Name = name; \ if (Head == NULL) \ Head = work; \ else \ Current->Next = work; \ work->Next = Head; \ Current = work; \ if (setjmp(work->Environment) == 0) \ longjmp(MAIN, 1); \ } /* ------------------------------------------------------- */ /* Macro THREAD_YIELD */ /* This macro simulates yielding control by jumping */ /* into the scheduler. The scheduler picks the next */ /* thread to run. */ /* ------------------------------------------------------- */ #define THREAD_YIELD(name) { \ if (setjmp(Current->Environment) == 0) \ longjmp(SCHEDULER, 1); \ } /* ------------------------------------------------------- */ /* FUNCTION funct_1(): */ /* A function to be run as a thread. */ /* ------------------------------------------------------- */ void funct_1(int name) { int i; THREAD_INIT(name); /* initialize as thread */ while (1) { /* running the thread */ for (i = 1; i <= MAX_COUNT; i++) printf("funct_1() executing\n"); THREAD_YIELD(name); /* yield control */ } } /* ------------------------------------------------------- */ /* FUNCTION funct_2(): */ /* A function to be run as a thread. */ /* ------------------------------------------------------- */ void funct_2(int name) { int i; THREAD_INIT(name); while (1) { for (i = 1; i <= MAX_COUNT; i++) printf(" funct_2() executing\n"); THREAD_YIELD(name); } } /* ------------------------------------------------------- */ /* FUNCTION funct_3(): */ /* A function to be run as a thread. */ /* ------------------------------------------------------- */ void funct_3(int name) { int i; THREAD_INIT(name); while (1) { for (i = 1; i <= MAX_COUNT; i++) printf(" funct_3() executing\n"); THREAD_YIELD(name); } } /* ------------------------------------------------------- */ /* FUNCTION funct_4(): */ /* A function to be run as a thread. */ /* ------------------------------------------------------- */ void funct_4(int name) { int i; THREAD_INIT(name); while (1) { for (i = 1; i <= MAX_COUNT; i++) printf(" funct_4() executing\n"); THREAD_YIELD(name); } } /* ------------------------------------------------------- */ /* FUNCTION Scheduler(): */ /* The scheduler is first called by the main program to */ /* setup an entry point. Then, it is re-entered through */ /* a longjmp() from the THREAD_YIELD() macro. */ /* ------------------------------------------------------- */ void Scheduler(void) { if (setjmp(SCHEDULER) == 0) longjmp(MAIN, 1); Current = Current->Next; longjmp(Current->Environment, 1); } /* ------------------------------------------------------- */ /* The main program starts here */ /* The main program calls each threads, allowing then to */ /* initializing themselves. Then, calls the scheduler. */ /* Finally, jumps to the scheduler to start the system. */ /* ------------------------------------------------------- */ void main(void) { Head = Current = NULL; /* initialize pointers */ THREAD_CREATE(funct_1, 1); /* initialize threads */ THREAD_CREATE(funct_2, 2); THREAD_CREATE(funct_3, 3); THREAD_CREATE(funct_4, 4); if (setjmp(MAIN) == 0) /* initialize scheduler */ Scheduler(); longjmp(SCHEDULER,1); /* start scheduler */ }