117 lines
4.6 KiB
Ada
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;
|