1 (* RTint.mod provides users of the COROUTINES library with the.
3 Copyright (C) 2009-2023 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 RTint ;
30 FROM M2RTS IMPORT Halt ;
31 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
32 FROM RTco IMPORT select, initSemaphore, wait, signal ;
33 FROM COROUTINES IMPORT PROTECTION ;
34 FROM libc IMPORT printf, perror ;
35 FROM Assertion IMPORT Assert ;
37 FROM Selective IMPORT InitSet, FdSet, Timeval, InitTime, KillTime, KillSet,
38 SetOfFd, FdIsSet, GetTime, FdZero, GetTimeOfDay, SetTime,
42 Microseconds = 1000000 ;
47 VectorType = (input, output, time) ;
48 Vector = POINTER TO RECORD
64 Pending : ARRAY [MIN(PROTECTION)..MAX(PROTECTION)] OF Vector ;
66 initialized: BOOLEAN ;
70 Max - returns the maximum: i or j.
73 PROCEDURE Max (i, j: INTEGER) : INTEGER ;
85 Max - returns the minimum: i or j.
88 PROCEDURE Min (i, j: INTEGER) : INTEGER ;
100 FindVector - searches the exists list for a vector of type, t,
101 which is associated with file descriptor, fd.
104 PROCEDURE FindVector (fd: INTEGER; t: VectorType) : Vector ;
110 IF (v^.type=t) AND (v^.File=fd)
121 InitInputVector - returns an interrupt vector which is associated
122 with the file descriptor, fd.
125 PROCEDURE InitInputVector (fd: INTEGER; pri: CARDINAL) : CARDINAL ;
131 printf("InitInputVector fd = %d priority = %d\n", fd, pri)
134 v := FindVector(fd, input) ;
155 END InitInputVector ;
159 InitOutputVector - returns an interrupt vector which is associated
160 with the file descriptor, fd.
163 PROCEDURE InitOutputVector (fd: INTEGER; pri: CARDINAL) : CARDINAL ;
168 v := FindVector (fd, output) ;
194 END InitOutputVector ;
198 InitTimeVector - returns an interrupt vector associated with
202 PROCEDURE InitTimeVector (micro, secs: CARDINAL; pri: CARDINAL) : CARDINAL ;
213 Assert (micro<Microseconds) ;
221 rel := InitTime(secs+DebugTime, micro) ;
222 abs := InitTime(0, 0) ;
233 FindVectorNo - searches the Exists list for vector, vec.
236 PROCEDURE FindVectorNo (vec: CARDINAL) : Vector ;
241 WHILE (v#NIL) AND (v^.no#vec) DO
249 FindPendingVector - searches the pending list for vector, vec.
252 PROCEDURE FindPendingVector (vec: CARDINAL) : Vector ;
257 FOR i := MIN(PROTECTION) TO MAX(PROTECTION) DO
259 WHILE (v#NIL) AND (v^.no#vec) DO
262 IF (v#NIL) AND (v^.no=vec)
268 END FindPendingVector ;
272 ReArmTimeVector - reprimes the vector, vec, to deliver an interrupt
273 at the new relative time.
276 PROCEDURE ReArmTimeVector (vec: CARDINAL;
277 micro, secs: CARDINAL) ;
281 Assert(micro<Microseconds) ;
283 v := FindVectorNo(vec) ;
286 Halt(__FILE__, __LINE__, __FUNCTION__,
287 'cannot find vector supplied')
290 SetTime (rel, secs + DebugTime, micro)
294 END ReArmTimeVector ;
298 GetTimeVector - assigns, micro, and, secs, with the remaining
299 time before this interrupt will expire.
300 This value is only updated when a Listen
304 PROCEDURE GetTimeVector (vec: CARDINAL; VAR micro, secs: CARDINAL) ;
309 v := FindVectorNo (vec) ;
312 Halt(__FILE__, __LINE__, __FUNCTION__,
313 'cannot find vector supplied')
316 GetTime (rel, secs, micro) ;
317 Assert (micro < Microseconds)
325 AttachVector - adds the pointer, p, to be associated with the interrupt
326 vector. It returns the previous value attached to this
330 PROCEDURE AttachVector (vec: CARDINAL; p: ADDRESS) : ADDRESS ;
336 v := FindVectorNo (vec) ;
339 Halt (__FILE__, __LINE__, __FUNCTION__, 'cannot find vector supplied')
345 printf ("AttachVector %d with 0x%x\n", vec, p);
355 IncludeVector - includes, vec, into the dispatcher list of
356 possible interrupt causes.
359 PROCEDURE IncludeVector (vec: CARDINAL) ;
366 v := FindPendingVector (vec) ;
369 v := FindVectorNo (vec) ;
372 Halt (__FILE__, __LINE__, __FUNCTION__,
373 'cannot find vector supplied') ;
375 (* printf('including vector %d (fd = %d)\n', vec, v^.File) ; *)
376 v^.pending := Pending[v^.priority] ;
377 Pending[v^.priority] := v ;
378 IF (v^.type = time) AND (NOT v^.queued)
381 r := GetTimeOfDay (v^.abs) ;
383 GetTime (v^.abs, s, m) ;
384 Assert (m<Microseconds) ;
385 AddTime (v^.abs, v^.rel) ;
386 GetTime (v^.abs, s, m) ;
387 Assert (m<Microseconds)
393 printf ('odd vector (%d) type (%d) arg (0x%x) is already attached to the pending queue\n',
394 vec, v^.type, v^.arg)
403 ExcludeVector - excludes, vec, from the dispatcher list of
404 possible interrupt causes.
407 PROCEDURE ExcludeVector (vec: CARDINAL) ;
412 v := FindPendingVector(vec) ;
415 Halt (__FILE__, __LINE__, __FUNCTION__,
416 'cannot find pending vector supplied')
418 (* printf('excluding vector %d\n', vec) ; *)
419 IF Pending[v^.priority]=v
421 Pending[v^.priority] := Pending[v^.priority]^.pending
423 u := Pending[v^.priority] ;
424 WHILE u^.pending#v DO
427 u^.pending := v^.pending
439 AddFd - adds the file descriptor, fd, to set, s, updating, max.
442 PROCEDURE AddFd (VAR s: SetOfFd; VAR max: INTEGER; fd: INTEGER) ;
444 max := Max (fd, max) ;
451 (* printf('%d, ', fd) *)
456 DumpPendingQueue - displays the pending queue.
459 PROCEDURE DumpPendingQueue ;
465 printf ("Pending queue\n");
466 FOR p := MIN (PROTECTION) TO MAX (PROTECTION) DO
470 IF (v^.type=input) OR (v^.type=output)
472 printf ("(fd=%d) (vec=%d)", v^.File, v^.no)
475 GetTime(v^.rel, s, m) ;
476 Assert (m<Microseconds) ;
477 printf ("time (%u.%06u secs) (arg = 0x%x)\n", s, m, v^.arg)
483 END DumpPendingQueue ;
492 AddTime - t1 := t1 + t2
495 PROCEDURE AddTime (t1, t2: Timeval) ;
497 a, b, s, m: CARDINAL ;
500 Assert (m < Microseconds) ;
502 Assert (b < Microseconds) ;
507 DEC (b, Microseconds) ;
515 IsGreaterEqual - returns TRUE if, a>=b
518 PROCEDURE IsGreaterEqual (a, b: Timeval) : BOOLEAN ;
520 as, am, bs, bm: CARDINAL ;
522 GetTime (a, as, am) ;
523 Assert (am < Microseconds) ;
524 GetTime (b, bs, bm) ;
525 Assert (bm < Microseconds) ;
526 RETURN (as > bs) OR ((as = bs) AND (am >= bm))
531 SubTime - assigns, s and m, to a - b.
534 PROCEDURE SubTime (VAR s, m: CARDINAL; a, b: Timeval) ;
539 GetTime (a, as, am) ;
540 Assert (am < Microseconds) ;
541 GetTime (b, bs, bm) ;
542 Assert (bm < Microseconds) ;
543 IF IsGreaterEqual (a, b)
549 Assert (m < Microseconds) ;
553 m := (Microseconds + am) - bm ;
554 Assert (m < Microseconds)
564 activatePending - activates the first interrupt pending and clears it.
567 PROCEDURE activatePending (untilInterrupt: BOOLEAN; call: DispatchVector; pri: CARDINAL;
568 maxFd: INTEGER; VAR i, o: SetOfFd; VAR t: Timeval; b4, after: Timeval) : BOOLEAN ;
580 p := MAX (PROTECTION) ;
587 input : IF (File < maxFd) AND (i # NIL) AND FdIsSet (File, i)
591 printf ('read (fd=%d) is ready (vec=%d)\n', File, no) ;
594 FdClr (File, i) ; (* so we dont activate this again from our select. *)
596 call (no, priority, arg) ;
599 output: IF (File < maxFd) AND (o#NIL) AND FdIsSet (File, o)
603 printf ('write (fd=%d) is ready (vec=%d)\n', File, no) ;
606 FdClr (File, o) ; (* so we dont activate this again from our select. *)
608 call (no, priority, arg) ;
611 time : IF untilInterrupt AND (t # NIL)
613 r := GetTimeOfDay (after) ;
618 Assert (m < Microseconds) ;
619 GetTime (after, afs, afm) ;
620 Assert (afm < Microseconds) ;
621 GetTime (b4, b4s, b4m) ;
622 Assert (b4m < Microseconds) ;
623 printf ("waited %u.%06u + %u.%06u now is %u.%06u\n",
624 s, m, b4s, b4m, afs, afm) ;
626 IF IsGreaterEqual (after, abs)
631 printf ("time has expired calling dispatcher\n")
633 t := KillTime (t) ; (* so we dont activate this again from our select. *)
637 printf ("call (%d, %d, 0x%x)\n", no, priority, arg)
639 call (no, priority, arg) ;
643 printf ("must wait longer as time has not expired\n")
654 END activatePending ;
658 Listen - will either block indefinitely (until an interrupt)
659 or alteratively will test to see whether any interrupts
661 If a pending interrupt was found then, call, is called
662 and then this procedure returns.
663 It only listens for interrupts > pri.
666 PROCEDURE Listen (untilInterrupt: BOOLEAN;
667 call: DispatchVector;
686 IF pri < MAX (PROTECTION)
696 t := InitTime (MAX (INTEGER), 0) ;
697 p := MAX (PROTECTION) ;
705 input : AddFd (i, maxFd, File) |
706 output: AddFd (o, maxFd, File) |
707 time : IF IsGreaterEqual (t, abs)
709 GetTime (abs, s, m) ;
710 Assert (m<Microseconds) ;
713 printf ("shortest delay is %u.%06u\n", s, m)
725 IF NOT untilInterrupt
729 IF untilInterrupt AND (i=NIL) AND (o=NIL) AND (NOT found)
731 Halt (__FILE__, __LINE__, __FUNCTION__,
732 'deadlock found, no more processes to run and no interrupts active')
734 (* printf('timeval = 0x%x\n', t) ; *)
735 (* printf('}\n') ; *)
736 IF (NOT found) AND (maxFd=-1) AND (i=NIL) AND (o=NIL)
738 (* no file descriptors to be selected upon. *)
744 Assert (m<Microseconds) ;
745 b4 := InitTime (0, 0) ;
746 after := InitTime (0, 0) ;
747 r := GetTimeOfDay (b4) ;
749 SubTime (s, m, t, b4) ;
753 printf ("select waiting for %u.%06u seconds\n", s, m)
759 printf ("select (.., .., .., %u.%06u)\n", s, m)
761 r := select (maxFd+1, i, o, NIL, t) ;
765 r := select (maxFd+1, i, o, NIL, NIL) ;
768 perror ("select timeout argument is faulty")
770 r := select (maxFd+1, i, NIL, NIL, t) ;
773 perror ("select output fd argument is faulty")
775 r := select (maxFd+1, NIL, o, NIL, t) ;
778 perror ("select input fd argument is faulty")
780 perror ("select maxFD+1 argument is faulty")
785 WHILE activatePending (untilInterrupt, call, pri,
786 maxFd+1, i, o, t, b4, after) DO
794 t := KillTime (after)
821 lock := initSemaphore (1) ;
824 FOR p := MIN(PROTECTION) TO MAX(PROTECTION) DO
827 initialized := TRUE ;