with TexT_IO; use Text_IO; Procedure Cooperative is Nb_Process : constant := 9 ; type Id is range 1.. Nb_Process; -- set of processes Nb_Trial : constant := 6; -- number of rendez-vous requested by each process --------------------------------------------- set of Assistants --------------- task type T_Assistant is entry Get_Id(Y: in Id); entry Local_Call(X: in Id; X_Other: out Id; Group_Leader: out Id; Accepted : out Boolean); -- local request entry Distant_Call(X: in Id; X_Other: out Id; Group_Leader: out Id; Accepted : out Boolean); -- remote call RPC private entry Waiting(X: in Id; X_Other: out Id; Group_Leader: out Id; Accepted : out Boolean); -- for Id'last Process end T_Assistant; Assistant: array(Id) of T_Assistant; -------------------------------------------------- Assistant task body -------------------- task body T_Assistant is Ego : Id; -- Caller_Id Partner : Id; -- the result of search Peer_To_Register : Boolean := False; -- partner found by CS2 through an accept Distant_call Candidate : Boolean := False ; -- searching a partner -------------------------------------- Process Next_Neighbour management Current : Id := Id'Last; -- used for managing Next_Neighbour -- Next_Neighbour provides a neighbour name which is always larger than the callerÍs name -- (this avoids deadlock due to circular calls) function Next_Neighbour return Id is begin if Current = Id'Last then Current := Ego + 1; else Current := Current + 1; end if; return Current; end Next_Neighbour; function Top(X : in Id) return Boolean is begin return X = Id'Last; end Top; -- X has the highest rank Y : Id; -- records a value given by Next_Neighbour --------------------------------------- end Next_Neighbour management begin -- attaching each Assistant to a different Process accept Get_Id(Y: in Id) do Ego := Y; end Get_Id; -- the cyclic Assistant Ego waits for a request from a remote process or from a local call loop select -- CS1 : FIRST MUTUALLY EXCLUSIVE ACTION : local call to propagate to Next_Neigbour -- the barrier is set to give precedence to a remote call over recurrent local calls (optimization) -- when Distant_Call'Count = 0 or Peer_To_Register => -- for possible optimization accept Local_Call(X: in Id; X_Other: out Id; Group_Leader: out Id; Accepted : out Boolean) do -- a new partner may have been already found and has to be registered if Peer_To_Register then X_Other := Partner ; Group_Leader := Ego; Accepted:= True; -- a partner has been found and registered; reset Assistant state Peer_To_Register := False; else Candidate := True; -- a local request is made for searching a partner -- calls a neighbour process, hoping it might be a partner -- assumption: every assistant that is called will answer positively or negatively to remote call if not Top(Ego) then -- calls a neighbour holding a name strictly bigger than Ego Y := Next_Neighbour; -- each time a different neighbour process Assistant(Y).Distant_Call(X, X_Other, Group_Leader, Accepted); if Accepted then Candidate := False; -- a partner is found, reset Assistant state end if; else requeue Waiting; -- this Assistant holds the biggest name, thus it never calls a neighbour end if; end if; end Local_Call; or -- used only by Assistant(Id'Last) for returning the partner name when Peer_To_Register => accept Waiting(X: in Id; X_Other: out Id; Group_Leader: out Id; Accepted : out Boolean) do -- a new partner has called, was accepted and then has to be registered X_Other := Partner ; Group_Leader := Ego; Accepted:= True; -- a partner has been found and registered; reset Assistant state Peer_To_Register := False; end Waiting; or -- CS2 : SECOND MUTUALLY EXCLUSIVE ACTION : waiting for a distant call -- the barrier forbids accepting a new distant call before acknowledging the previous one when not Peer_To_Register => accept Distant_Call(X: in Id; X_Other: out Id; Group_Leader: out Id; Accepted : out Boolean) do Partner := X; X_Other := Ego; Group_Leader := Ego; Accepted := Candidate; -- the pair is accepted only if process Ego is seeking Peer_To_Register := Candidate; -- when accepted (candidate), has to be registered locally Candidate := False; -- whatever the answer, the process Ego is no longer seeking end Distant_Call; or terminate; end select; end loop; -- end of cyclic Assistant code end T_Assistant; --- end of Assistant body ------------------------------------------------set of processes ----------------------- task type T_Process is entry Get_Id(Y : in Id); entry Start_Peering(Pilot : in Id; Copilot : in Id; Leader : in Id); entry Finish_Peering(Copilot : in Id; Pilot : in Id; Leader : in Id); end T_Process; Process: array(Id) of T_Process; ------------------------------------------------Pocess task body -------------------- task body T_Process is Ego : Id; -- Caller_Id Partner : Id; -- the result of search Leader : Id; Done : Boolean := False; begin -- giving each Process a different name accept Get_Id(Y: in Id) do Ego := Y; end Get_Id; -- each process loops seeking a partner just for recording its name and the rendez-vous -- peer-to-peer asymmetric communication is simulated only for I in 1 .. Nb_Trial loop -- get a partner loop Assistant(Ego).Local_Call(Ego, Partner, Leader, Done);-- repeats request until a partner is found delay(0.001); exit when Done; end loop; Put_line(" Process" & Id'Image(Ego) & " is notified that its booked partner is process " & Id'Image(Partner) & " The Group Leadership owns to " & Id'Image(Leader)); if Ego = Leader then Process(Partner).Start_Peering(Ego, Partner, Leader); -- sends intializing RPC accept Finish_Peering(Copilot : in Id; Pilot : in Id; Leader : in Id); -- waits until peering ends else accept Start_Peering(Pilot : in Id; Copilot : in Id; Leader : in Id); -- waits partner call delay(1.0); -- simulates peer interchange and processes corresponding activity Put_line("PROCESS" & Id'Image(Ego) & " acts as COPILOT while PEERING with" & Id'Image(Partner) & " as PILOT"); Process(Partner).Finish_Peering(Ego, Partner, Leader); -- peer exchange ends; sends releasing RPC end if; end loop; end T_Process; --------------------------------------------- allocating names to tasks ------- begin for I in Id loop Assistant(I).Get_Id(I) ; end loop; for I in Id loop Process(I).Get_Id(I) ; end loop; end Cooperative;