1 (* Executive.mod provides a simple multitasking executive.
3 Copyright (C) 2002-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. *)
27 IMPLEMENTATION MODULE Executive
[MAX(PROTECTION
)] ;
29 FROM SYSTEM
IMPORT ADDRESS
, PROCESS
, LISTEN
, ADR
,
30 NEWPROCESS
, TRANSFER
, IOTRANSFER
, ListenLoop
,
33 FROM COROUTINES
IMPORT PROTECTION
;
34 FROM SysStorage
IMPORT ALLOCATE
, DEALLOCATE
;
35 FROM StrLib
IMPORT StrCopy
;
36 FROM StrLib
IMPORT StrLen
;
37 FROM NumberIO
IMPORT CardToStr
;
38 FROM Debug
IMPORT DebugString
, Halt
;
46 IdleStackSize
= 16 * 1024 * 1024 ;
49 SEMAPHORE
= POINTER TO Semaphore
; (* defines dijkstra's semaphores *)
51 Value
: CARDINAL ; (* semaphore value *)
52 SemName
: EntityName
; (* semaphore name for debugging *)
53 Who
: DESCRIPTOR
; (* queue of waiting processes *)
54 ExistsQ
: SemQueue
; (* list of existing semaphores *)
57 DESCRIPTOR
= POINTER TO Descriptor
; (* handle onto a process *)
59 Volatiles
: PROCESS
; (* process volatile environment *)
60 ReadyQ
: DesQueue
; (* queue of ready processes *)
61 ExistsQ
: DesQueue
; (* queue of existing processes *)
62 SemaphoreQ
: DesQueue
; (* queue of waiting processes *)
63 Which
: SEMAPHORE
; (* which semaphore are we waiting*)
64 RunName
: EntityName
; (* process name for debugging *)
65 Status
: State
; (* state of process *)
66 RunPriority
: Priority
; (* runtime priority of process *)
67 Size
: CARDINAL ; (* Maximum stack size *)
68 Start
: ADDRESS
; (* Stack start *)
69 Debugged
: BOOLEAN ; (* Does user want to debug a *)
70 (* deadlocked process? *)
83 EntityName
= ARRAY [0..MaxCharsInName
] OF CHAR ;
85 Priority
= (idle
, lo
, hi
) ; (* process run priority *)
87 State
= (Runnable
, Suspended
, WaitOnSem
, WaitOnInt
) ;
90 ExistsQueue
: DESCRIPTOR
; (* List of existing processes *)
91 RunQueue
: ARRAY Priority
OF DESCRIPTOR
;
92 (* List of runnable processes *)
93 CurrentProcess
: DESCRIPTOR
;
94 AllSemaphores
: SEMAPHORE
; (* List of all semaphores *)
95 GarbageItem
: DESCRIPTOR
; (* Descriptor destined to free *)
102 PROCEDURE Assert (c
: BOOLEAN; file
: ARRAY OF CHAR; line
: CARDINAL;
103 function
: ARRAY OF CHAR) ;
108 Halt ('assert failed', file
, function
, line
)
114 InitProcess - initializes a process which is held in the suspended
115 state. When the process is resumed it will start executing
116 procedure, p. The process has a maximum stack size of,
117 StackSize, bytes and its textual name is, Name.
118 The StackSize should be at least 5000 bytes.
121 PROCEDURE InitProcess (p
: PROC;
123 Name
: ARRAY OF CHAR) : DESCRIPTOR
;
126 ToOldState
: PROTECTION
;
127 db
: ARRAY [0.
.80] OF CHAR ;
129 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
133 (* allocate space for this processes stack *)
134 ALLOCATE(Start
, StackSize
) ;
135 NEWPROCESS(p
, Start
, StackSize
, Volatiles
) ; (* create volatiles *)
136 InitQueue(ReadyQ
) ; (* not on the ready queue as suspended *)
137 AddToExists(d
) ; (* add process to the exists queue *)
138 InitQueue(SemaphoreQ
) ; (* not on a semaphore queue yet *)
139 Which
:= NIL ; (* not on a semaphore queue yet *)
140 StrCopy(Name
, RunName
) ; (* copy name into descriptor for debugging *)
141 Status
:= Suspended
; (* this process will be suspended *)
142 RunPriority
:= lo
; (* all processes start off at lo priority *)
143 Debugged
:= FALSE ; (* no need to debug deadlock yet! *)
145 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
146 RETURN( d
) (* and return a descriptor to the caller *)
151 KillProcess - kills the current process. Notice that if InitProcess
152 is called again, it might reuse the DESCRIPTOR of the
153 killed process. It is the responsibility of the caller
154 to ensure all other processes understand this process
158 PROCEDURE KillProcess
;
160 ToOldState
: PROTECTION
;
162 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
163 SubFromReady(CurrentProcess
) ;
164 SubFromExists(ExistsQueue
, CurrentProcess
) ;
165 GarbageItem
:= CurrentProcess
;
167 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
172 Resume - resumes a suspended process. If all is successful then the process, p,
173 is returned. If it fails then NIL is returned.
176 PROCEDURE Resume (d
: DESCRIPTOR
) : DESCRIPTOR
;
178 ToOldState
: PROTECTION
;
180 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
184 (* legal state transition *)
185 Status
:= Runnable
; (* change status *)
186 AddToReady(d
) ; (* add to run queue *)
187 RunQueue
[RunPriority
] := d
; (* make d at top of q *)
188 Reschedule (* check whether this process has a higher run priority *)
190 (* we are trying to Resume a process which is *)
191 Halt ('trying to resume a process which is not suspended',
192 __FILE__
, __FUNCTION__
, __LINE__
) ;
193 RETURN( NIL ) (* not held in a Suspended state - error *)
196 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
202 Suspend - suspend the calling process.
203 The process can only continue running if another process
209 ToOldState
: PROTECTION
;
211 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
212 WITH CurrentProcess^
DO
215 SubFromReady(CurrentProcess
) ;
217 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
222 InitSemaphore - creates a semaphore whose initial value is, v, and
226 PROCEDURE InitSemaphore (v
: CARDINAL; Name
: ARRAY OF CHAR) : SEMAPHORE
;
229 ToOldState
: PROTECTION
;
231 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
234 Value
:= v
; (* initial value of semaphore *)
235 StrCopy(Name
, SemName
) ; (* save the name for future debugging *)
236 Who
:= NIL ; (* no one waiting on this semaphore yet *)
237 AddToSemaphoreExists(s
) ; (* add semaphore to exists list *)
239 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
245 Wait - performs dijkstra's P operation on a semaphore.
246 A process which calls this procedure will
247 wait until the value of the semaphore is > 0
248 and then it will decrement this value.
251 PROCEDURE Wait (s
: SEMAPHORE
) ;
253 ToOldState
: PROTECTION
;
255 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
261 SubFromReady(CurrentProcess
) ; (* remove from run q *)
262 IF Who
=CurrentProcess
265 Halt ('we are already on sem',
266 __FILE__
, __FUNCTION__
, __LINE__
)
268 AddToSemaphore(Who
, CurrentProcess
) ; (* add to semaphore q *)
269 CurrentProcess^.Status
:= WaitOnSem
; (* set new status *)
270 CurrentProcess^.Which
:= s
; (* debugging aid *)
271 Reschedule (* find next process *)
274 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
279 Signal - performs dijkstra's V operation on a semaphore.
280 A process which calls the procedure will increment
281 the semaphores value.
284 PROCEDURE Signal (s
: SEMAPHORE
) ;
286 ToOldState
: PROTECTION
;
289 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
293 INC( Value
) (* no process waiting *)
295 d
:= SubFromSemaphoreTop(Who
) ; (* remove process from semaphore q *)
296 d^.Which
:= NIL ; (* no longer waiting on semaphore *)
297 d^.Status
:= Runnable
; (* set new status *)
298 AddToReady(d
) ; (* add process to the run queue *)
299 Reschedule (* find out whether there is a *)
300 (* higher priority to run. *)
303 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
308 WaitForIO - waits for an interrupt to occur on vector, VectorNo.
311 PROCEDURE WaitForIO (VectorNo
: CARDINAL) ;
313 Calling
: DESCRIPTOR
;
315 ToOldState
: PROTECTION
;
318 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; *)
320 DebugString('inside WaitForIO ') ;
321 DebugString(CurrentProcess^.RunName) ;
324 Assert(CurrentProcess^.Status
=Runnable
,
325 __FILE__
, __LINE__
, __FUNCTION__
) ;
326 SubFromReady(CurrentProcess
) ; (* remove process from run queue *)
328 alter run priority to hi as all processes waiting for an interrupt
329 are scheduled to run at the highest priority.
331 WITH CurrentProcess^
DO
332 Status
:= WaitOnInt
; (* it will be blocked waiting for an interrupt. *)
333 RunPriority
:= hi
; (* this (hopefully) allows it to run as soon as *)
334 (* the interrupt occurs. *)
336 Calling
:= CurrentProcess
; (* process which called WaitForIO *)
337 CurrentProcess
:= NextReady() ; (* find next process to run while we wait *)
338 Next
:= CurrentProcess^.Volatiles
;
340 This is quite complicated. We transfer control to the next process saving
341 our volatile environment into the Calling process descriptor volatiles.
342 When an interrupt occurs the calling process will be resumed and the
343 interrupted process volatiles will be placed into Next.
345 IOTRANSFER(Calling^.Volatiles
, Next
, VectorNo
) ;
348 At this point the interrupt has just occurred and the volatiles of
349 the interrupted process are in Next. Next is the current process
350 and so we must save them before picking up the Calling descriptor.
353 CurrentProcess^.Volatiles
:= Next
; (* carefully stored away *)
354 CurrentProcess
:= Calling
; (* update CurrentProcess *)
356 DebugString(CurrentProcess^.RunName) ;
358 CurrentProcess^.Status
:= Runnable
; (* add to run queue *)
359 AddToReady(CurrentProcess
) ;
361 DebugString(' finishing WaitForIO\n') ;
364 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
369 Ps - displays a process list together with relevant their status.
374 ToOldState
: PROTECTION
;
377 a
: ARRAY [0.
.5] OF CHAR ;
379 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
385 p
:= p^.ExistsQ.Right
393 DebugString(SemName
) ;
394 WriteNSpaces(MaxCharsInName
-StrLen(SemName
)) ;
395 CardToStr(Value
, 0, a
) ;
399 s
:= s^.ExistsQ.Right
400 UNTIL s
=AllSemaphores
402 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
407 DisplayProcess - displays the process, p, together with its status.
410 PROCEDURE DisplayProcess (p
: DESCRIPTOR
) ;
412 a
: ARRAY [0.
.4] OF CHAR ;
415 DebugString(RunName
) ; WriteNSpaces(MaxCharsInName
-StrLen(RunName
)) ;
418 idle
: DebugString(' idle ') |
419 lo
: DebugString(' lo ') |
420 hi
: DebugString(' hi ')
425 Runnable
: DebugString('runnable ') |
426 Suspended
: DebugString('suspended') |
427 WaitOnSem
: DebugString('waitonsem (') ;
428 DebugString(Which^.SemName
) ;
430 WaitOnInt
: DebugString('waitonint')
439 WriteNSpaces - writes, n, spaces.
442 PROCEDURE WriteNSpaces (n
: CARDINAL) ;
452 GetCurrentProcess - returns the descriptor of the current running
456 PROCEDURE GetCurrentProcess () : DESCRIPTOR
;
458 ToOldState
: PROTECTION
;
461 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
462 p
:= CurrentProcess
;
463 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
465 END GetCurrentProcess
;
469 RotateRunQueue - rotates the process run queue.
472 PROCEDURE RotateRunQueue
;
474 ToOldState
: PROTECTION
;
476 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
477 (* we only need to rotate the lo priority processes as:
478 idle - should only have one process (the idle process)
479 hi - are the device drivers which most of the time are performing
484 RunQueue
[lo
] := RunQueue
[lo
]^.ReadyQ.Right
486 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
491 ProcessName - displays the name of process, d, through
495 PROCEDURE ProcessName (d
: DESCRIPTOR
) ;
497 DebugString(d^.RunName
)
505 PROCEDURE DebugProcess (d
: DESCRIPTOR
) ;
507 ToOldState
: PROTECTION
;
509 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; *)
513 DebugString('debugging process (') ;
514 DebugString(RunName
) ;
515 DebugString(') was waiting on semaphore (') ;
516 DebugString(Which^.SemName
) ;
518 SubFromSemaphore(Which^.Who
, d
) ;
524 DebugString('can only debug deadlocked processes (') ;
525 DebugString(RunName
) ;
526 DebugString(') which are waiting on a semaphore\n')
529 (* ToOldState := TurnInterrupts(ToOldState) *)
534 CheckDebugged - checks to see whether the debugged flag has
535 been set by the debugger.
536 TRUE is returned if the process was debugged.
537 FALSE is returned if the process was not debugged.
540 PROCEDURE CheckDebugged () : BOOLEAN ;
542 WITH CurrentProcess^
DO
546 You will see this comment after you have enabled a
547 deadlocked process to continue via the gdb command:
549 print Executive_DebugProcess(d)
551 debugger caused deadlocked process to continue
553 (* gdb.breakpoint ; *)
555 SubFromReady(CurrentProcess
) ;
556 AddToSemaphore(Which^.Who
, CurrentProcess
) ;
557 (* add it back to the queue sem *)
558 Status
:= WaitOnSem
;
568 Reschedule - reschedules to the highest runnable process.
571 PROCEDURE Reschedule
;
574 the repeat loop allows us to debug a process even when it is
575 technically waiting on a semaphore. We run the process into
576 a breakpoint and then back into this schedule routine.
577 This is really useful when trying to find out why processes have
582 UNTIL NOT CheckDebugged()
587 ScheduleProcess - finds the highest priority Runnable process and
588 then transfers control to it.
591 PROCEDURE ScheduleProcess
;
594 Highest
: DESCRIPTOR
;
596 Highest
:= NextReady() ;
598 (* rotate ready Q to ensure fairness *)
599 RunQueue
[Highest^.RunPriority
] := Highest^.ReadyQ.Right
;
601 (* no need to transfer if Highest=CurrentProcess *)
602 IF Highest#CurrentProcess
604 From
:= CurrentProcess
;
606 DebugString('context switching from ') ; DebugString(From^.RunName) ;
608 (* alter CurrentProcess before we TRANSFER *)
609 CurrentProcess
:= Highest
;
611 DebugString(' to ') ; DebugString(CurrentProcess^.RunName) ;
614 TRANSFER(From^.Volatiles
, Highest^.Volatiles
) ;
616 ; DebugString(' (') ; DebugString(CurrentProcess^.RunName) ;
621 END ScheduleProcess
;
625 NextReady - returns the highest priority Runnable process.
628 PROCEDURE NextReady () : DESCRIPTOR
;
630 Highest
: DESCRIPTOR
;
634 FOR Pri
:= idle
TO hi
DO
637 Highest
:= RunQueue
[Pri
]
640 Assert(Highest#
NIL, __FILE__
, __LINE__
, __FUNCTION__
) ;
646 CheckGarbageCollect - checks to see whether GarbageItem is set
647 and if so it deallocates storage associated
648 with this descriptor.
651 PROCEDURE CheckGarbageCollect
;
656 DEALLOCATE(Start
, Size
)
658 DISPOSE(GarbageItem
) ;
661 END CheckGarbageCollect
;
665 AddToExists - adds item, Item, to the exists queue.
668 PROCEDURE AddToExists (Item
: DESCRIPTOR
) ;
672 ExistsQueue
:= Item
; (* Head is empty therefore make *)
673 Item^.ExistsQ.Left
:= Item
; (* Item the only entry on this *)
674 Item^.ExistsQ.Right
:= Item (* queue. *)
676 Item^.ExistsQ.Right
:= ExistsQueue
; (* Add Item to the end of queue *)
677 Item^.ExistsQ.Left
:= ExistsQueue^.ExistsQ.Left
;
678 ExistsQueue^.ExistsQ.Left^.ExistsQ.Right
:= Item
;
679 ExistsQueue^.ExistsQ.Left
:= Item
685 SubFromExists - removes a process, Item, from the exists queue, Head.
688 PROCEDURE SubFromExists (VAR Head
: DESCRIPTOR
; Item
: DESCRIPTOR
) ;
690 IF (Item^.ExistsQ.Right
=Head
) AND (Item
=Head
)
696 Head
:= Head^.ExistsQ.Right
698 Item^.ExistsQ.Left^.ExistsQ.Right
:= Item^.ExistsQ.Right
;
699 Item^.ExistsQ.Right^.ExistsQ.Left
:= Item^.ExistsQ.Left
705 AddToSemaphore - adds item, Item, to the semaphore queue defined by Head.
708 PROCEDURE AddToSemaphore (VAR Head
: DESCRIPTOR
; Item
: DESCRIPTOR
) ;
712 Head
:= Item
; (* Head is empty therefore make *)
713 Item^.SemaphoreQ.Left
:= Item
; (* Item the only entry on this *)
714 Item^.SemaphoreQ.Right
:= Item (* queue. *)
716 Item^.SemaphoreQ.Right
:= Head
; (* Add Item to the end of queue *)
717 Item^.SemaphoreQ.Left
:= Head^.SemaphoreQ.Left
;
718 Head^.SemaphoreQ.Left^.SemaphoreQ.Right
:= Item
;
719 Head^.SemaphoreQ.Left
:= Item
725 AddToSemaphoreExists - adds item, Item, to the semaphore exists queue.
728 PROCEDURE AddToSemaphoreExists (Item
: SEMAPHORE
) ;
732 AllSemaphores
:= Item
; (* Head is empty therefore make *)
733 Item^.ExistsQ.Left
:= Item
; (* Item the only entry on this *)
734 Item^.ExistsQ.Right
:= Item (* queue. *)
736 Item^.ExistsQ.Right
:= AllSemaphores
;
737 (* Add Item to the end of queue *)
738 Item^.ExistsQ.Left
:= AllSemaphores^.ExistsQ.Left
;
739 AllSemaphores^.ExistsQ.Left^.ExistsQ.Right
:= Item
;
740 AllSemaphores^.ExistsQ.Left
:= Item
742 END AddToSemaphoreExists
;
746 AddToReady - adds item, Item, to the ready queue.
749 PROCEDURE AddToReady (Item
: DESCRIPTOR
) ;
751 AddToReadyQ(RunQueue
[Item^.RunPriority
], Item
)
756 AddToReadyQ - adds item, Item, to the ready queue defined by Head.
759 PROCEDURE AddToReadyQ (VAR Head
: DESCRIPTOR
; Item
: DESCRIPTOR
) ;
763 Head
:= Item
; (* Head is empty therefore make *)
764 Item^.ReadyQ.Left
:= Item
; (* Item the only entry on this *)
765 Item^.ReadyQ.Right
:= Item (* queue. *)
767 Item^.ReadyQ.Right
:= Head
; (* Add Item to the end of queue *)
768 Item^.ReadyQ.Left
:= Head^.ReadyQ.Left
;
769 Head^.ReadyQ.Left^.ReadyQ.Right
:= Item
;
770 Head^.ReadyQ.Left
:= Item
776 SubFromReady - subtract process descriptor, Item, from the Ready queue.
779 PROCEDURE SubFromReady (Item
: DESCRIPTOR
) ;
781 SubFromReadyQ(RunQueue
[Item^.RunPriority
], Item
)
786 SubFromReadyQ - removes a process, Item, from a queue, Head.
789 PROCEDURE SubFromReadyQ (VAR Head
: DESCRIPTOR
; Item
: DESCRIPTOR
) ;
791 IF (Item^.ReadyQ.Right
=Head
) AND (Item
=Head
)
797 Head
:= Head^.ReadyQ.Right
799 Item^.ReadyQ.Left^.ReadyQ.Right
:= Item^.ReadyQ.Right
;
800 Item^.ReadyQ.Right^.ReadyQ.Left
:= Item^.ReadyQ.Left
806 SubFromSemaphoreTop - returns the first descriptor in the
810 PROCEDURE SubFromSemaphoreTop (VAR Head
: DESCRIPTOR
) : DESCRIPTOR
;
815 SubFromSemaphore(Head
, Top
) ;
817 END SubFromSemaphoreTop
;
821 SubFromSemaphore - removes a process, Item, from a queue, Head.
824 PROCEDURE SubFromSemaphore (VAR Head
: DESCRIPTOR
; Item
: DESCRIPTOR
) ;
826 IF (Item^.SemaphoreQ.Right
=Head
) AND (Item
=Head
)
832 Head
:= Head^.SemaphoreQ.Right
834 Item^.SemaphoreQ.Left^.SemaphoreQ.Right
:= Item^.SemaphoreQ.Right
;
835 Item^.SemaphoreQ.Right^.SemaphoreQ.Left
:= Item^.SemaphoreQ.Left
837 END SubFromSemaphore
;
841 Idle - this process is only run whenever there is no other Runnable
842 process. It should never be removed from the run queue.
847 ToOldState
: PROTECTION
;
849 ToOldState
:= TurnInterrupts(MIN(PROTECTION
)) ; (* enable interrupts *)
852 Listen for interrupts.
853 We could solve chess endgames here or calculate PI etc.
854 We forever wait for an interrupt since there is nothing else
859 (* we must NEVER exit from the above loop *)
864 InitIdleProcess - creates an idle process descriptor which
865 is run whenever no other process is Runnable.
866 The Idle process should be the only process which
867 has the priority idle.
871 IdleProcess
: DESCRIPTOR
; (* Idle process always runnable *)
873 PROCEDURE InitIdleProcess
;
875 db
: ARRAY [0.
.80] OF CHAR ;
879 ALLOCATE(Start
, IdleStackSize
) ;
880 Size
:= IdleStackSize
;
881 NEWPROCESS(Idle
, Start
, IdleStackSize
, Volatiles
) ;
882 InitQueue(SemaphoreQ
) ; (* not on a semaphore queue *)
883 Which
:= NIL ; (* at all. *)
884 StrCopy('Idle', RunName
) ; (* idle process's name *)
885 Status
:= Runnable
; (* should always be idle *)
886 RunPriority
:= idle
; (* lowest priority possible *)
887 Debugged
:= FALSE ; (* should never be debugging *)
889 AddToReady(IdleProcess
) ; (* should be the only *)
890 (* process at this run priority *)
891 AddToExists(IdleProcess
) (* process now exists.. *)
892 END InitIdleProcess
;
896 InitInitProcess - creates a descriptor for this running environment
897 so it too can be manipulated by Reschedule.
899 This concept is important to understand.
900 InitInitProcess is called by the startup code to this
901 module. It ensures that the current stack and processor
902 volatiles can be "housed" in a process descriptor and
903 therefore it can be manipulated just like any other
907 PROCEDURE InitInitProcess
;
909 NEW(CurrentProcess
) ;
910 WITH CurrentProcess^
DO
911 Size
:= 0 ; (* we dont know the size of main stack *)
912 Start
:= NIL ; (* we don't need to know where it is. *)
913 InitQueue(ReadyQ
) ; (* assign queues to NIL *)
915 InitQueue(SemaphoreQ
) ; (* not waiting on a semaphore queue yet *)
916 Which
:= NIL ; (* at all. *)
917 StrCopy('Init', RunName
) ; (* name for debugging purposes *)
918 Status
:= Runnable
; (* currently running *)
919 RunPriority
:= lo
; (* default status *)
920 Debugged
:= FALSE ; (* not deadlock debugging yet *)
922 AddToExists(CurrentProcess
) ;
923 AddToReady(CurrentProcess
)
924 END InitInitProcess
;
928 InitQueue - initializes a queue, q, to empty.
931 PROCEDURE InitQueue (VAR q
: DesQueue
) ;
941 Init - initializes all the global variables.
947 RunQueue
[lo
] := NIL ;
948 RunQueue
[hi
] := NIL ;
949 RunQueue
[idle
] := NIL ;
950 AllSemaphores
:= NIL ;