Advertisement
NaZaRa

Untitled

Jan 11th, 2019
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.43 KB | None | 0 0
  1. //----------------------------------------------------------------------------//
  2. // GNU GPL OS/K //
  3. // //
  4. // Authors: spectral` //
  5. // NeoX //
  6. // //
  7. // Desc: Scheduling algorithm //
  8. //----------------------------------------------------------------------------//
  9.  
  10. #include <stdio.h>
  11.  
  12. typedef unsigned int uint;
  13. typedef unsigned long ulong;
  14.  
  15. #define printdbg printf
  16. #define _STR(x) #x
  17. #define _XSTR(x) _STR(x)
  18.  
  19. #define _KALTYPES_H
  20. #include <common/kallist.h>
  21.  
  22. typedef struct {
  23. int pid;
  24. int prioClass;
  25. int prioLevel;
  26. int procState;
  27. ulong timeSlice;
  28. ListNode_t *schedNode;
  29. } Process_t;
  30.  
  31. //
  32. // States for a process
  33. //
  34. #define STATE_RUNNING 0
  35. #define STATE_RUNNABLE 1
  36. #define STATE_BLOCKED 2
  37.  
  38. //
  39. // Time in ticks a process should be run
  40. //
  41. #define DEFAULT_PROC_TIMESLICE 5 // 20 ticks
  42. #define TIMECRIT_PROC_TIMESLICE 20000 // 20000 ticks
  43.  
  44. // XXX per-CPU stuff
  45. Process_t *CurProc = NULL;
  46.  
  47. #define GetCurProc() (CurProc)
  48. static inline
  49. void SetCurProc(Process_t *proc)
  50. {
  51. CurProc = proc;
  52. if (CurProc != NULL) {
  53. CurProc->procState = STATE_RUNNING;
  54. }
  55. }
  56.  
  57. //
  58. // For test purpose only
  59. //
  60. int procslen = 9;
  61. Process_t procs[] = {
  62. { 0, 0, 12, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  63. { 1, 2, 16, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  64. { 2, 3, 31, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  65. { 3, 2, 1, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  66. { 4, 0, 5, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  67. { 5, 0, 30, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  68. { 6, 1, 19, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  69. { 7, 1, 0, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  70. { 8, 3, 12, STATE_RUNNABLE, DEFAULT_PROC_TIMESLICE, NULL },
  71. };
  72.  
  73. //
  74. // Shared lock among all process lists
  75. //
  76. static Lock_t *PrioClassesLock = NULL;
  77.  
  78. //
  79. // (Un)Lock priority class list heads
  80. // XXX should we disable IRQs?
  81. //
  82.  
  83. static inline
  84. void SchedLock(void)
  85. { AquireLock(PrioClassesLock); }
  86.  
  87. static inline
  88. void SchedUnlock(void)
  89. { ReleaseLock(PrioClassesLock); }
  90.  
  91. //
  92. // The four priority classes of OS/2
  93. //
  94. ListHead_t *IdlePrioProcs = NULL,
  95. *ReglPrioProcs = NULL,
  96. *ServPrioProcs = NULL,
  97. *TimeCritProcs = NULL;
  98.  
  99. char *PrioClassesNames[] = {
  100. "Idle priority class",
  101. "Regular priority class",
  102. "Server priority class",
  103. "Time-critical class",
  104. };
  105.  
  106. enum { IDLE_PRIO_PROC = 0,
  107. REGL_PRIO_PROC = 1,
  108. SERV_PRIO_PROC = 2,
  109. TIME_CRIT_PROC = 3,
  110. };
  111.  
  112. //
  113. // Get priority class list head
  114. //
  115. ListHead_t *GetPrioClassHead(int prioClass)
  116. {
  117. switch (prioClass) {
  118. case TIME_CRIT_PROC: return TimeCritProcs;
  119. case SERV_PRIO_PROC: return ServPrioProcs;
  120. case REGL_PRIO_PROC: return ReglPrioProcs;
  121. case IDLE_PRIO_PROC: return IdlePrioProcs;
  122. default: KalAssert(FALSE && "Unknown priority class");
  123. }
  124. }
  125.  
  126. //
  127. // Determine which process is going to run first
  128. // Returns NULL for "equal" processes
  129. //
  130. Process_t *CompareProcs(Process_t *proc1, Process_t *proc2)
  131. {
  132. KalAssert(proc1 && proc2);
  133.  
  134. if (proc1->prioClass > proc2->prioClass) return proc1;
  135. if (proc1->prioClass < proc2->prioClass) return proc2;
  136.  
  137. if (proc1->prioLevel > proc2->prioLevel) return proc1;
  138. if (proc1->prioLevel < proc2->prioLevel) return proc2;
  139.  
  140. return NULL; // same class and level
  141. }
  142.  
  143. //
  144. // Add process to schedule lists
  145. //
  146. void SchedThisProc(Process_t *proc)
  147. {
  148. KalAssert(proc && proc->procState == STATE_RUNNABLE);
  149.  
  150. bool found = false;
  151. ListNode_t *iterNode = NULL;
  152. ListNode_t *procNode = CreateNode(proc);
  153. ListHead_t *head = GetPrioClassHead(proc->prioClass);
  154.  
  155. KalAssert(procNode && head);
  156.  
  157. // XXX double locking
  158. // SchedLock();
  159.  
  160. proc->schedNode = procNode;
  161.  
  162. printdbg("Adding process %d to '%s'\n", proc->pid, PrioClassesNames[proc->prioClass]);
  163.  
  164. //
  165. // Find a process with lesser priority
  166. //
  167. for (iterNode = head->first; iterNode; iterNode = iterNode->next) {
  168. if (proc->prioLevel > GetNodeData(iterNode, Process_t *)->prioLevel) {
  169. AddNodeBefore(head, iterNode, procNode);
  170. found = true;
  171. break;
  172. }
  173. }
  174.  
  175. //
  176. // Didn't find any process with lesser priority
  177. //
  178. if (found == false) {
  179. AppendNode(head, procNode);
  180. }
  181.  
  182. // SchedUnlock();
  183. }
  184.  
  185. //
  186. // Selects process to schedule next
  187. //
  188. // WARNING
  189. // Does not call SchedLock()/SchedUnlock()
  190. //
  191. Process_t *SelectSchedNext(void)
  192. {
  193. if (TimeCritProcs->length > 0) return GetNodeData(TimeCritProcs->first, Process_t *);
  194. if (ServPrioProcs->length > 0) return GetNodeData(ServPrioProcs->first, Process_t *);
  195. if (ReglPrioProcs->length > 0) return GetNodeData(ReglPrioProcs->first, Process_t *);
  196. if (IdlePrioProcs->length > 0) return GetNodeData(IdlePrioProcs->first, Process_t *);
  197.  
  198. return NULL;
  199. }
  200.  
  201. void PrintList(ListHead_t *head);
  202.  
  203. //
  204. // Remove running process from schedule lists
  205. // and schedule next runnable process
  206. //
  207. void BlockCurProc(void)
  208. {
  209. // SchedLock();
  210.  
  211. KalAssert(GetCurProc() && GetCurProc()->procState == STATE_RUNNING);
  212.  
  213. ListNode_t *procNode = GetCurProc()->schedNode;
  214.  
  215. GetCurProc()->procState = STATE_BLOCKED;
  216. RemoveNode(procNode->head, procNode);
  217.  
  218. SetCurProc(SelectSchedNext());
  219.  
  220. // SchedUnlock();
  221. }
  222.  
  223. //
  224. // Should we schedule another process?
  225. // Called at each tick
  226. //
  227. void SchedOnTick(void)
  228. {
  229. Process_t *procNext;
  230. Process_t *winner;
  231.  
  232. //
  233. // We're either idle or running something
  234. //
  235. KalAssert(GetCurProc() == NULL || GetCurProc()->procState == STATE_RUNNING);
  236.  
  237. SchedLock();
  238.  
  239. //
  240. // Has current process spent his timeslice?
  241. // (To be handled in CPU decisions function)
  242. //
  243. if (GetCurProc() != NULL) {
  244. if (GetCurProc()->timeSlice <= 1) {
  245.  
  246. // Update process info
  247. GetCurProc()->timeSlice = DEFAULT_PROC_TIMESLICE;
  248. GetCurProc()->procState = STATE_RUNNABLE;
  249.  
  250. // Remove from list
  251. RemoveNode(GetCurProc()->schedNode->head, GetCurProc()->schedNode);
  252.  
  253. // Add again to list
  254. SchedThisProc(GetCurProc());
  255.  
  256. // Mark as idle
  257. SetCurProc(NULL);
  258. }
  259.  
  260. //
  261. // Otherwise, make him lose a tick
  262. //
  263. else {
  264. GetCurProc()->timeSlice--;
  265. }
  266. }
  267.  
  268. //
  269. // Are we idle, or scheduling next process?
  270. //
  271. if (GetCurProc() == NULL) {
  272. SetCurProc(SelectSchedNext());
  273. goto leave;
  274. }
  275.  
  276. //
  277. // Is there a higher priority process that is runnable?
  278. //
  279. procNext = SelectSchedNext();
  280. winner = CompareProcs(GetCurProc(), procNext);
  281.  
  282. //
  283. // Yes, procNext should preempt current process
  284. //
  285. if (winner == procNext) {
  286. GetCurProc()->procState = STATE_RUNNABLE;
  287. SchedThisProc(GetCurProc());
  288. SetCurProc(procNext);
  289. }
  290.  
  291. //
  292. // Current process won't be preempted and has time remaining
  293. //
  294. leave:
  295. SchedUnlock();
  296. }
  297.  
  298. #define PrintProc(proc) printdbg("{ %d, '%s', %d , %d}\n", (proc)->pid, \
  299. PrioClassesNames[(proc)->prioClass], (proc)->prioLevel, (proc)->timeSlice);
  300.  
  301. //
  302. // Print out process list
  303. //
  304. void PrintList(ListHead_t *head)
  305. {
  306. KalAssert(head);
  307.  
  308. Process_t *proc;
  309. ListNode_t *node = head->first;
  310.  
  311. printdbg("len: %d\n", head->length);
  312.  
  313. while (node) {
  314. proc = GetNodeData(node, Process_t *);
  315.  
  316. PrintProc(proc);
  317.  
  318. node = node->next;
  319. }
  320.  
  321. puts("");
  322. }
  323.  
  324. //
  325. // Initialize scheduler
  326. //
  327. void InitSched(void)
  328. {
  329. int pid;
  330. Process_t *proc;
  331.  
  332. PrioClassesLock = malloc(sizeof(Lock_t));
  333. InitLock(PrioClassesLock, KLOCK_SPINLOCK);
  334.  
  335. TimeCritProcs = CreateListHeadWithLock(PrioClassesLock, 0);
  336. ServPrioProcs = CreateListHeadWithLock(PrioClassesLock, 0);
  337. ReglPrioProcs = CreateListHeadWithLock(PrioClassesLock, 0);
  338. IdlePrioProcs = CreateListHeadWithLock(PrioClassesLock, 0);
  339.  
  340. for (pid = 0; pid < procslen; pid++) {
  341. if (procs[pid].procState == STATE_RUNNABLE) {
  342. SchedThisProc(&procs[pid]);
  343. }
  344. }
  345. }
  346.  
  347. //
  348. // Shutdown scheduler
  349. //
  350. void FiniSched(void)
  351. {
  352. KalAssert(IdlePrioProcs && ReglPrioProcs && ServPrioProcs && TimeCritProcs);
  353.  
  354. while (IdlePrioProcs->length > 0) RemoveNode(IdlePrioProcs, IdlePrioProcs->first);
  355. while (ReglPrioProcs->length > 0) RemoveNode(ReglPrioProcs, ReglPrioProcs->first);
  356. while (ServPrioProcs->length > 0) RemoveNode(ServPrioProcs, ServPrioProcs->first);
  357. while (TimeCritProcs->length > 0) RemoveNode(TimeCritProcs, TimeCritProcs->first);
  358.  
  359. DestroyListHead(IdlePrioProcs); IdlePrioProcs = NULL;
  360. DestroyListHead(ReglPrioProcs); ReglPrioProcs = NULL;
  361. DestroyListHead(ServPrioProcs); ServPrioProcs = NULL;
  362. DestroyListHead(TimeCritProcs); TimeCritProcs = NULL;
  363.  
  364. free((void *)PrioClassesLock);
  365. }
  366.  
  367. #ifndef _KALEID_KERNEL
  368. int main(void)
  369. {
  370. InitSched();
  371.  
  372. puts("---------------");
  373.  
  374. puts("Time Critical:");
  375. PrintList(TimeCritProcs);
  376.  
  377. puts("Server:");
  378. PrintList(ServPrioProcs);
  379.  
  380. puts("Regular:");
  381. PrintList(ReglPrioProcs);
  382.  
  383. puts("Idle:");
  384. PrintList(IdlePrioProcs);
  385.  
  386. puts("---------------");
  387.  
  388. getchar();
  389.  
  390. int tick = 0;
  391.  
  392. while (tick < 20) {
  393. printf("\nTick %d\n", tick);
  394.  
  395. if (GetCurProc() == NULL) {
  396. puts("Currently IDLE");
  397. }
  398.  
  399. else {
  400. puts("Currently running process:");
  401. PrintProc(GetCurProc());
  402. }
  403.  
  404. if (tick == 9 || tick == 14) {
  405. puts("\nBlocking current process");
  406. BlockCurProc();
  407. }
  408.  
  409. SchedOnTick();
  410.  
  411. puts("\n---------------");
  412. tick++;
  413. }
  414.  
  415. FiniSched();
  416.  
  417. return 0;
  418. }
  419. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement