]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/m2/gm2-libs-coroutines/TimerHandler.mod
Merge modula-2 front end onto gcc.
[thirdparty/gcc.git] / gcc / m2 / gm2-libs-coroutines / TimerHandler.mod
1 (* TimerHandler.mod provides a simple timer handler for the Executive.
2
3 Copyright (C) 2002-2022 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
5
6 This file is part of GNU Modula-2.
7
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)
11 any later version.
12
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.
17
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.
21
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/>. *)
26
27 IMPLEMENTATION MODULE TimerHandler[MAX(PROTECTION)] ;
28
29
30 FROM COROUTINES IMPORT PROTECTION ;
31 FROM SysStorage IMPORT ALLOCATE ;
32 FROM NumberIO IMPORT CardToStr ;
33 FROM Debug IMPORT Halt, DebugString ;
34 FROM KeyBoardLEDs IMPORT SwitchScroll ;
35 FROM RTint IMPORT ReArmTimeVector, GetTimeVector, InitTimeVector ;
36 FROM Executive IMPORT DESCRIPTOR, Suspend, Resume, GetCurrentProcess,
37 WaitForIO, InitProcess, RotateRunQueue,
38 ProcessName, Ps ;
39
40 CONST
41 MaxQuantum = 4 ; (* Maximum ticks a process may consume *)
42 (* before being rescheduled. *)
43 BaseTicks = 1000000 ; (* Max resolution of clock ticks per sec *)
44 TimerStackSize = 100000H ; (* Reasonable sized stack for a process *)
45 Debugging = FALSE ; (* Do you want lots of debugging info? *)
46
47 TYPE
48 EVENT = POINTER TO RECORD
49 EventQ : Queue ;
50 WhichQ : QueueType ;
51 Process : DESCRIPTOR ;
52 NoOfTicks : CARDINAL ;
53 WasCancelled: BOOLEAN ;
54 END ;
55
56 (* the queue types are either:
57
58 active queue which has a list of outstanding events
59 dead queue which is essentially the free list
60 solo which is no queue and the event is in limbo
61 *)
62
63 QueueType = (active, dead, solo) ;
64
65 Queue = RECORD
66 Right,
67 Left : EVENT ;
68 END ;
69
70 VAR
71 TotalTicks : CARDINAL ; (* System up time tick count *)
72 CurrentQuanta : CARDINAL ; (* Currentprocess time quanta allowance *)
73 ActiveQueue, (* Queue of outstanding timer requests *)
74 DeadQueue : EVENT ; (* Free list of events. *)
75
76
77 (*
78 GetTicks - returns the number of ticks since boottime.
79 *)
80
81 PROCEDURE GetTicks () : CARDINAL ;
82 VAR
83 ToOldState : PROTECTION ;
84 CopyOfTicks: CARDINAL ;
85 BEGIN
86 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
87 CopyOfTicks := TotalTicks ;
88 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
89 RETURN( CopyOfTicks )
90 END GetTicks ;
91
92
93 (*
94 Sleep - suspends the current process for a time, t.
95 The time is measured in ticks.
96 *)
97
98 PROCEDURE Sleep (t: CARDINAL) ;
99 VAR
100 ToOldState: PROTECTION ;
101 e : EVENT ;
102 BEGIN
103 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
104 e := ArmEvent (t) ;
105 IF WaitOn (e)
106 THEN
107 END ;
108 (* ToOldState := TurnInterrupts(ToOldState) (* restore interrupts *) *)
109 END Sleep ;
110
111
112 (*
113 More lower system calls to the timer procedures follow,
114 they are necessary to allow handling multiple events.
115 *)
116
117
118 (*
119 ArmEvent - initializes an event, e, to occur at time, t.
120 The time, t, is measured in ticks.
121 The event is NOT placed onto the event queue.
122 *)
123
124 PROCEDURE ArmEvent (t: CARDINAL) : EVENT ;
125 VAR
126 e : EVENT ;
127 ToOldState: PROTECTION ;
128 Ticks : CARDINAL ;
129 BEGIN
130 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
131 e := CreateSolo() ;
132
133 (* your code needs to go here *)
134 WITH e^ DO (* remove for student *)
135 InitQueue(EventQ) ; (* not on a queue yet *) (* remove for student *)
136 WhichQ := solo ; (* and set the queue state accordingly *) (* remove for student *)
137 Process := NIL ; (* no process waiting event yet *) (* remove for student *)
138 NoOfTicks := t ; (* absolute number of ticks *) (* remove for student *)
139 WasCancelled := FALSE ; (* has not been cancelled *) (* remove for student *)
140 END ; (* remove for student *)
141
142 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
143 RETURN( e )
144 END ArmEvent ;
145
146
147 (*
148 WaitOn - places event, e, onto the event queue and then the calling
149 process suspends. It is resumed up by either the event
150 expiring or the event, e, being cancelled.
151 TRUE is returned if the event was cancelled
152 FALSE is returned if the event expires.
153 The event, e, is always assigned to NIL when the function
154 finishes.
155 *)
156
157 PROCEDURE WaitOn (VAR e: EVENT) : BOOLEAN ;
158 VAR
159 ToOldState: PROTECTION ;
160 Cancelled : BOOLEAN ;
161 BEGIN
162 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
163 IF e=NIL
164 THEN
165 Halt(__FILE__, __LINE__, __FUNCTION__,
166 'event should never be NIL')
167 ELSE
168 WITH e^ DO
169 (* we will just check to see whether someone has cancelled this *)
170 (* event before it ever got to the queue... *)
171 IF NOT WasCancelled
172 THEN
173 (* right so it wasn't cancelled. Lets place it on the queue and *)
174 (* go to sleep. *)
175 Process := GetCurrentProcess() ; (* so we know who is waiting *)
176 OnActiveQueue(e) ; (* add to the queue and then *)
177
178 IF Debugging
179 THEN
180 DisplayActive ; (* debugging *)
181 END ;
182
183 Suspend (* wait for Resume (we sleep) *)
184 END ;
185 (* At this point we have either been cancelled or not. We must *)
186 (* check the event again as we might have been sleeping (Suspend) *)
187 Cancelled := WasCancelled
188 END
189 END ;
190 OnDeadQueue(e) ; (* now it is safe to throw this event away *)
191 e := NIL ;
192 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
193 RETURN Cancelled
194 END WaitOn ;
195
196
197 (*
198 Cancel - cancels the event, e, on the event queue and makes
199 the appropriate process runnable again.
200 TRUE is returned if the event was cancelled and
201 FALSE is returned is the event was not found or
202 no process was waiting on this event.
203 *)
204
205 PROCEDURE Cancel (e: EVENT) : BOOLEAN ;
206 VAR
207 ToOldState: PROTECTION ;
208 Cancelled : BOOLEAN ;
209 Private : DESCRIPTOR ;
210 BEGIN
211 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
212 IF IsOnActiveQueue(e)
213 THEN
214 WITH e^ DO
215 Cancelled := NOT WasCancelled ;
216 IF WasCancelled
217 THEN
218 Halt(__FILE__, __LINE__, __FUNCTION__,
219 'inconsistancy event has been cancelled and it is on queue')
220 END ;
221 OnSoloQueue(e) ;
222 WasCancelled := TRUE ;
223 IF Process#NIL (* double check that it has not *)
224 (* already been cancelled *)
225 THEN
226 Private := Process ; (* we use our own Private variable *)
227 Process := NIL ; (* as we need to set Process to NIL *)
228 Process := Resume(Private) (* before we Resume. Otherwise *)
229 (* there is the possibility that it *)
230 (* might be reused before we := NIL *)
231 (* (because when we touch Resume *)
232 (* another process could run and..) *)
233 END
234 END
235 ELSE
236 Cancelled := FALSE
237 END ;
238 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
239 RETURN( Cancelled )
240 END Cancel ;
241
242
243 (*
244 ReArmEvent - removes an event, e, from the event queue. A new time
245 is given to this event and it is then re-inserted onto the
246 event queue in the correct place.
247 TRUE is returned if this occurred
248 FALSE is returned if the event was not found.
249 *)
250
251 PROCEDURE ReArmEvent (e: EVENT; t: CARDINAL) : BOOLEAN ;
252 VAR
253 ToOldState: PROTECTION ;
254 ReArmed : BOOLEAN ;
255 BEGIN
256 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; (* disable interrupts *) *)
257 WITH e^ DO
258 IF WasCancelled
259 THEN
260 ReArmed := FALSE
261 ELSIF IsOnActiveQueue(e) OR IsOnSoloQueue(e)
262 THEN
263 ReArmed := TRUE ;
264 OnSoloQueue(e) ; (* remove from queue *)
265 NoOfTicks := t ; (* give it a new time *)
266 OnActiveQueue(e) (* back on queue *)
267 ELSE
268 Halt(__FILE__, __LINE__, __FUNCTION__,
269 'ReArm should not be asked to ReArm a dead event')
270 END
271 END ;
272 (* ToOldState := TurnInterrupts(ToOldState) ; (* restore interrupts *) *)
273 RETURN( ReArmed )
274 END ReArmEvent ;
275
276
277 (*
278 StartClock - ticks is milli seconds.
279 *)
280
281 PROCEDURE StartClock (vec: CARDINAL; ticks: CARDINAL) ;
282 BEGIN
283 ReArmTimeVector (vec, ticks MOD BaseTicks, ticks DIV BaseTicks)
284 END StartClock ;
285
286
287 (*
288 LoadClock - returns the number of milli seconds.
289 *)
290
291 PROCEDURE LoadClock (vec: CARDINAL) : CARDINAL ;
292 VAR
293 micro, secs: CARDINAL ;
294 BEGIN
295 GetTimeVector (vec, micro, secs) ;
296 RETURN secs * BaseTicks + micro
297 END LoadClock ;
298
299
300 (*
301 Timer - is a process which serves the clock interrupt.
302 Its function is fourfold:
303
304 (i) to maintain the timer event queue
305 (ii) to give some fairness to processes via round robin scheduling
306 (iii) to keep a count of the total ticks so far (time of day)
307 (iv) provide a heartbeat sign of life via the scroll lock LED
308 *)
309
310 PROCEDURE Timer ;
311 VAR
312 CurrentCount: CARDINAL ;
313 ToOldState : PROTECTION ;
314 ScrollLED : BOOLEAN ;
315 TimerIntNo : CARDINAL ;
316 r : INTEGER ;
317 BEGIN
318 (* ToOldState := TurnInterrupts(MAX(PROTECTION)) ; *)
319 ScrollLED := FALSE ;
320 TimerIntNo := InitTimeVector ((BaseTicks DIV TicksPerSecond) MOD BaseTicks,
321 (BaseTicks DIV TicksPerSecond) DIV BaseTicks,
322 MAX (PROTECTION)) ;
323 LOOP
324 WaitForIO (TimerIntNo) ;
325
326 (* Get current clock count *)
327 CurrentCount := (* LoadClock(TimerIntNo) ; *) 0 ;
328 (* Now compenstate for lost ticks *)
329 StartClock (TimerIntNo, CurrentCount + (BaseTicks DIV TicksPerSecond)) ;
330
331 (* your code needs to go here *)
332 INC (TotalTicks) ; (* (iii) *) (* remove for student *)
333 (* now pulse scroll LED *) (* remove for student *)
334 IF (TotalTicks MOD TicksPerSecond) = 0 (* remove for student *)
335 THEN (* remove for student *)
336 ScrollLED := NOT ScrollLED ; (* remove for student *)
337 (* r := printf("<scroll %d>", TotalTicks); *)
338 SwitchScroll(ScrollLED) (* (iv) *) (* remove for student *)
339 END ; (* remove for student *)
340 IF (TotalTicks MOD MaxQuantum) = 0 (* remove for student *)
341 THEN (* remove for student *)
342 RotateRunQueue (* (ii) *) (* remove for student *)
343 END ; (* remove for student *)
344
345 CheckActiveQueue (* (i) *) (* remove for student *)
346 END
347 END Timer ;
348
349
350 (*
351 CheckActiveQueue - purpose is:
352
353 (i) to remove all events which have expired
354 (ii) resume all processes waiting on these events
355 (iii) decrement the first event with a non zero NoOfTicks
356 *)
357
358 PROCEDURE CheckActiveQueue ;
359 VAR
360 e : EVENT ;
361 Private: DESCRIPTOR ;
362 BEGIN
363 IF Debugging
364 THEN
365 DebugString('inside CheckActiveQueue\n') ;
366 DisplayActive
367 END ;
368 WHILE (ActiveQueue#NIL) AND (ActiveQueue^.NoOfTicks=0) DO (* (i) *)
369 e := ActiveQueue ;
370 OnSoloQueue(e) ;
371 (* note we do not put it onto the dead queue. The process
372 waiting for the event will place, e, onto the dead queue *)
373 WITH e^ DO
374 IF (NOT WasCancelled) AND (Process#NIL)
375 THEN
376 Private := Process ; (* we use our own Private variable *)
377 Process := NIL ; (* as we might context switch in *)
378 Process := Resume(Private) ; (* resume. (ii) *)
379 IF Debugging
380 THEN
381 Ps
382 END
383 END
384 END
385 END ;
386 IF ActiveQueue#NIL
387 THEN
388 DEC(ActiveQueue^.NoOfTicks) (* (iii) *)
389 END ;
390 IF Debugging
391 THEN
392 DebugString('after CheckActiveQueue\n') ;
393 DisplayActive
394 END ;
395 END CheckActiveQueue ;
396
397
398 (*
399 CreateSolo - create a new event. It does this by either getting an event from
400 the dead queue or (if the dead queue is empty) an event is created
401 by using NEW.
402 *)
403
404 PROCEDURE CreateSolo () : EVENT ;
405 VAR
406 e: EVENT ;
407 BEGIN
408 IF DeadQueue=NIL
409 THEN
410 NEW(e)
411 ELSE
412 e := DeadQueue ;
413 SubFrom(DeadQueue, e)
414 END ;
415 e^.WhichQ := solo ;
416 RETURN( e )
417 END CreateSolo ;
418
419
420 (*
421 RemoveFromDead - removes event, e, from the dead queue.
422 *)
423
424 PROCEDURE RemoveFromDead (e: EVENT) ;
425 BEGIN
426 SubFrom(DeadQueue, e)
427 END RemoveFromDead ;
428
429
430 (*
431 OnDeadQueue - places an event onto the dead queue.
432 *)
433
434 PROCEDURE OnDeadQueue (e: EVENT) ;
435 BEGIN
436 IF e#NIL
437 THEN
438 OnSoloQueue(e) ; (* put on solo queue first *)
439 AddTo(DeadQueue, e) ; (* now safe to put on dead queue *)
440 e^.WhichQ := dead
441 END
442 END OnDeadQueue ;
443
444
445 (*
446 OnSoloQueue - places an event onto the solo queue.
447 *)
448
449 PROCEDURE OnSoloQueue (e: EVENT) ;
450 BEGIN
451 IF e#NIL
452 THEN
453 IF IsOnActiveQueue(e)
454 THEN
455 RemoveFromActive(e)
456 ELSIF IsOnDeadQueue(e)
457 THEN
458 RemoveFromDead(e)
459 END ;
460 e^.WhichQ := solo
461 END
462 END OnSoloQueue ;
463
464
465 (*
466 OnActiveQueue - places an event onto the active queue.
467 *)
468
469 PROCEDURE OnActiveQueue (e: EVENT) ;
470 BEGIN
471 IF e#NIL
472 THEN
473 IF IsOnDeadQueue(e)
474 THEN
475 Halt(__FILE__, __LINE__, __FUNCTION__, 'illegal state change')
476 ELSIF IsOnSoloQueue(e)
477 THEN
478 RelativeAddToActive(e) ;
479 e^.WhichQ := active
480 END
481 END
482 END OnActiveQueue ;
483
484
485 (*
486 IsOnSoloQueue - returns TRUE if event, e, is on the solo queue.
487 *)
488
489 PROCEDURE IsOnSoloQueue (e: EVENT) : BOOLEAN ;
490 BEGIN
491 RETURN( (e#NIL) AND (e^.WhichQ=solo) )
492 END IsOnSoloQueue ;
493
494
495 (*
496 IsOnDeadQueue - returns TRUE if event, e, is on the dead queue.
497 *)
498
499 PROCEDURE IsOnDeadQueue (e: EVENT) : BOOLEAN ;
500 BEGIN
501 RETURN( (e#NIL) AND (e^.WhichQ=dead) )
502 END IsOnDeadQueue ;
503
504
505 (*
506 IsOnActiveQueue - returns TRUE if event, e, is on the active queue.
507 *)
508
509 PROCEDURE IsOnActiveQueue (e: EVENT) : BOOLEAN ;
510 BEGIN
511 RETURN( (e#NIL) AND (e^.WhichQ=active) )
512 END IsOnActiveQueue ;
513
514
515 (*
516 RemoveFromActive - removes an event, e, from the active queue.
517 *)
518
519 PROCEDURE RemoveFromActive (e: EVENT) ;
520 BEGIN
521 IF ActiveQueue=e
522 THEN
523 SubFrom(ActiveQueue, e) ;
524 (* providing that the ActiveQueue is non empty we need to
525 modify first event ticks as we have removed the first event, e. *)
526 IF ActiveQueue#NIL
527 THEN
528 INC(ActiveQueue^.NoOfTicks, e^.NoOfTicks)
529 END
530 ELSE
531 (* providing that event, e, is not the last event on the list then
532 update the next event by the time of, e. *)
533 IF e^.EventQ.Right#ActiveQueue
534 THEN
535 INC(e^.EventQ.Right^.NoOfTicks, e^.NoOfTicks)
536 END ;
537 SubFrom(ActiveQueue, e)
538 END
539 END RemoveFromActive ;
540
541
542 (*
543 InsertBefore - insert an event, new, on a circular event queue BEFORE
544 event, pos.
545 *)
546
547 PROCEDURE InsertBefore (VAR Head: EVENT; pos, new: EVENT) ;
548 BEGIN
549 IF Head=NIL
550 THEN
551 (* empty queue *)
552 Head := new ;
553 new^.EventQ.Right := new ;
554 new^.EventQ.Left := new
555 ELSIF Head=pos
556 THEN
557 (* insert before the first element on the queue *)
558 new^.EventQ.Right := pos ;
559 new^.EventQ.Left := pos^.EventQ.Left ;
560 pos^.EventQ.Left^.EventQ.Right := new ;
561 pos^.EventQ.Left := new ;
562 Head := new
563 ELSE
564 (* insert before any other element *)
565 new^.EventQ.Right := pos ;
566 new^.EventQ.Left := pos^.EventQ.Left ;
567 pos^.EventQ.Left^.EventQ.Right := new ;
568 pos^.EventQ.Left := new
569 END
570 END InsertBefore ;
571
572
573 (*
574 InsertAfter - place an event, new, AFTER the event pos on any circular event queue.
575 *)
576
577 PROCEDURE InsertAfter (pos, new: EVENT) ;
578 BEGIN
579 new^.EventQ.Right := pos^.EventQ.Right ;
580 new^.EventQ.Left := pos ;
581 pos^.EventQ.Right^.EventQ.Left := new ;
582 pos^.EventQ.Right := new
583 END InsertAfter ;
584
585
586 (*
587 RelativeAddToActive - the active event queue is an ordered queue of
588 relative time events.
589 The event, e, is inserted at the appropriate
590 position in the queue. The event, e, enters
591 this routine with an absolute NoOfTicks field which
592 is then used to work out the relative position
593 of the event. After the position is found then
594 the absolute NoOfTicks field is altered to a
595 relative value and inserted on the queue.
596 *)
597
598 PROCEDURE RelativeAddToActive (e: EVENT) ;
599 VAR
600 t : EVENT ;
601 sum: CARDINAL ;
602 BEGIN
603 IF ActiveQueue = NIL
604 THEN
605 (* simple as the queue is empty (relative=absolute) *)
606 InsertBefore (ActiveQueue, ActiveQueue, e)
607 ELSE
608 (* at the end of the while loop sum will contain the total of all
609 events up to but not including, t.
610 If the value of sum is < e^.NoOfTicks then e must be placed at the end
611 >= e^.NoOfTicks then e needs to be placed in the middle
612 *)
613
614 sum := ActiveQueue^.NoOfTicks ;
615 t := ActiveQueue^.EventQ.Right ; (* second event *)
616 WHILE (sum < e^.NoOfTicks) AND (t # ActiveQueue) DO
617 INC (sum, t^.NoOfTicks) ;
618 t := t^.EventQ.Right
619 END ;
620 IF sum < e^.NoOfTicks
621 THEN
622 (* e will occur after all the current ActiveQueue has expired therefore
623 we must add it to the end of the ActiveQueue. *)
624 DEC (e^.NoOfTicks, sum) ;
625 InsertAfter (ActiveQueue^.EventQ.Left, e)
626 ELSE
627 (* as sum >= e^.NoOfTicks we know that e is scheduled to occur
628 in the middle of the queue but before t^.Left
629 *)
630 DEC (e^.NoOfTicks, sum-t^.EventQ.Left^.NoOfTicks) ;
631 InsertBefore (ActiveQueue, t^.EventQ.Left, e)
632 END ;
633 (* the first event after e must have its relative NoOfTicks altered *)
634 IF e^.EventQ.Right # ActiveQueue
635 THEN
636 DEC (e^.EventQ.Right^.NoOfTicks, e^.NoOfTicks)
637 END
638 END
639 END RelativeAddToActive ;
640
641
642 (*
643 AddTo - adds an event to a specified queue.
644 *)
645
646 PROCEDURE AddTo (VAR Head: EVENT; e: EVENT) ;
647 BEGIN
648 IF Head=NIL
649 THEN
650 Head := e ;
651 e^.EventQ.Left := e ;
652 e^.EventQ.Right := e
653 ELSE
654 e^.EventQ.Right := Head ;
655 e^.EventQ.Left := Head^.EventQ.Left ;
656 Head^.EventQ.Left^.EventQ.Right := e ;
657 Head^.EventQ.Left := e
658 END
659 END AddTo ;
660
661
662 (*
663 SubFrom - removes an event from a queue.
664 *)
665
666 PROCEDURE SubFrom (VAR Head: EVENT; e: EVENT) ;
667 BEGIN
668 IF (e^.EventQ.Left = Head) AND (e = Head)
669 THEN
670 Head := NIL
671 ELSE
672 IF Head = e
673 THEN
674 Head := Head^.EventQ.Right
675 END ;
676 e^.EventQ.Left^.EventQ.Right := e^.EventQ.Right ;
677 e^.EventQ.Right^.EventQ.Left := e^.EventQ.Left
678 END
679 END SubFrom ;
680
681
682 (*
683 DisplayActive - display the active queue.
684 *)
685
686 PROCEDURE DisplayActive ;
687 VAR
688 e: EVENT ;
689 BEGIN
690 e := ActiveQueue ;
691 IF e#NIL
692 THEN
693 REPEAT
694 DisplayEvent(e) ;
695 e := e^.EventQ.Right
696 UNTIL e=ActiveQueue
697 END
698 END DisplayActive ;
699
700
701 (*
702 DisplayEvent - display a single event, e.
703 *)
704
705 PROCEDURE DisplayEvent (e: EVENT) ;
706 VAR
707 a: ARRAY [0..20] OF CHAR ;
708 BEGIN
709 WITH e^ DO
710 CardToStr(NoOfTicks, 6, a) ;
711 DebugString(a) ;
712 DebugString(' process (') ;
713 IF Process=NIL
714 THEN
715 DebugString('is NIL') ;
716 ELSE
717 ProcessName(Process)
718 END ;
719 DebugString(')') ;
720 IF WasCancelled
721 THEN
722 DebugString(' has been cancelled')
723 END
724 END ;
725 DebugString('\n')
726 END DisplayEvent ;
727
728
729 (*
730 InitQueue -
731 *)
732
733 PROCEDURE InitQueue (VAR q: Queue) ;
734 BEGIN
735 q.Right := NIL ;
736 q.Left := NIL
737 END InitQueue ;
738
739
740 (*
741 Init - starts the timer process and initializes some queues.
742 *)
743
744 PROCEDURE Init ;
745 VAR
746 d: DESCRIPTOR ;
747 BEGIN
748 TotalTicks := 0 ;
749 CurrentQuanta := 0 ;
750 ActiveQueue := NIL ;
751 DeadQueue := NIL ;
752 d := Resume(InitProcess(Timer, TimerStackSize, 'Timer'))
753 END Init ;
754
755
756 BEGIN
757 Init
758 END TimerHandler.