#include "priority.h" #include #define LO_CRITICAL_SECS 2 #define HI_CRITICAL_SECS 2 #define STACK_SIZE 1000 #define TOP_OF(stk) &stk[STACK_SIZE] typedef struct THREAD { void (*function)() ; int priority ; char graphic ; char *title ; WINDOW *window ; OS_STK stack[STACK_SIZE] ; } THREAD ; typedef enum { SEMA_PENDING = 0, SEMA_ACQUIRED = 1, SEMA_RELEASED = 2 } SEMAPHORE ; #define DORMANT 'ú' #define PENDING '' #define RELEASED '±' #define ACQUIRED 'Û' #define SUSPENDED PENDING int Column(void) ; void CriticalSectionTime(WINDOW *, DWORD32) ; DWORD32 Elapsed(void) ; void HighPriThread() ; void HorizBar(THREAD *) ; void Marker(WINDOW *, char) ; void MedPriThread() ; void LowPriThread() ; void Loops(THREAD *, int, int) ; void ResetSimulation(void) ; void SecsOfWork(THREAD *, int) ; void Semaphore(WINDOW *, SEMAPHORE, int) ; void SetUpThread(int, char *, void (*)(), int) ; void StartThread(int) ; void TimeStamp(WINDOW *, int, int, char *, DWORD32) ; BOOL Unbounded(DWORD32) ; void WaitForKeystroke(void) ; THREAD thread[3] ; DWORD32 time_base ; OS_EVENT * semaphore ; int main() { ClearScreen(0x07) ; SetCursorVisible(FALSE) ; SetUpThread(TSK_HI, "High Priority Thread", HighPriThread, PRI_HI); SetUpThread(TSK_MED, "Medium Priority Thread", MedPriThread, PRI_MED); SetUpThread(TSK_LOW, "Low Priority Thread", LowPriThread, PRI_LOW); OSInit() ; semaphore = OSSemCreate(1) ; StartThread(TSK_LOW) ; OSStart() ; return 0 ; } void LowPriThread() { int w, row ; THREAD *t ; SetCursorPosition(12, 30) ; PutString("Initializing...") ; SecsOfWork(NULL, 0) ; row = 0 ; t = thread ; for (w = 0; w < ENTRIES(thread); w++, t++) { t->window = WindowCreate(t->title, row, row + 7, 0, 79) ; row += 8 ; } for (;;) { DWORD32 timer, start, stop ; timer = Now_Plus(10) ; time_base = start = Milliseconds() ; LoPriThreadPend() ; StartThread(TSK_MED) ; StartThread(TSK_HI) ; SecsOfWork(&thread[TSK_LOW], LO_CRITICAL_SECS) ; stop = Milliseconds() ; CriticalSectionTime(thread[TSK_LOW].window, stop - start) ; LoPriThreadPost() ; while (Now_Plus(0) < timer) { SecsOfWork(&thread[TSK_LOW], 1) ; } ResetSimulation() ; } } void MedPriThread() { OSTimeDly(random() % 6000) ; TimeStamp(thread[TSK_MED].window, 3, 0, "Started at ", Elapsed()); thread[TSK_MED].graphic = RELEASED ; SecsOfWork(&thread[TSK_MED], 2) ; thread[TSK_MED].graphic = DORMANT ; TimeStamp(thread[TSK_MED].window, 4, 0, "Stopped at ", Elapsed()); for (;;) OSTimeDly(1) ; } void HighPriThread() { unsigned start, elapsed ; OSTimeDly(random() % 1000) ; thread[TSK_HI].graphic = RELEASED ; SecsOfWork(&thread[TSK_HI], 1) ; start = Milliseconds() ; HiPriThreadPend() ; SecsOfWork(&thread[TSK_HI], HI_CRITICAL_SECS) ; elapsed = Milliseconds() - start ; CriticalSectionTime(thread[TSK_HI].window, elapsed) ; HiPriThreadPost() ; WindowSetCursor(thread[TSK_HI].window, 4, 45) ; WindowPutString(thread[TSK_HI].window, Unbounded(elapsed) ? "UNBOUNDED PRIORITY INVERSION" : "Bounded Priority Inversion") ; SecsOfWork(&thread[TSK_HI], 1) ; thread[TSK_HI].graphic = DORMANT ; for (;;) OSTimeDly(1) ; } void SecsOfWork(THREAD *t, int seconds) { static unsigned outer ; static unsigned inner ; if (!seconds) { int i, start, msec ; /* Determine loop parameters for a 1-second delay */ outer = inner = 1 ; for (i = 0; i < 31; i++) { start = Milliseconds() ; Loops(NULL, outer, inner) ; msec = Milliseconds() - start ; if (msec > 500) break ; outer = inner *= 2 ; } outer = (1000 * outer + msec/2) / msec ; } while (seconds--) Loops(t, outer, inner) ; } void Loops(THREAD *t, int outer, int inner) { while (outer--) { int i ; for (i = 0; i < inner; i++) ; HorizBar(t) ; } } int Column(void) { return (77 * Elapsed() + 5000) / 10000 ; } void HorizBar(THREAD *me) { static int previous = -1 ; int col = Column() ; if (col != previous && col < 78) { THREAD *t ; int i ; t = thread ; for (i = 0; i < ENTRIES(thread); i++, t++) { char graphic = t->graphic ; if (t != me && graphic != DORMANT) { graphic = SUSPENDED ; } if (!me) continue ; WindowSetCursor(t->window, 1, col) ; WindowPutChar(t->window, graphic) ; } previous = col ; } } void ResetSimulation(void) { THREAD *t ; int i ; OSTaskDel(PRI_HI) ; OSTaskDel(PRI_MED) ; WaitForKeystroke() ; t = thread ; for (i = 0; i < ENTRIES(thread); i++, t++) { WindowErase(t->window) ; t->graphic = DORMANT ; } OSTaskChangePrio(thread[TSK_LOW].priority, PRI_LOW) ; time_base = Milliseconds() ; } void CriticalSectionTime(WINDOW *w, DWORD32 msec) { TimeStamp(w, 5, 45, "Critical Section: ", msec) ; } void Semaphore(WINDOW *w, SEMAPHORE sema, int row) { static char *labels[] = { "Pending at ", "Acquire at ", "Release at " } ; Marker(w, labels[sema][0]) ; TimeStamp(w, row, 0, labels[sema], Elapsed()) ; } void Marker(WINDOW *w, char marker) { int col = Column() ; if (col) col++ ; WindowSetCursor(w, 2, col) ; WindowPutChar(w, marker) ; } void TimeStamp(WINDOW *w, int row, int col, char *label, DWORD32 msec) { char bfr[10] ; WindowSetCursor(w, row, col) ; WindowPutString(w, label) ; FormatUnsigned(bfr, (msec + 5)/10, 10, 3, '0') ; WindowPutChar(w, bfr[0]) ; WindowPutChar(w, '.') ; WindowPutString(w, &bfr[1]) ; WindowPutString(w, " sec") ; } void WaitForKeystroke(void) { SetCursorPosition(24, 26) ; PutString("Press any key to restart...") ; while (!ScanCodeRdy()) ; GetScanCode() ; while (!ScanCodeRdy()) ; GetScanCode() ; SetCursorPosition(24, 26) ; PutString(" ") ; } DWORD32 Elapsed(void) { return Milliseconds() - time_base ; } BOOL Unbounded(DWORD32 elapsed) { return elapsed > 100 + 1000 * (LO_CRITICAL_SECS + HI_CRITICAL_SECS) ; } void SetUpThread(int which, char *title, void (*function)(), int priority) { THREAD *t = &thread[which] ; t->title = title ; t->function = function ; t->priority = priority ; t->graphic = DORMANT ; } void StartThread(int which) { THREAD *t = &thread[which] ; OSTaskCreate(t->function, NULL, TOP_OF(t->stack), t->priority) ; } void SemaphorePend(int which) { THREAD *t = &thread[which] ; BYTE8 err ; Semaphore(t->window, SEMA_PENDING, 3) ; t->graphic = PENDING ; OSSemPend(semaphore, 0, &err) ; Semaphore(t->window, SEMA_ACQUIRED, 4) ; t->graphic = ACQUIRED ; } void SemaphorePost(int which) { THREAD *t = &thread[which] ; Semaphore(t->window, SEMA_RELEASED, 5) ; t->graphic = RELEASED ; OSSemPost(semaphore) ; } void ChangePriority(int which, int new_pri) { THREAD *t = &thread[which] ; WINDOW *w = t->window ; int old_pri = t->priority ; t->priority = new_pri ; WindowSetCursor(w, 0, 60) ; WindowPutString(w, new_pri == PRI_RAISED ? "PRIORITY RAISED" : " ") ; OSTaskChangePrio(old_pri, new_pri) ; }