process.mod 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. (* Copyright (C) 1987 Jensen & Partners International *)
  2. (*$V-,S-,R-,I-*)
  3. IMPLEMENTATION MODULE Process;
  4. FROM SYSTEM IMPORT PROCESS,NEWPROCESS,TRANSFER,IOTRANSFER,EI,DI,
  5. GetFlags,SetFlags,CurrentProcess,Out;
  6. FROM Storage IMPORT ALLOCATE;
  7. FROM Lib IMPORT Terminate;
  8. TYPE
  9. Task = POINTER TO TaskDescriptor;
  10. SIGNAL = POINTER TO SigRec;
  11. SigRec = RECORD
  12. count : INTEGER;
  13. waiting : Task;
  14. END;
  15. TaskDescriptor = RECORD
  16. next : Task; (* queue of waiting Process *)
  17. priority : CARDINAL;
  18. cor : PROCESS;
  19. due : CARDINAL;
  20. nextdue : Task;
  21. END;
  22. VAR
  23. cp : Task; (* currently active task + ready queue *)
  24. dq : Task; (* queue of delayed tasks *)
  25. wq : Task; (* queue of tasks that have reached thier delay time
  26. but haven't been placed on the ready queue *)
  27. SchedProc : PROCESS;
  28. SchedStack : ADDRESS;
  29. Started : BOOLEAN;
  30. (*$W+*) (* Volatile variables *)
  31. VAR
  32. Stop : BOOLEAN;
  33. LockNest : CARDINAL; (* No of nested locks *)
  34. (* only safe to slice if zero *)
  35. SchedTime : CARDINAL;
  36. (*$W-*)
  37. PROCEDURE QInsert(T: Task; VAR Q: Task);
  38. (* inserts task after last task in Q with greater or equal priority *)
  39. VAR
  40. q,qb : Task;
  41. BEGIN
  42. q := Q;
  43. qb := NIL;
  44. WHILE (q<>NIL)AND(T^.priority<=q^.priority) DO
  45. qb := q;
  46. q := q^.next;
  47. END;
  48. IF qb=NIL THEN
  49. Q := T;
  50. ELSE
  51. qb^.next := T;
  52. END;
  53. T^.next := q;
  54. END QInsert;
  55. PROCEDURE AddReadyProcess(T: Task);
  56. (* adds new process to ready list
  57. NB gets added ahead of current process if at same priority
  58. *)
  59. VAR
  60. mp : PROCESS;
  61. oldcp : Task;
  62. ie : CARDINAL;
  63. BEGIN
  64. ie := GetFlags(); DI;
  65. IF cp=NIL THEN
  66. QInsert(T,cp); (* add new process *)
  67. ELSE
  68. oldcp := cp; (* remove current process *)
  69. cp := cp^.next;
  70. QInsert(T,cp); (* add new process *)
  71. QInsert(oldcp,cp); (* add current process *)
  72. END;
  73. mp := cp^.cor;
  74. TRANSFER (mp,mp);
  75. SetFlags(ie);
  76. END AddReadyProcess;
  77. PROCEDURE StartProcess(P: PROC; N: CARDINAL; Pr: CARDINAL);
  78. VAR
  79. t0 : Task; wsp: ADDRESS;
  80. np : Task;
  81. BEGIN
  82. t0 := cp;
  83. ALLOCATE (wsp, N);
  84. ALLOCATE (np, SIZE(TaskDescriptor));
  85. np^.priority := Pr;
  86. NEWPROCESS (P, wsp, N , np^.cor);
  87. AddReadyProcess(np);
  88. END StartProcess;
  89. PROCEDURE SEND(s: SIGNAL);
  90. VAR
  91. t0 : Task;
  92. ie : CARDINAL;
  93. BEGIN
  94. ie := GetFlags(); DI;
  95. IF s^.count <> MAX(INTEGER) THEN
  96. INC(s^.count);
  97. IF s^.count <= 0 THEN (* somebody waiting *)
  98. t0 := s^.waiting;
  99. s^.waiting := t0^.next;
  100. AddReadyProcess(t0);
  101. END;
  102. END;
  103. SetFlags(ie);
  104. END SEND;
  105. PROCEDURE Notify(s: SIGNAL);
  106. VAR
  107. t0 : Task;
  108. ie : CARDINAL;
  109. BEGIN
  110. ie := GetFlags(); DI;
  111. IF s^.count < 0 THEN (* somebody waiting *)
  112. INC(s^.count);
  113. t0 := s^.waiting;
  114. s^.waiting := t0^.next;
  115. (* add to waiting q *)
  116. t0^.nextdue := wq;
  117. wq := t0;
  118. END;
  119. SetFlags(ie);
  120. END Notify;
  121. PROCEDURE WAIT (s: SIGNAL);
  122. VAR
  123. t0 : Task;
  124. mp : PROCESS;
  125. ie : CARDINAL;
  126. BEGIN (* insert cp in queue s *)
  127. ie := GetFlags(); DI;
  128. DEC(s^.count);
  129. IF s^.count < 0 THEN (* wait *)
  130. t0 := cp;
  131. cp := cp^.next;
  132. QInsert(t0,s^.waiting);
  133. mp := cp^.cor;
  134. TRANSFER (mp,mp);
  135. END;
  136. SetFlags(ie);
  137. END WAIT;
  138. PROCEDURE Awaited(s: SIGNAL) : BOOLEAN;
  139. BEGIN
  140. RETURN (s^.count<0);
  141. END Awaited;
  142. PROCEDURE Init(VAR s: SIGNAL);
  143. BEGIN
  144. NEW(s);
  145. s^.waiting := NIL;
  146. s^.count := 0;
  147. END Init;
  148. PROCEDURE CheckTimeQ;
  149. VAR
  150. ta,tb,tn : Task;
  151. BEGIN
  152. ta := dq;
  153. tb := NIL;
  154. WHILE ta <> NIL DO
  155. tn := ta^.nextdue;
  156. IF ta^.due = SchedTime THEN
  157. IF tb = NIL THEN dq := tn ELSE tb^.nextdue := tn END;
  158. ta^.nextdue := wq;
  159. wq := ta;
  160. ELSE
  161. tb := ta;
  162. END;
  163. ta := tn;
  164. END;
  165. END CheckTimeQ;
  166. PROCEDURE Slice;
  167. (* Clears waiting queue *)
  168. (* Then schedules next ready process if it is of equal priority *)
  169. VAR
  170. nextt,oldt,ta : Task;
  171. BEGIN
  172. IF LockNest = 0 THEN
  173. (* move waiting queue to the ready queue *)
  174. (* set up by CheckTimeQueue *)
  175. WHILE wq <> NIL DO
  176. ta := wq; wq := wq^.nextdue;
  177. QInsert(ta,cp);
  178. END;
  179. (* now do slice *)
  180. nextt := cp^.next;
  181. IF (nextt <> NIL) AND (nextt^.priority = cp^.priority) THEN (* slice *)
  182. oldt := cp; cp := nextt;
  183. QInsert(oldt,cp); (* insert old cp at end of processes *)
  184. END;
  185. END;
  186. END Slice;
  187. MODULE SS[1]; (* IRQ 1: timer interrupt *)
  188. IMPORT Stop,Task,PROCESS,IOTRANSFER,TRANSFER,SchedTime,cp,DI,
  189. Slice,CheckTimeQ;
  190. EXPORT Scheduler;
  191. PROCEDURE Scheduler;
  192. VAR
  193. nextt,
  194. oldt : Task;
  195. op,np : PROCESS;
  196. Int8 : PROC;
  197. TYPE
  198. code = ARRAY[0..2] OF SHORTCARD;
  199. CONST
  200. Int8code = code(0CDH,08H,0CBH); (* INT 08H / RETF *)
  201. BEGIN
  202. DI;
  203. Int8 := PROC(ADR(Int8code));
  204. Stop := FALSE;
  205. SchedTime := 0;
  206. LOOP
  207. np := cp^.cor;
  208. LOOP
  209. IOTRANSFER(op,np,8);
  210. Int8;
  211. INC(SchedTime);
  212. IF Stop THEN EXIT END;
  213. CheckTimeQ;
  214. Slice;
  215. np := cp^.cor;
  216. END;
  217. Stop := FALSE;
  218. TRANSFER(op,np); (* no return until restarted *)
  219. END;
  220. END Scheduler;
  221. END SS;
  222. PROCEDURE Idler; (* always on cp chain *)
  223. VAR
  224. i : CARDINAL;
  225. BEGIN
  226. LOOP INC(i);
  227. END;
  228. END Idler;
  229. PROCEDURE StartScheduler;
  230. VAR
  231. ie : CARDINAL;
  232. BEGIN
  233. ie := GetFlags(); DI;
  234. IF NOT Started THEN
  235. Started := TRUE;
  236. IF SchedStack = NIL THEN (* first time *)
  237. ALLOCATE( SchedStack, 512 );
  238. NEWPROCESS( Scheduler, SchedStack, 512, SchedProc );
  239. END;
  240. TRANSFER( cp^.cor, SchedProc );
  241. END;
  242. SetFlags(ie);
  243. END StartScheduler;
  244. PROCEDURE StopScheduler;
  245. VAR
  246. ie : CARDINAL;
  247. BEGIN
  248. ie := GetFlags();
  249. IF Started THEN
  250. EI ;
  251. Started := FALSE;
  252. Stop := TRUE;
  253. WHILE Stop DO END;
  254. END;
  255. SetFlags(ie);
  256. END StopScheduler;
  257. PROCEDURE Delay(T: CARDINAL);
  258. (* Waits T time slices *)
  259. (* 0 will swap to next process of equal priority, without delaying *)
  260. VAR
  261. mp : PROCESS;
  262. ie : CARDINAL;
  263. BEGIN
  264. ie := GetFlags(); DI;
  265. IF T = 0 THEN
  266. mp := cp^.cor;
  267. Slice;
  268. IF mp = cp^.cor THEN
  269. SetFlags(ie);
  270. RETURN
  271. END; (* no other processes ready *)
  272. ELSE
  273. cp^.due := SchedTime + T;
  274. cp^.nextdue := dq;
  275. dq := cp;
  276. cp := cp^.next;
  277. END;
  278. mp := cp^.cor;
  279. TRANSFER(mp,mp);
  280. SetFlags(ie);
  281. END Delay;
  282. PROCEDURE Lock;
  283. (* Critical region lock - prevents timeslicing *)
  284. (* may be nested *)
  285. BEGIN
  286. INC(LockNest);
  287. END Lock;
  288. PROCEDURE Unlock;
  289. (* Unlock procedure, always paired with a call to Lock.
  290. Will de-schedule current process if there are ready processes
  291. of equal priority *)
  292. VAR
  293. ie : CARDINAL;
  294. BEGIN
  295. ie := GetFlags(); DI;
  296. IF LockNest <= 1 THEN
  297. LockNest := 0; Delay(0);
  298. ELSE
  299. DEC(LockNest);
  300. END;
  301. SetFlags(ie);
  302. END Unlock;
  303. VAR
  304. Continue : PROC;
  305. PROCEDURE CloseDown;
  306. BEGIN
  307. StopScheduler;
  308. Continue;
  309. END CloseDown;
  310. BEGIN
  311. dq := NIL;
  312. wq := NIL;
  313. NEW(cp);
  314. cp^.next := NIL;
  315. cp^.priority := 1;
  316. cp^.cor := CurrentProcess();
  317. StartProcess( Idler, 512 , 0 );
  318. SchedStack := NIL;
  319. Started := FALSE;
  320. LockNest := 0;
  321. Terminate(CloseDown,Continue);
  322. END Process.
  323.