1 (* SYSTEM.mod provides access to COROUTINE primitives and underlying system.
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 SYSTEM
;
29 FROM RTco
IMPORT init
, initThread
, transfer
, currentThread
, turnInterrupts
;
31 FROM RTint
IMPORT Listen
, AttachVector
,
32 IncludeVector
, ExcludeVector
;
36 FROM Storage
IMPORT ALLOCATE
;
37 FROM M2RTS
IMPORT Halt
;
38 FROM libc
IMPORT printf
, memcpy
, memset
;
42 BitsPerBitset
= MAX (BITSET) +1 ;
45 PtrToIOTransferState
= POINTER TO IOTransferState
;
46 IOTransferState
= RECORD
48 ptrToSecond
: POINTER TO PROCESS
;
49 next
: PtrToIOTransferState
;
58 TRANSFER - save the current volatile environment into, p1.
59 Restore the volatile environment from, p2.
62 PROCEDURE TRANSFER (VAR p1
: PROCESS
; p2
: PROCESS
) ;
67 IF p1.context
=p2.context
69 Halt('error when attempting to context switch to the same process',
70 __FILE__
, __FUNCTION__
, __LINE__
)
72 transfer (p1.context
, p2.context
)
77 NEWPROCESS - p is a parameterless procedure, a, is the origin of
78 the workspace used for the process stack and containing
79 the volatile environment of the process. StackSize, is
80 the maximum size of the stack in bytes which can be used
81 by this process. new, is the new process.
84 PROCEDURE NEWPROCESS (p
: PROC; a
: ADDRESS
; StackSize
: CARDINAL; VAR new
: PROCESS
) ;
88 context
:= initThread (p
, StackSize
, MAX(PROTECTION
))
94 IOTRANSFER - saves the current volatile environment into, First,
95 and restores volatile environment, Second.
96 When an interrupt, InterruptNo, is encountered then
97 the reverse takes place. (The then current volatile
98 environment is shelved onto Second and First is resumed).
100 NOTE: that upon interrupt the Second might not be the
101 same process as that before the original call to
105 PROCEDURE IOTRANSFER (VAR First
, Second
: PROCESS
; InterruptNo
: CARDINAL) ;
108 l
: POINTER TO IOTransferState
;
112 ptrToFirst
:= ADR (First
) ;
113 ptrToSecond
:= ADR (Second
) ;
114 next
:= AttachVector (InterruptNo
, ADR (p
))
116 IncludeVector (InterruptNo
) ;
117 TRANSFER (First
, Second
)
122 IOTransferHandler - handles interrupts related to a pending IOTRANSFER.
125 PROCEDURE IOTransferHandler (InterruptNo
: CARDINAL;
127 l
: PtrToIOTransferState
) ;
129 old
: PtrToIOTransferState
;
133 Halt ('no processes attached to this interrupt vector which is associated with IOTRANSFER',
134 __FILE__
, __FUNCTION__
, __LINE__
)
137 old
:= AttachVector (InterruptNo
, next
) ;
140 Halt ('inconsistancy of return result',
141 __FILE__
, __FUNCTION__
, __LINE__
)
145 ExcludeVector (InterruptNo
)
147 printf ('odd vector has been chained\n')
149 TRANSFER (ptrToSecond^
, ptrToFirst^
)
152 END IOTransferHandler
;
156 LISTEN - briefly listen for any interrupts.
162 Listen (FALSE, IOTransferHandler
, MIN (PROTECTION
))
167 ListenLoop - should be called instead of users writing:
173 It performs the same function but yields
174 control back to the underlying operating system.
175 It also checks for deadlock.
176 This function returns when an interrupt occurs.
177 (File descriptor becomes ready or time event expires).
180 PROCEDURE ListenLoop
;
184 Listen (TRUE, IOTransferHandler
, MIN (PROTECTION
))
190 TurnInterrupts - switches processor interrupts to the
191 protection level, to. It returns the old value.
194 PROCEDURE TurnInterrupts (to
: PROTECTION
) : PROTECTION
;
199 old
:= VAL (PROTECTION
, turnInterrupts (VAL (CARDINAL, to
))) ;
200 Listen (FALSE, IOTransferHandler
, to
) ;
201 (* printf ("interrupt level is %d\n", currentIntValue); *)
207 Finished - generates an error message. Modula-2 processes should never
211 PROCEDURE Finished (p
: ADDRESS
) ;
213 Halt('process terminated illegally',
214 __FILE__
, __FUNCTION__
, __LINE__
)
219 localInit - checks to see whether we need to initialize pthread
222 PROCEDURE localInit
;
229 Halt ("gthr did not initialize",
230 __FILE__
, __FUNCTION__
, __LINE__
)
238 localMain - creates the holder for the main process.
241 PROCEDURE localMain (VAR mainProcess
: PROCESS
) ;
247 context
:= currentThread ()
254 Max - returns the maximum of a and b.
257 PROCEDURE Max (a
, b
: CARDINAL) : CARDINAL ;
269 Min - returns the minimum of a and b.
272 PROCEDURE Min (a
, b
: CARDINAL) : CARDINAL ;
284 ShiftVal - is a runtime procedure whose job is to implement
285 the SHIFT procedure of ISO SYSTEM. GNU Modula-2 will
286 inline a SHIFT of a single WORD sized set and will only
287 call this routine for larger sets.
290 PROCEDURE ShiftVal (VAR s
, d
: ARRAY OF BITSET;
291 SetSizeInBits
: CARDINAL;
292 ShiftCount
: INTEGER) ;
298 ShiftCount
:= ShiftCount
MOD VAL(INTEGER, SetSizeInBits
) ;
299 ShiftLeft (s
, d
, SetSizeInBits
, ShiftCount
)
302 ShiftCount
:= (-ShiftCount
) MOD VAL(INTEGER, SetSizeInBits
) ;
303 ShiftRight (s
, d
, SetSizeInBits
, ShiftCount
)
305 a
:= memcpy (ADR (d
), ADR (s
), (HIGH (d
) + 1) * SIZE (BITSET))
311 ShiftLeft - performs the shift left for a multi word set.
312 This procedure might be called by the back end of
313 GNU Modula-2 depending whether amount is known at compile
317 PROCEDURE ShiftLeft (VAR s
, d
: ARRAY OF BITSET;
318 SetSizeInBits
: CARDINAL;
319 ShiftCount
: CARDINAL) ;
326 IF ShiftCount
MOD BitsPerBitset
=0
328 i
:= ShiftCount
DIV BitsPerBitset
;
330 a
:= memcpy (a
, ADR (s
), (h
-i
) * SIZE (BITSET)) ;
331 a
:= memset (ADR (d
), 0, i
* SIZE (BITSET))
336 lo
:= SHIFT (s
[i
], ShiftCount
MOD BitsPerBitset
) ;
337 hi
:= SHIFT (s
[i
], -(BitsPerBitset
- (ShiftCount
MOD BitsPerBitset
))) ;
339 j
:= i
+ ShiftCount
DIV BitsPerBitset
;
355 ShiftRight - performs the shift left for a multi word set.
356 This procedure might be called by the back end of
357 GNU Modula-2 depending whether amount is known at compile
361 PROCEDURE ShiftRight (VAR s
, d
: ARRAY OF BITSET;
362 SetSizeInBits
: CARDINAL;
363 ShiftCount
: CARDINAL) ;
370 IF ShiftCount
MOD BitsPerBitset
=0
372 i
:= ShiftCount
DIV BitsPerBitset
;
375 a
:= memcpy (ADR (d
), a
, j
* VAL (INTEGER, SIZE(BITSET))) ;
377 a
:= memset (a
, 0, i
* VAL (INTEGER, SIZE(BITSET)))
381 lo
:= SHIFT(s
[i
], BitsPerBitset
- (ShiftCount
MOD BitsPerBitset
)) ;
382 hi
:= SHIFT(s
[i
], -(ShiftCount
MOD BitsPerBitset
)) ;
384 j
:= i
- VAL(INTEGER, ShiftCount
DIV BitsPerBitset
) ;
401 RotateVal - is a runtime procedure whose job is to implement
402 the ROTATE procedure of ISO SYSTEM. GNU Modula-2 will
403 inline a ROTATE of a single WORD (or less)
404 sized set and will only call this routine for larger sets.
407 PROCEDURE RotateVal (VAR s
, d
: ARRAY OF BITSET;
408 SetSizeInBits
: CARDINAL;
409 RotateCount
: INTEGER) ;
415 RotateLeft(s
, d
, SetSizeInBits
, RotateCount
)
418 RotateRight(s
, d
, SetSizeInBits
, -RotateCount
)
420 a
:= memcpy(ADR(d
), ADR(s
), (HIGH(d
)+1)*SIZE(BITSET))
426 RotateLeft - performs the rotate left for a multi word set.
427 This procedure might be called by the back end of
428 GNU Modula-2 depending whether amount is known at compile
432 PROCEDURE RotateLeft (VAR s
, d
: ARRAY OF BITSET;
433 SetSizeInBits
: CARDINAL;
434 RotateCount
: CARDINAL) ;
437 b
, i
, j
, h
: CARDINAL ;
440 (* firstly we set d := {} *)
447 RotateCount
:= RotateCount
MOD SetSizeInBits
;
448 b
:= SetSizeInBits
MOD BitsPerBitset
;
455 lo
:= SHIFT(s
[i
], RotateCount
MOD BitsPerBitset
) ;
456 hi
:= SHIFT(s
[i
], -(b
- (RotateCount
MOD BitsPerBitset
))) ;
457 j
:= ((i
*BitsPerBitset
+ RotateCount
) MOD
458 SetSizeInBits
) DIV BitsPerBitset
;
460 j
:= (((i
+1)*BitsPerBitset
+ RotateCount
) MOD
461 SetSizeInBits
) DIV BitsPerBitset
;
469 RotateRight - performs the rotate right for a multi word set.
470 This procedure might be called by the back end of
471 GNU Modula-2 depending whether amount is known at compile
475 PROCEDURE RotateRight (VAR s
, d
: ARRAY OF BITSET;
476 SetSizeInBits
: CARDINAL;
477 RotateCount
: CARDINAL) ;
479 RotateLeft(s
, d
, SetSizeInBits
, SetSizeInBits
-RotateCount
)