//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Authors: spectral` // // NeoX // // // // Desc: Scheduling algorithm // //----------------------------------------------------------------------------// #include #ifndef _KALEID_KERNEL #include CREATE_PER_CPU(CurProc, Process_t *); // // For test purpose only // int procslen = 9; Process_t procs[] = { { 0, 0, 0, 12, 12, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 1, 2, 2, 16, 16, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 2, 3, 3, 31, 31, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 3, 2, 2, 1, 1, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 4, 0, 0, 5, 5, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 5, 0, 0, 30, 30, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 6, 1, 1, 19, 19, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 7, 1, 1, 0, 0, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, { 8, 3, 3, 12, 12, STATE_RUNNABLE, DEF_PROC_TSLICE, DEF_PROC_TSLICE, NULL }, }; #endif // // Set current process // TODO Select thread, context switch // static inline void SetCurProc(Process_t *proc) { _SetCurProc(proc); if (GetCurProc() != NULL) { GetCurProc()->procState = STATE_RUNNING; } } // // (Un)Lock priority class list heads // static inline void SchedLock(void) { #ifdef _KALEID_KERNEL DisableIRQs(); #endif } static inline void SchedUnlock(void) { #ifdef _KALEID_KERNEL EnableIRQs(); #endif } // // The four priority classes of OS/2 // CREATE_PER_CPU(IdlePrioProcs, ListHead_t *); CREATE_PER_CPU(ReglPrioProcs, ListHead_t *); CREATE_PER_CPU(ServPrioProcs, ListHead_t *); CREATE_PER_CPU(TimeCritProcs, ListHead_t *); char *PrioClassesNames[] = { "Idle priority class", "Regular priority class", "Server priority class", "Time-critical class", }; enum { IDLE_PRIO_PROC = 0, REGL_PRIO_PROC = 1, SERV_PRIO_PROC = 2, TIME_CRIT_PROC = 3, }; // // Get priority class list head // static inline ListHead_t *GetPrioClassHead(int prioClass) { switch (prioClass) { case TIME_CRIT_PROC: return GetTimeCritProcs(); case SERV_PRIO_PROC: return GetServPrioProcs(); case REGL_PRIO_PROC: return GetReglPrioProcs(); case IDLE_PRIO_PROC: return GetIdlePrioProcs(); default: KalAssert(FALSE && "Unknown priority class"); } return NULL; } // // Determine which process is going to run first // Return NULL for "equal" processes // static inline Process_t *CompareProcs(Process_t *proc1, Process_t *proc2) { KalAssert(proc1 && proc2); if (proc1->prioClass > proc2->prioClass) return proc1; if (proc1->prioClass < proc2->prioClass) return proc2; if (proc1->prioLevel > proc2->prioLevel) return proc1; if (proc1->prioLevel < proc2->prioLevel) return proc2; return NULL; // same class and level } // // Add process to schedule lists (unlocked) // static inline void SchedThisProcUnlocked(Process_t *proc) { KalAssert(proc && proc->procState == STATE_RUNNABLE); bool found = false; ListNode_t *iterNode = NULL; ListNode_t *procNode = CreateNode(proc); ListHead_t *head = GetPrioClassHead(proc->prioClass); KalAssert(procNode && head); proc->schedNode = procNode; //printdbg("Adding process %d to '%s'\n", proc->pid, PrioClassesNames[proc->prioClass]); // // Find a process with lesser priority // for (iterNode = head->first; iterNode; iterNode = iterNode->next) { if (proc->prioLevel > GetNodeData(iterNode, Process_t *)->prioLevel) { AddNodeBefore(head, iterNode, procNode); found = true; break; } } // // Didn't find any process with lesser priority // if (found == false) { AppendNode(head, procNode); } } // // Add process to schedule lists // void SchedThisProc(Process_t *proc) { SchedLock(); SchedThisProcUnlocked(proc); SchedUnlock(); } // // Selects process to schedule next // // WARNING // Does not call SchedLock()/SchedUnlock() // static inline Process_t *SelectSchedNext(void) { if (GetTimeCritProcs()->length > 0) return GetNodeData(GetTimeCritProcs()->first, Process_t *); if (GetServPrioProcs()->length > 0) return GetNodeData(GetServPrioProcs()->first, Process_t *); if (GetReglPrioProcs()->length > 0) return GetNodeData(GetReglPrioProcs()->first, Process_t *); if (GetIdlePrioProcs()->length > 0) return GetNodeData(GetIdlePrioProcs()->first, Process_t *); return NULL; } // // Remove running process from schedule lists // and schedule next runnable process // static inline void BlockCurProc(void) { KalAssert(GetCurProc() && GetCurProc()->procState == STATE_RUNNING); ListNode_t *procNode = GetCurProc()->schedNode; GetCurProc()->procState = STATE_BLOCKED; RemoveNode(procNode->head, procNode); SetCurProc(SelectSchedNext()); } // // Should we schedule another process? // Called at each tick // void SchedOnTick(void) { Process_t *procNext; Process_t *winner; SchedLock(); // // We're either idle or running something // KalAssert(GetCurProc() == NULL || GetCurProc()->procState == STATE_RUNNING); // // Has current process spent his timeslice? // (To be handled in CPU decisions function) // if (GetCurProc() != NULL) { if (GetCurProc()->timeSlice <= 1) { // Restore default attributes, cancelling boosts GetCurProc()->prioClass = GetCurProc()->defPrioClass; GetCurProc()->prioLevel = GetCurProc()->defPrioLevel; GetCurProc()->timeSlice = GetCurProc()->defTimeSlice; GetCurProc()->procState = STATE_RUNNABLE; // Remove from list RemoveNode(GetCurProc()->schedNode->head, GetCurProc()->schedNode); // Schedule again, with default attributes now SchedThisProcUnlocked(GetCurProc()); // Mark as idle SetCurProc(NULL); } // // Otherwise, make him lose a tick // else { GetCurProc()->timeSlice--; } } // // Are we idle, or scheduling next process? // if (GetCurProc() == NULL) { SetCurProc(SelectSchedNext()); goto leave; } // // Is there a higher priority process that is runnable? // procNext = SelectSchedNext(); winner = CompareProcs(GetCurProc(), procNext); // // Yes, procNext should preempt current process // if (winner == procNext) { GetCurProc()->procState = STATE_RUNNABLE; SchedThisProcUnlocked(GetCurProc()); SetCurProc(procNext); } // // Current process won't be preempted and has time remaining // leave: SchedUnlock(); } #define PrintProc(proc) printdbg("{ %d, '%s', %d , %d}\n", (proc)->pid, \ PrioClassesNames[(proc)->prioClass], (proc)->prioLevel, (proc)->timeSlice); // // Print out process list // void PrintList(ListHead_t *head) { KalAssert(head); Process_t *proc; ListNode_t *node = head->first; printdbg("len: %d\n", head->length); while (node) { proc = GetNodeData(node, Process_t *); PrintProc(proc); node = node->next; } puts(""); } // // Initialize scheduler // void InitSched(void) { int pid; Process_t *proc; SchedLock(); _SetTimeCritProcs(CreateListHead()); _SetServPrioProcs(CreateListHead()); _SetReglPrioProcs(CreateListHead()); _SetIdlePrioProcs(CreateListHead()); #ifndef _KALEID_KERNEL for (pid = 0; pid < procslen; pid++) { if (procs[pid].procState == STATE_RUNNABLE) { SchedThisProcUnlocked(&procs[pid]); } } #endif SchedUnlock(); } // // Shutdown scheduler // void FiniSched(void) { KalAssert(GetIdlePrioProcs() && GetReglPrioProcs() && GetServPrioProcs() && GetTimeCritProcs()); SchedLock(); while (GetIdlePrioProcs()->length > 0) RemoveNode(GetIdlePrioProcs(), GetIdlePrioProcs()->first); while (GetReglPrioProcs()->length > 0) RemoveNode(GetReglPrioProcs(), GetReglPrioProcs()->first); while (GetServPrioProcs()->length > 0) RemoveNode(GetServPrioProcs(), GetServPrioProcs()->first); while (GetTimeCritProcs()->length > 0) RemoveNode(GetTimeCritProcs(), GetTimeCritProcs()->first); DestroyListHead(GetIdlePrioProcs()); _SetIdlePrioProcs(NULL); DestroyListHead(GetReglPrioProcs()); _SetReglPrioProcs(NULL); DestroyListHead(GetServPrioProcs()); _SetServPrioProcs(NULL); DestroyListHead(GetTimeCritProcs()); _SetTimeCritProcs(NULL); SchedUnlock(); } #ifndef _KALEID_KERNEL int main(void) { InitSched(); puts("---------------"); puts("Time Critical:"); PrintList(GetTimeCritProcs()); puts("Server:"); PrintList(GetServPrioProcs()); puts("Regular:"); PrintList(GetReglPrioProcs()); puts("Idle:"); PrintList(GetIdlePrioProcs()); puts("---------------"); getchar(); int tick = 0; while (tick < 20) { printf("Tick %d - Running: ", tick); if (GetCurProc() == NULL) { puts("IDLE"); } else { PrintProc(GetCurProc()); } if (tick == 9 || tick == 14) { puts("Blocking current process"); BlockCurProc(); } SchedOnTick(); //puts("\n---------------"); tick++; } FiniSched(); return 0; } #endif