package body Agila_Ports is use type Word; Max_Generation : constant Word := Word'Last / Max_Ports; function Valid (State : Manager; Handle : Word) return Boolean is Slot : constant Natural := Natural (Handle mod Max_Ports); begin return Handle >= Max_Ports and then State.Table (Slot).Active and then State.Table (Slot).Generation = Handle / Max_Ports; end Valid; procedure Create (State : in out Manager; Owner : Word; Handle : out Word; Result : out Status) is begin Handle := 0; if Owner = 0 then Result := Invalid_Argument; return; end if; for Slot in State.Table'Range loop if not State.Table (Slot).Active and not State.Table (Slot).Retired then State.Table (Slot).Active := True; State.Table (Slot).Owner := Owner; State.Table (Slot).Allowed_Sender := 0; State.Table (Slot).Head := 0; State.Table (Slot).Count := 0; State.Table (Slot).Queue := [others => (0, 0)]; Handle := State.Table (Slot).Generation * Max_Ports + Word (Slot); Result := Ok; return; end if; end loop; Result := Exhausted; end Create; procedure Allow_Sender (State : in out Manager; Handle, Owner, Sender : Word; Result : out Status) is Slot : constant Natural := Natural (Handle mod Max_Ports); begin if not Valid (State, Handle) then Result := Invalid_Handle; elsif State.Table (Slot).Owner /= Owner then Result := Permission_Denied; elsif Sender = 0 then Result := Invalid_Argument; else State.Table (Slot).Allowed_Sender := Sender; Result := Ok; end if; end Allow_Sender; procedure Revoke_Sender (State : in out Manager; Handle, Owner, Sender : Word; Result : out Status) is Slot : constant Natural := Natural (Handle mod Max_Ports); begin if not Valid (State, Handle) then Result := Invalid_Handle; elsif State.Table (Slot).Owner /= Owner then Result := Permission_Denied; elsif Sender = 0 or else State.Table (Slot).Allowed_Sender /= Sender then Result := Invalid_Argument; else State.Table (Slot).Allowed_Sender := 0; Result := Ok; end if; end Revoke_Sender; procedure Send (State : in out Manager; Handle, Caller, Value : Word; Result : out Status) is Slot : constant Natural := Natural (Handle mod Max_Ports); begin if not Valid (State, Handle) then Result := Invalid_Handle; return; end if; declare P : Port renames State.Table (Slot); begin if Caller = 0 or else (Caller /= P.Owner and Caller /= P.Allowed_Sender) then Result := Permission_Denied; elsif P.Count = Queue_Capacity then Result := Full; else P.Queue ((P.Head + P.Count) mod Queue_Capacity) := (Caller, Value); P.Count := P.Count + 1; Result := Ok; end if; end; end Send; procedure Receive (State : in out Manager; Handle, Caller : Word; Item : out Message; Result : out Status) is Slot : constant Natural := Natural (Handle mod Max_Ports); begin Item := (0, 0); if not Valid (State, Handle) then Result := Invalid_Handle; return; end if; declare P : Port renames State.Table (Slot); begin if Caller /= P.Owner then Result := Permission_Denied; elsif P.Count = 0 then Result := Empty; else Item := P.Queue (P.Head); P.Queue (P.Head) := (0, 0); P.Head := (P.Head + 1) mod Queue_Capacity; P.Count := P.Count - 1; Result := Ok; end if; end; end Receive; procedure Close (State : in out Manager; Handle, Caller : Word; Result : out Status) is Slot : constant Natural := Natural (Handle mod Max_Ports); begin if not Valid (State, Handle) then Result := Invalid_Handle; elsif State.Table (Slot).Owner /= Caller then Result := Permission_Denied; else State.Table (Slot).Active := False; State.Table (Slot).Owner := 0; State.Table (Slot).Allowed_Sender := 0; State.Table (Slot).Count := 0; State.Table (Slot).Queue := [others => (0, 0)]; if State.Table (Slot).Generation = Max_Generation then State.Table (Slot).Retired := True; else State.Table (Slot).Generation := State.Table (Slot).Generation + 1; end if; Result := Ok; end if; end Close; end Agila_Ports;