(* RTentity.mod implements a grouping of different opaque types. Copyright (C) 2008-2023 Free Software Foundation, Inc. Contributed by Gaius Mulley . This file is part of GNU Modula-2. GNU Modula-2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . *) IMPLEMENTATION MODULE RTentity ; FROM libc IMPORT malloc, free ; FROM M2RTS IMPORT Halt ; FROM RTco IMPORT init, initSemaphore, wait, signal ; TYPE Group = POINTER TO RECORD left, right: Group ; entity : SYSTEM.ADDRESS ; entityKey : CARDINAL ; END ; PROCEDURE InitGroup () : Group ; VAR g: Group ; BEGIN checkInitialized ; wait (mutex) ; g := malloc (SIZE (g^)) ; WITH g^ DO left := NIL ; right := NIL ; entity := NIL ; entityKey := 0 END ; signal (mutex) ; RETURN g END InitGroup ; (* killGroup - *) PROCEDURE killGroup (g: Group) : Group ; BEGIN IF g # NIL THEN WITH g^ DO left := killGroup (left) ; right := killGroup (right) END ; free (g) END ; RETURN NIL END killGroup ; PROCEDURE KillGroup (g: Group) : Group ; BEGIN wait (mutex) ; g := killGroup (g) ; signal (mutex) ; RETURN g END KillGroup ; PROCEDURE GetKey (g: Group; a: SYSTEM.ADDRESS) : CARDINAL ; VAR parent, child : Group ; BEGIN assert (initialized) ; wait (mutex) ; findChildAndParent (g, a, child, parent) ; signal (mutex) ; IF child = NIL THEN RETURN 0 ELSE RETURN child^.entityKey END END GetKey ; PROCEDURE PutKey (g: Group; a: SYSTEM.ADDRESS; key: CARDINAL) ; VAR parent, child : Group ; BEGIN assert (initialized) ; wait (mutex) ; findChildAndParent (g, a, child, parent) ; IF child = NIL THEN (* no child found, now is, a, less than parent or greater? *) IF parent = g THEN (* empty tree, add it to the left branch of t *) child := malloc (SIZE (child^)) ; parent^.left := child ELSE (* parent is a leaf node *) IF a < parent^.entity THEN child := malloc (SIZE (child^)) ; parent^.left := child ELSIF a > parent^.entity THEN child := malloc (SIZE (child^)) ; parent^.right := child END END ; WITH child^ DO right := NIL ; left := NIL ; entity := a ; entityKey := key END ELSE Halt ('internal runtime error, entity already stored', __FILE__, __FUNCTION__, __LINE__) END ; signal (mutex) END PutKey ; PROCEDURE IsIn (g: Group; a: SYSTEM.ADDRESS) : BOOLEAN ; VAR child, parent: Group ; BEGIN assert (initialized) ; wait (mutex) ; findChildAndParent (g, a, child, parent) ; signal (mutex) ; RETURN child # NIL END IsIn ; (* DelKey - deletes an entry in the binary tree. NB in order for this to work we must ensure that the InitGroup sets both left and right to NIL. *) PROCEDURE DelKey (g: Group; a: SYSTEM.ADDRESS) ; VAR i, child, parent: Group ; BEGIN assert (initialized) ; wait (mutex) ; (* find parent and child of the node *) findChildAndParent (g, a, child, parent) ; IF (child # NIL) AND (child^.entity = a) THEN (* Have found the node to be deleted *) IF parent^.right = child THEN (* Node is child and this is greater than the parent. *) (* Greater being on the right. *) (* Connect child^.left onto the parent^.right. *) (* Connect child^.right onto the end of the right *) (* most branch of child^.left. *) IF child^.left # NIL THEN (* Scan for right most node of child^.left *) i := child^.left ; WHILE i^.right # NIL DO i := i^.right END ; i^.right := child^.right ; parent^.right := child^.left ELSE (* No child^.left node therefore link over child *) (* (as in a single linked list) to child^.right *) parent^.right := child^.right END ; free (child) ELSE (* assert that parent^.left=child will always be true *) (* Perform exactly the mirror image of the above code *) (* Connect child^.right onto the parent^.left. *) (* Connect child^.left onto the end of the left most *) (* branch of child^.right *) IF child^.right # NIL THEN (* Scan for left most node of child^.right *) i := child^.right ; WHILE i^.left # NIL DO i := i^.left END ; i^.left := child^.left ; parent^.left := child^.right ELSE (* No child^.right node therefore link over c *) (* (as in a single linked list) to child^.left. *) parent^.left := child^.left END ; free (child) END ELSE Halt('internal runtime error, trying to delete an entity which is not in the tree', __FILE__, __FUNCTION__, __LINE__) END ; signal (mutex) END DelKey ; (* findChildAndParent - find a node, child, in a binary tree, t, with name equal to n. If an entry is found, parent is set to the node above child. *) PROCEDURE findChildAndParent (t: Group; a: SYSTEM.ADDRESS; VAR child, parent: Group) ; BEGIN (* remember to skip the sentinal value and assign parent and child *) parent := t ; IF t = NIL THEN Halt ('internal runtime error, RTentity is either corrupt or the module storage has not been initialized yet', __FILE__, __FUNCTION__, __LINE__) END ; child := t^.left ; IF child # NIL THEN REPEAT IF a < child^.entity THEN parent := child ; child := child^.left ELSIF a > child^.entity THEN parent := child ; child := child^.right END UNTIL (child = NIL) OR (a = child^.entity) END END findChildAndParent ; (* assert - simple assertion procedure. *) PROCEDURE assert (condition: BOOLEAN) ; BEGIN IF NOT condition THEN Halt ('internal runtime error, RTentity is either corrupt or the module storage has not been initialized yet', __FILE__, __FUNCTION__, __LINE__) END END assert ; (* checkInitialized - *) PROCEDURE checkInitialized ; VAR result: INTEGER ; BEGIN IF NOT initialized THEN initialized := TRUE ; result := init () ; mutex := initSemaphore (1) END END checkInitialized ; VAR initialized: BOOLEAN ; (* Set to FALSE when the bss is created. *) mutex : INTEGER ; END RTentity.