1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S Y S T E M . R P C --
10 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 ------------------------------------------------------------------------------
37 with Unchecked_Deallocation;
40 with System.RPC.Net_Trace;
41 with System.RPC.Garlic;
42 with System.RPC.Streams;
43 pragma Elaborate (System.RPC.Garlic);
45 package body System.RPC is
47 -- ??? general note: the debugging calls are very heavy, especially
48 -- those that create exception handlers in every procedure. Do we
49 -- really still need all this stuff?
51 use type Ada.Streams.Stream_Element_Count;
52 use type Ada.Streams.Stream_Element_Offset;
54 use type Garlic.Protocol_Access;
55 use type Garlic.Lock_Method;
57 Max_Of_Message_Id : constant := 127;
59 subtype Message_Id_Type is
60 Integer range -Max_Of_Message_Id .. Max_Of_Message_Id;
61 -- A message id is either a request id or reply id. A message id is
62 -- provided with a message to a receiving stub which uses the opposite
63 -- as a reply id. A message id helps to retrieve to which task is
64 -- addressed a reply. When the environment task receives a message, the
65 -- message id is extracted : a positive message id stands for a call, a
66 -- negative message id stands for a reply. A null message id stands for
67 -- an asynchronous request.
69 subtype Request_Id_Type is Message_Id_Type range 1 .. Max_Of_Message_Id;
70 -- When a message id is positive, it is a request
72 type Message_Length_Per_Request is array (Request_Id_Type)
73 of Ada.Streams.Stream_Element_Count;
75 Header_Size : Ada.Streams.Stream_Element_Count :=
76 Streams.Get_Integer_Initial_Size +
77 Streams.Get_SEC_Initial_Size;
78 -- Initial size needed for frequently used header streams
80 Stream_Error : exception;
81 -- Occurs when a read procedure is executed on an empty stream
82 -- or when a write procedure is executed on a full stream
84 Partition_RPC_Receiver : RPC_Receiver;
85 -- Cache the RPC_Recevier passed by Establish_RPC_Receiver
87 type Anonymous_Task_Node;
89 type Anonymous_Task_Node_Access is access Anonymous_Task_Node;
90 -- Types we need to construct a singly linked list of anonymous tasks
91 -- This pool is maintained to avoid a task creation each time a RPC
92 -- occurs - to be cont'd
94 task type Anonymous_Task_Type (Self : Anonymous_Task_Node_Access) is
97 (Message_Id : in Message_Id_Type;
98 Partition : in Partition_ID;
99 Params_Size : in Ada.Streams.Stream_Element_Count;
100 Result_Size : in Ada.Streams.Stream_Element_Count;
101 Protocol : in Garlic.Protocol_Access);
102 -- This entry provides an anonymous task a remote call to perform.
103 -- This task calls for a Request id is provided to construct the
104 -- reply id by using -Request. Partition is used to send the reply
105 -- message. Params_Size is the size of the calling stub Params stream.
106 -- Then Protocol (used by the environment task previously) allows
107 -- extraction of the message following the header (The header is
108 -- extracted by the environment task)
109 -- Note: grammar in above is obscure??? needs cleanup
111 end Anonymous_Task_Type;
113 type Anonymous_Task_Access is access Anonymous_Task_Type;
115 type Anonymous_Task_List is record
116 Head : Anonymous_Task_Node_Access;
117 Tail : Anonymous_Task_Node_Access;
120 type Anonymous_Task_Node is record
121 Element : Anonymous_Task_Access;
122 Next : Anonymous_Task_Node_Access;
124 -- Types we need to construct a singly linked list of anonymous tasks.
125 -- This pool is maintained to avoid a task creation each time a RPC occurs.
127 protected Garbage_Collector is
130 (Item : out Anonymous_Task_Node_Access);
131 -- Anonymous task pool management : if there is an anonymous task
132 -- left, use it. Otherwise, allocate a new one
135 (Item : in out Anonymous_Task_Node_Access);
136 -- Anonymous task pool management : queue this task in the pool
137 -- of inactive anonymous tasks.
141 Anonymous_List : Anonymous_Task_Node_Access;
142 -- The list root of inactive anonymous tasks
144 end Garbage_Collector;
148 entry New_Request (Request : out Request_Id_Type);
149 -- To get a new request
151 entry Wait_On (Request_Id_Type)
152 (Length : out Ada.Streams.Stream_Element_Count);
153 -- To block the calling stub when it waits for a reply
154 -- When it is resumed, we provide the size of the reply
157 (Request : in Request_Id_Type;
158 Length : in Ada.Streams.Stream_Element_Count);
159 -- To wake up the calling stub when the environnement task has
160 -- received a reply for this request
164 task Environnement is
167 -- Receive no message until Partition_Receiver is set
168 -- Establish_RPC_Receiver decides when the environment task
169 -- is allowed to start
173 protected Partition_Receiver is
176 -- Blocks if the Partition_RPC_Receiver has not been set
179 -- Done by Establish_RPC_Receiver when Partition_RPC_Receiver
184 Was_Set : Boolean := False;
185 -- True when Partition_RPC_Receiver has been set
187 end Partition_Receiver;
188 -- Anonymous tasks have to wait for the Partition_RPC_Receiver
192 (D_Elaborate, -- About the elaboration of this package
193 D_Communication, -- About calls to Send and Receive
195 D_Exception); -- Exception handler
198 package Debugging is new System.RPC.Net_Trace (Debug_Level, "RPC : ");
202 (Flag : in Debug_Level; Info : in String) renames Debugging.Debug;
205 ------------------------
206 -- Partition_Receiver --
207 ------------------------
209 protected body Partition_Receiver is
211 -------------------------------
212 -- Partition_Receiver.Is_Set --
213 -------------------------------
215 entry Is_Set when Was_Set is
220 ----------------------------
221 -- Partition_Receiver.Set --
222 ----------------------------
229 end Partition_Receiver;
236 (Index : out Packet_Node_Access;
237 Stream : Params_Stream_Type)
240 Index := Stream.Extra.Head;
244 D (D_Exception, "exception in Head_Node");
253 (Index : out Packet_Node_Access;
254 Stream : Params_Stream_Type)
257 Index := Stream.Extra.Tail;
261 D (D_Exception, "exception in Tail_Node");
269 function Null_Node (Index : in Packet_Node_Access) return Boolean is
275 D (D_Exception, "exception in Null_Node");
279 ----------------------
280 -- Delete_Head_Node --
281 ----------------------
283 procedure Delete_Head_Node (Stream : in out Params_Stream_Type) is
286 new Unchecked_Deallocation
287 (Packet_Node, Packet_Node_Access);
289 Next_Node : Packet_Node_Access := Stream.Extra.Head.Next;
292 -- Delete head node and free memory usage
294 Free (Stream.Extra.Head);
295 Stream.Extra.Head := Next_Node;
297 -- If the extra storage is empty, update tail as well
299 if Stream.Extra.Head = null then
300 Stream.Extra.Tail := null;
305 D (D_Exception, "exception in Delete_Head_Node");
307 end Delete_Head_Node;
313 procedure Next_Node (Node : in out Packet_Node_Access) is
315 -- Node is set to the next node
316 -- If not possible, Stream_Error is raised
326 D (D_Exception, "exception in Next_Node");
330 ---------------------
331 -- Append_New_Node --
332 ---------------------
334 procedure Append_New_Node (Stream : in out Params_Stream_Type) is
335 Index : Packet_Node_Access;
338 -- Set Index to the end of the linked list
340 Tail_Node (Index, Stream);
342 if Null_Node (Index) then
344 -- The list is empty : set head as well
346 Stream.Extra.Head := new Packet_Node;
347 Stream.Extra.Tail := Stream.Extra.Head;
350 -- The list is not empty : link new node with tail
352 Stream.Extra.Tail.Next := new Packet_Node;
353 Stream.Extra.Tail := Stream.Extra.Tail.Next;
359 D (D_Exception, "exception in Append_New_Node");
368 (Stream : in out Params_Stream_Type;
369 Item : out Ada.Streams.Stream_Element_Array;
370 Last : out Ada.Streams.Stream_Element_Offset)
371 renames System.RPC.Streams.Read;
378 (Stream : in out Params_Stream_Type;
379 Item : in Ada.Streams.Stream_Element_Array)
380 renames System.RPC.Streams.Write;
382 -----------------------
383 -- Garbage_Collector --
384 -----------------------
386 protected body Garbage_Collector is
388 --------------------------------
389 -- Garbage_Collector.Allocate --
390 --------------------------------
392 procedure Allocate (Item : out Anonymous_Task_Node_Access) is
393 New_Anonymous_Task_Node : Anonymous_Task_Node_Access;
394 Anonymous_Task : Anonymous_Task_Access;
397 -- If the list is empty, allocate a new anonymous task
398 -- Otherwise, reuse the first queued anonymous task
400 if Anonymous_List = null then
402 -- Create a new anonymous task
403 -- Provide this new task with its id to allow it
404 -- to enqueue itself into the free anonymous task list
405 -- with the function Deallocate
407 New_Anonymous_Task_Node := new Anonymous_Task_Node;
409 new Anonymous_Task_Type (New_Anonymous_Task_Node);
410 New_Anonymous_Task_Node.all := (Anonymous_Task, null);
413 -- Extract one task from the list
414 -- Set the Next field to null to avoid possible bugs
416 New_Anonymous_Task_Node := Anonymous_List;
417 Anonymous_List := Anonymous_List.Next;
418 New_Anonymous_Task_Node.Next := null;
422 -- Item is an out parameter
424 Item := New_Anonymous_Task_Node;
428 D (D_Exception, "exception in Allocate (Anonymous Task)");
432 ----------------------------------
433 -- Garbage_Collector.Deallocate --
434 ----------------------------------
436 procedure Deallocate (Item : in out Anonymous_Task_Node_Access) is
438 -- Enqueue the task in the free list
440 Item.Next := Anonymous_List;
441 Anonymous_List := Item;
445 D (D_Exception, "exception in Deallocate (Anonymous Task)");
449 end Garbage_Collector;
456 (Partition : Partition_ID;
457 Params : access Params_Stream_Type;
458 Result : access Params_Stream_Type)
460 Protocol : Protocol_Access;
461 Request : Request_Id_Type;
462 Header : aliased Params_Stream_Type (Header_Size);
463 R_Length : Ada.Streams.Stream_Element_Count;
466 -- Parameters order :
467 -- Opcode (provided and used by garlic)
468 -- (1) Size (provided by s-rpc and used by garlic)
469 -- (size of (2)+(3)+(4)+(5))
470 -- (2) Request (provided by calling stub (resp receiving stub) and
471 -- used by anonymous task (resp Do_RPC))
472 -- *** ZERO IF APC ***
473 -- (3) Res.len. (provided by calling stubs and used by anonymous task)
474 -- *** ZERO IF APC ***
475 -- (4) Receiver (provided by calling stubs and used by anonymous task)
476 -- (5) Params (provided by calling stubs and used by anonymous task)
478 -- The call is a remote call or a local call. A local call occurs
479 -- when the pragma All_Calls_Remote has been specified. Do_RPC is
480 -- called and the execution has to be performed in the PCS
482 if Partition /= Garlic.Get_My_Partition_ID then
484 -- Get a request id to be resumed when the reply arrives
486 Dispatcher.New_Request (Request);
488 -- Build header = request (2) + result.initial_size (3)
490 D (D_Debug, "Do_RPC - Build header");
491 Streams.Allocate (Header);
492 Streams.Integer_Write_Attribute -- (2)
493 (Header'Access, Request);
494 System.RPC.Streams.SEC_Write_Attribute -- (3)
495 (Header'Access, Result.Initial_Size);
497 -- Get a protocol method to communicate with the remote partition
498 -- and give the message size
501 "Do_RPC - Lookup for protocol to talk to partition" &
502 Partition_ID'Image (Partition));
505 Streams.Get_Stream_Size (Header'Access) +
506 Streams.Get_Stream_Size (Params), -- (1)
510 -- Send the header by using the protocol method
512 D (D_Communication, "Do_RPC - Send Header to partition" &
513 Partition_ID'Image (Partition));
517 Header'Access); -- (2) + (3)
519 -- The header is deallocated
521 Streams.Deallocate (Header);
523 -- Send Params from Do_RPC
525 D (D_Communication, "Do_RPC - Send Params to partition" &
526 Partition_ID'Image (Partition));
530 Params); -- (4) + (5)
532 -- Let Garlic know we have nothing else to send
537 D (D_Debug, "Do_RPC - Suspend");
539 -- Wait for a reply and get the reply message length
541 Dispatcher.Wait_On (Request) (R_Length);
542 D (D_Debug, "Do_RPC - Resume");
545 New_Result : aliased Params_Stream_Type (R_Length);
547 -- Adjust the Result stream size right now to be able to load
548 -- the stream in one receive call. Create a temporary resutl
549 -- that will be substituted to Do_RPC one
551 Streams.Allocate (New_Result);
553 -- Receive the reply message from receiving stub
555 D (D_Communication, "Do_RPC - Receive Result from partition" &
556 Partition_ID'Image (Partition));
562 -- Let Garlic know we have nothing else to receive
564 Garlic.Complete_Receive
568 -- Update calling stub Result stream
570 D (D_Debug, "Do_RPC - Reconstruct Result");
571 Streams.Deallocate (Result.all);
572 Result.Initial := New_Result.Initial;
573 Streams.Dump ("|||", Result.all);
578 -- Do RPC locally and first wait for Partition_RPC_Receiver to be
581 Partition_Receiver.Is_Set;
582 D (D_Debug, "Do_RPC - Locally");
583 Partition_RPC_Receiver.all (Params, Result);
589 D (D_Exception, "exception in Do_RPC");
598 (Partition : Partition_ID;
599 Params : access Params_Stream_Type)
601 Message_Id : Message_Id_Type := 0;
602 Protocol : Protocol_Access;
603 Header : aliased Params_Stream_Type (Header_Size);
606 -- For more informations, see above
607 -- Request = 0 as we are not waiting for a reply message
608 -- Result length = 0 as we don't expect a result at all
610 if Partition /= Garlic.Get_My_Partition_ID then
612 -- Build header = request (2) + result.initial_size (3)
613 -- As we have an APC, the request id is null to indicate
614 -- to the receiving stub that we do not expect a reply
615 -- This comes from 0 = -0
617 D (D_Debug, "Do_APC - Build Header");
618 Streams.Allocate (Header);
619 Streams.Integer_Write_Attribute
620 (Header'Access, Integer (Message_Id));
621 Streams.SEC_Write_Attribute
624 -- Get a protocol method to communicate with the remote partition
625 -- and give the message size
628 "Do_APC - Lookup for protocol to talk to partition" &
629 Partition_ID'Image (Partition));
632 Streams.Get_Stream_Size (Header'Access) +
633 Streams.Get_Stream_Size (Params),
637 -- Send the header by using the protocol method
639 D (D_Communication, "Do_APC - Send Header to partition" &
640 Partition_ID'Image (Partition));
646 -- The header is deallocated
648 Streams.Deallocate (Header);
650 -- Send Params from Do_APC
652 D (D_Communication, "Do_APC - Send Params to partition" &
653 Partition_ID'Image (Partition));
659 -- Let Garlic know we have nothing else to send
667 Result : aliased Params_Stream_Type (0);
669 -- Result is here a dummy parameter
670 -- No reason to deallocate as it is not allocated at all
672 Partition_Receiver.Is_Set;
673 D (D_Debug, "Do_APC - Locally");
674 Partition_RPC_Receiver.all (Params, Result'Access);
682 D (D_Exception, "exception in Do_APC");
686 ----------------------------
687 -- Establish_RPC_Receiver --
688 ----------------------------
690 procedure Establish_RPC_Receiver
691 (Partition : in Partition_ID;
692 Receiver : in RPC_Receiver)
695 -- Set Partition_RPC_Receiver and allow RPC mechanism
697 Partition_RPC_Receiver := Receiver;
698 Partition_Receiver.Set;
699 D (D_Elaborate, "Partition_Receiver is set");
703 D (D_Exception, "exception in Establish_RPC_Receiver");
705 end Establish_RPC_Receiver;
711 task body Dispatcher is
712 Last_Request : Request_Id_Type := Request_Id_Type'First;
713 Current_Rqst : Request_Id_Type := Request_Id_Type'First;
714 Current_Size : Ada.Streams.Stream_Element_Count;
720 -- New_Request to get an entry in Dispatcher table
722 -- Wait_On for Do_RPC calls
724 -- Wake_Up called by environment task when a Do_RPC receives
725 -- the result of its remote call
728 accept New_Request (Request : out Request_Id_Type) do
729 Request := Last_Request;
732 -- ??? Avaibility check
734 if Last_Request = Request_Id_Type'Last then
735 Last_Request := Request_Id_Type'First;
737 Last_Request := Last_Request + 1;
744 (Request : Request_Id_Type;
745 Length : Ada.Streams.Stream_Element_Count)
747 -- The environment reads the header and has been notified
748 -- of the reply id and the size of the result message
750 Current_Rqst := Request;
751 Current_Size := Length;
756 -- ??? Must be select with delay for aborted tasks
760 accept Wait_On (Current_Rqst)
761 (Length : out Ada.Streams.Stream_Element_Count)
763 Length := Current_Size;
767 -- To free the Dispatcher when a task is aborted
781 D (D_Exception, "exception in Dispatcher body");
785 -------------------------
786 -- Anonymous_Task_Type --
787 -------------------------
789 task body Anonymous_Task_Type is
790 Whoami : Anonymous_Task_Node_Access := Self;
791 C_Message_Id : Message_Id_Type; -- Current Message Id
792 C_Partition : Partition_ID; -- Current Partition
793 Params_S : Ada.Streams.Stream_Element_Count; -- Params message size
794 Result_S : Ada.Streams.Stream_Element_Count; -- Result message size
795 C_Protocol : Protocol_Access; -- Current Protocol
799 -- Get a new RPC to execute
803 (Message_Id : in Message_Id_Type;
804 Partition : in Partition_ID;
805 Params_Size : in Ada.Streams.Stream_Element_Count;
806 Result_Size : in Ada.Streams.Stream_Element_Count;
807 Protocol : in Protocol_Access)
809 C_Message_Id := Message_Id;
810 C_Partition := Partition;
811 Params_S := Params_Size;
812 Result_S := Result_Size;
813 C_Protocol := Protocol;
820 Params : aliased Params_Stream_Type (Params_S);
821 Result : aliased Params_Stream_Type (Result_S);
822 Header : aliased Params_Stream_Type (Header_Size);
825 -- We reconstruct all the client context : Params and Result
826 -- with the SAME size, then we receive Params from calling stub
829 "Anonymous Task - Receive Params from partition" &
830 Partition_ID'Image (C_Partition));
836 -- Let Garlic know we don't receive anymore
838 Garlic.Complete_Receive
842 -- Check that Partition_RPC_Receiver has been set
844 Partition_Receiver.Is_Set;
849 "Anonymous Task - Perform Partition_RPC_Receiver for request" &
850 Message_Id_Type'Image (C_Message_Id));
851 Partition_RPC_Receiver (Params'Access, Result'Access);
853 -- If this was a RPC we send the result back
854 -- Otherwise, do nothing else than deallocation
856 if C_Message_Id /= 0 then
858 -- Build Header = -C_Message_Id + Result Size
859 -- Provide the request id to the env task of the calling
860 -- stub partition We get the real result stream size : the
861 -- calling stub (in Do_RPC) updates its size to this one
863 D (D_Debug, "Anonymous Task - Build Header");
864 Streams.Allocate (Header);
865 Streams.Integer_Write_Attribute
866 (Header'Access, Integer (-C_Message_Id));
867 Streams.SEC_Write_Attribute
869 Streams.Get_Stream_Size (Result'Access));
871 -- Get a protocol method to comunicate with the remote
872 -- partition and give the message size
875 "Anonymous Task - Lookup for protocol talk to partition" &
876 Partition_ID'Image (C_Partition));
879 Streams.Get_Stream_Size (Header'Access) +
880 Streams.Get_Stream_Size (Result'Access),
884 -- Send the header by using the protocol method
887 "Anonymous Task - Send Header to partition" &
888 Partition_ID'Image (C_Partition));
894 -- Send Result toDo_RPC
897 "Anonymous Task - Send Result to partition" &
898 Partition_ID'Image (C_Partition));
904 -- Let Garlic know we don't send anymore
909 Streams.Deallocate (Header);
912 Streams.Deallocate (Params);
913 Streams.Deallocate (Result);
916 -- Enqueue into the anonymous task free list : become inactive
918 Garbage_Collector.Deallocate (Whoami);
924 D (D_Exception, "exception in Anonymous_Task_Type body");
926 end Anonymous_Task_Type;
932 task body Environnement is
933 Partition : Partition_ID;
934 Message_Size : Ada.Streams.Stream_Element_Count;
935 Result_Size : Ada.Streams.Stream_Element_Count;
936 Message_Id : Message_Id_Type;
937 Header : aliased Params_Stream_Type (Header_Size);
938 Protocol : Protocol_Access;
939 Anonymous : Anonymous_Task_Node_Access;
942 -- Wait the Partition_RPC_Receiver to be set
945 D (D_Elaborate, "Environment task elaborated");
948 -- We receive first a fixed size message : the header
949 -- Header = Message Id + Message Size
951 Streams.Allocate (Header);
953 -- Garlic provides the size of the received message and the
954 -- protocol to use to communicate with the calling partition
956 Garlic.Initiate_Receive
962 "Environment task - Receive protocol to talk to active partition" &
963 Partition_ID'Image (Partition));
965 -- Extract the header to route the message either to
966 -- an anonymous task (Message Id > 0 <=> Request Id)
967 -- or to a waiting task (Message Id < 0 <=> Reply Id)
970 "Environment task - Receive Header from partition" &
971 Partition_ID'Image (Partition));
977 -- Evaluate the remaining size of the message
979 Message_Size := Message_Size -
980 Streams.Get_Stream_Size (Header'Access);
982 -- Extract from header : message id and message size
984 Streams.Integer_Read_Attribute (Header'Access, Message_Id);
985 Streams.SEC_Read_Attribute (Header'Access, Result_Size);
987 if Streams.Get_Stream_Size (Header'Access) /= 0 then
989 -- If there are stream elements left in the header ???
991 D (D_Exception, "Header is not empty");
996 if Message_Id < 0 then
998 -- The message was sent by a receiving stub : wake up the
999 -- calling task - We have a reply there
1001 D (D_Debug, "Environment Task - Receive Reply from partition" &
1002 Partition_ID'Image (Partition));
1003 Dispatcher.Wake_Up (-Message_Id, Result_Size);
1006 -- The message was send by a calling stub : get an anonymous
1007 -- task to perform the job
1009 D (D_Debug, "Environment Task - Receive Request from partition" &
1010 Partition_ID'Image (Partition));
1011 Garbage_Collector.Allocate (Anonymous);
1013 -- We subtracted the size of the header from the size of the
1014 -- global message in order to provide immediatly Params size
1016 Anonymous.Element.Start
1025 -- Deallocate header : unnecessary - WARNING
1027 Streams.Deallocate (Header);
1033 D (D_Exception, "exception in Environment");
1038 -- Set debugging information
1040 Debugging.Set_Environment_Variable ("RPC");
1041 Debugging.Set_Debugging_Name ("D", D_Debug);
1042 Debugging.Set_Debugging_Name ("E", D_Exception);
1043 Debugging.Set_Debugging_Name ("C", D_Communication);
1044 Debugging.Set_Debugging_Name ("Z", D_Elaborate);
1045 D (D_Elaborate, "To be elaborated");
1047 -- When this body is elaborated we should ensure that RCI name server
1048 -- has been already elaborated : this means that Establish_RPC_Receiver
1049 -- has already been called and that Partition_RPC_Receiver is set
1051 Environnement.Start;
1052 D (D_Elaborate, "ELABORATED");