Files
open_kernel/core/agila_ports.adb
T

117 lines
4.6 KiB
Ada

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;