FSF GCC merge 02/23/03
[official-gcc.git] / gcc / ada / 9drpc.adb
blobc44200cf443d0f9448a47db017c347150004bbfa
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S Y S T E M . R P C --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
11 -- --
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. --
22 -- --
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. --
29 -- --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 -- --
33 ------------------------------------------------------------------------------
35 -- Version for ???
37 with Unchecked_Deallocation;
38 with Ada.Streams;
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
96 entry Start
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;
118 end record;
120 type Anonymous_Task_Node is record
121 Element : Anonymous_Task_Access;
122 Next : Anonymous_Task_Node_Access;
123 end record;
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
129 procedure Allocate
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
134 procedure Deallocate
135 (Item : in out Anonymous_Task_Node_Access);
136 -- Anonymous task pool management : queue this task in the pool
137 -- of inactive anonymous tasks.
139 private
141 Anonymous_List : Anonymous_Task_Node_Access;
142 -- The list root of inactive anonymous tasks
144 end Garbage_Collector;
146 task Dispatcher is
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
156 entry Wake_Up
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
162 end Dispatcher;
164 task Environnement is
166 entry Start;
167 -- Receive no message until Partition_Receiver is set
168 -- Establish_RPC_Receiver decides when the environment task
169 -- is allowed to start
171 end Environnement;
173 protected Partition_Receiver is
175 entry Is_Set;
176 -- Blocks if the Partition_RPC_Receiver has not been set
178 procedure Set;
179 -- Done by Establish_RPC_Receiver when Partition_RPC_Receiver
180 -- is known
182 private
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
189 -- to be established
191 type Debug_Level is
192 (D_Elaborate, -- About the elaboration of this package
193 D_Communication, -- About calls to Send and Receive
194 D_Debug, -- Verbose
195 D_Exception); -- Exception handler
196 -- Debugging levels
198 package Debugging is new System.RPC.Net_Trace (Debug_Level, "RPC : ");
199 -- Debugging package
201 procedure D
202 (Flag : in Debug_Level; Info : in String) renames Debugging.Debug;
203 -- Shortcut
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
216 begin
217 null;
218 end Is_Set;
220 ----------------------------
221 -- Partition_Receiver.Set --
222 ----------------------------
224 procedure Set is
225 begin
226 Was_Set := True;
227 end Set;
229 end Partition_Receiver;
231 ---------------
232 -- Head_Node --
233 ---------------
235 procedure Head_Node
236 (Index : out Packet_Node_Access;
237 Stream : Params_Stream_Type)
239 begin
240 Index := Stream.Extra.Head;
242 exception
243 when others =>
244 D (D_Exception, "exception in Head_Node");
245 raise;
246 end Head_Node;
248 ---------------
249 -- Tail_Node --
250 ---------------
252 procedure Tail_Node
253 (Index : out Packet_Node_Access;
254 Stream : Params_Stream_Type)
256 begin
257 Index := Stream.Extra.Tail;
259 exception
260 when others =>
261 D (D_Exception, "exception in Tail_Node");
262 raise;
263 end Tail_Node;
265 ---------------
266 -- Null_Node --
267 ---------------
269 function Null_Node (Index : in Packet_Node_Access) return Boolean is
270 begin
271 return Index = null;
273 exception
274 when others =>
275 D (D_Exception, "exception in Null_Node");
276 raise;
277 end Null_Node;
279 ----------------------
280 -- Delete_Head_Node --
281 ----------------------
283 procedure Delete_Head_Node (Stream : in out Params_Stream_Type) is
285 procedure Free is
286 new Unchecked_Deallocation
287 (Packet_Node, Packet_Node_Access);
289 Next_Node : Packet_Node_Access := Stream.Extra.Head.Next;
291 begin
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;
301 end if;
303 exception
304 when others =>
305 D (D_Exception, "exception in Delete_Head_Node");
306 raise;
307 end Delete_Head_Node;
309 ---------------
310 -- Next_Node --
311 ---------------
313 procedure Next_Node (Node : in out Packet_Node_Access) is
314 begin
315 -- Node is set to the next node
316 -- If not possible, Stream_Error is raised
318 if Node = null then
319 raise Stream_Error;
320 else
321 Node := Node.Next;
322 end if;
324 exception
325 when others =>
326 D (D_Exception, "exception in Next_Node");
327 raise;
328 end 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;
337 begin
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;
349 else
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;
355 end if;
357 exception
358 when others =>
359 D (D_Exception, "exception in Append_New_Node");
360 raise;
361 end Append_New_Node;
363 ----------
364 -- Read --
365 ----------
367 procedure Read
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;
373 -----------
374 -- Write --
375 -----------
377 procedure Write
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;
396 begin
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;
408 Anonymous_Task :=
409 new Anonymous_Task_Type (New_Anonymous_Task_Node);
410 New_Anonymous_Task_Node.all := (Anonymous_Task, null);
412 else
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;
420 end if;
422 -- Item is an out parameter
424 Item := New_Anonymous_Task_Node;
426 exception
427 when others =>
428 D (D_Exception, "exception in Allocate (Anonymous Task)");
429 raise;
430 end Allocate;
432 ----------------------------------
433 -- Garbage_Collector.Deallocate --
434 ----------------------------------
436 procedure Deallocate (Item : in out Anonymous_Task_Node_Access) is
437 begin
438 -- Enqueue the task in the free list
440 Item.Next := Anonymous_List;
441 Anonymous_List := Item;
443 exception
444 when others =>
445 D (D_Exception, "exception in Deallocate (Anonymous Task)");
446 raise;
447 end Deallocate;
449 end Garbage_Collector;
451 ------------
452 -- Do_RPC --
453 ------------
455 procedure Do_RPC
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;
465 begin
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
500 D (D_Communication,
501 "Do_RPC - Lookup for protocol to talk to partition" &
502 Partition_ID'Image (Partition));
503 Garlic.Initiate_Send
504 (Partition,
505 Streams.Get_Stream_Size (Header'Access) +
506 Streams.Get_Stream_Size (Params), -- (1)
507 Protocol,
508 Garlic.Remote_Call);
510 -- Send the header by using the protocol method
512 D (D_Communication, "Do_RPC - Send Header to partition" &
513 Partition_ID'Image (Partition));
514 Garlic.Send
515 (Protocol.all,
516 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));
527 Garlic.Send
528 (Protocol.all,
529 Partition,
530 Params); -- (4) + (5)
532 -- Let Garlic know we have nothing else to send
534 Garlic.Complete_Send
535 (Protocol.all,
536 Partition);
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");
544 declare
545 New_Result : aliased Params_Stream_Type (R_Length);
546 begin
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));
557 Garlic.Receive
558 (Protocol.all,
559 Partition,
560 New_Result'Access);
562 -- Let Garlic know we have nothing else to receive
564 Garlic.Complete_Receive
565 (Protocol.all,
566 Partition);
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);
575 end;
577 else
578 -- Do RPC locally and first wait for Partition_RPC_Receiver to be
579 -- set
581 Partition_Receiver.Is_Set;
582 D (D_Debug, "Do_RPC - Locally");
583 Partition_RPC_Receiver.all (Params, Result);
585 end if;
587 exception
588 when others =>
589 D (D_Exception, "exception in Do_RPC");
590 raise;
591 end Do_RPC;
593 ------------
594 -- Do_APC --
595 ------------
597 procedure Do_APC
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);
605 begin
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
622 (Header'Access, 0);
624 -- Get a protocol method to communicate with the remote partition
625 -- and give the message size
627 D (D_Communication,
628 "Do_APC - Lookup for protocol to talk to partition" &
629 Partition_ID'Image (Partition));
630 Garlic.Initiate_Send
631 (Partition,
632 Streams.Get_Stream_Size (Header'Access) +
633 Streams.Get_Stream_Size (Params),
634 Protocol,
635 Garlic.Remote_Call);
637 -- Send the header by using the protocol method
639 D (D_Communication, "Do_APC - Send Header to partition" &
640 Partition_ID'Image (Partition));
641 Garlic.Send
642 (Protocol.all,
643 Partition,
644 Header'Access);
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));
654 Garlic.Send
655 (Protocol.all,
656 Partition,
657 Params);
659 -- Let Garlic know we have nothing else to send
661 Garlic.Complete_Send
662 (Protocol.all,
663 Partition);
664 else
666 declare
667 Result : aliased Params_Stream_Type (0);
668 begin
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);
676 end;
678 end if;
680 exception
681 when others =>
682 D (D_Exception, "exception in Do_APC");
683 raise;
684 end Do_APC;
686 ----------------------------
687 -- Establish_RPC_Receiver --
688 ----------------------------
690 procedure Establish_RPC_Receiver
691 (Partition : in Partition_ID;
692 Receiver : in RPC_Receiver)
694 begin
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");
701 exception
702 when others =>
703 D (D_Exception, "exception in Establish_RPC_Receiver");
704 raise;
705 end Establish_RPC_Receiver;
707 ----------------
708 -- Dispatcher --
709 ----------------
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;
716 begin
717 loop
718 -- Three services:
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
727 select
728 accept New_Request (Request : out Request_Id_Type) do
729 Request := Last_Request;
731 -- << TODO >>
732 -- ??? Avaibility check
734 if Last_Request = Request_Id_Type'Last then
735 Last_Request := Request_Id_Type'First;
736 else
737 Last_Request := Last_Request + 1;
738 end if;
740 end New_Request;
743 accept Wake_Up
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;
753 end Wake_Up;
755 -- << TODO >>
756 -- ??? Must be select with delay for aborted tasks
758 select
760 accept Wait_On (Current_Rqst)
761 (Length : out Ada.Streams.Stream_Element_Count)
763 Length := Current_Size;
764 end Wait_On;
767 -- To free the Dispatcher when a task is aborted
769 delay 1.0;
771 end select;
774 terminate;
775 end select;
777 end loop;
779 exception
780 when others =>
781 D (D_Exception, "exception in Dispatcher body");
782 raise;
783 end Dispatcher;
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
797 begin
798 loop
799 -- Get a new RPC to execute
801 select
802 accept Start
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;
814 end Start;
816 terminate;
817 end select;
819 declare
820 Params : aliased Params_Stream_Type (Params_S);
821 Result : aliased Params_Stream_Type (Result_S);
822 Header : aliased Params_Stream_Type (Header_Size);
824 begin
825 -- We reconstruct all the client context : Params and Result
826 -- with the SAME size, then we receive Params from calling stub
828 D (D_Communication,
829 "Anonymous Task - Receive Params from partition" &
830 Partition_ID'Image (C_Partition));
831 Garlic.Receive
832 (C_Protocol.all,
833 C_Partition,
834 Params'Access);
836 -- Let Garlic know we don't receive anymore
838 Garlic.Complete_Receive
839 (C_Protocol.all,
840 C_Partition);
842 -- Check that Partition_RPC_Receiver has been set
844 Partition_Receiver.Is_Set;
846 -- Do it locally
848 D (D_Debug,
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
868 (Header'Access,
869 Streams.Get_Stream_Size (Result'Access));
871 -- Get a protocol method to comunicate with the remote
872 -- partition and give the message size
874 D (D_Communication,
875 "Anonymous Task - Lookup for protocol talk to partition" &
876 Partition_ID'Image (C_Partition));
877 Garlic.Initiate_Send
878 (C_Partition,
879 Streams.Get_Stream_Size (Header'Access) +
880 Streams.Get_Stream_Size (Result'Access),
881 C_Protocol,
882 Garlic.Remote_Call);
884 -- Send the header by using the protocol method
886 D (D_Communication,
887 "Anonymous Task - Send Header to partition" &
888 Partition_ID'Image (C_Partition));
889 Garlic.Send
890 (C_Protocol.all,
891 C_Partition,
892 Header'Access);
894 -- Send Result toDo_RPC
896 D (D_Communication,
897 "Anonymous Task - Send Result to partition" &
898 Partition_ID'Image (C_Partition));
899 Garlic.Send
900 (C_Protocol.all,
901 C_Partition,
902 Result'Access);
904 -- Let Garlic know we don't send anymore
906 Garlic.Complete_Send
907 (C_Protocol.all,
908 C_Partition);
909 Streams.Deallocate (Header);
910 end if;
912 Streams.Deallocate (Params);
913 Streams.Deallocate (Result);
914 end;
916 -- Enqueue into the anonymous task free list : become inactive
918 Garbage_Collector.Deallocate (Whoami);
920 end loop;
922 exception
923 when others =>
924 D (D_Exception, "exception in Anonymous_Task_Type body");
925 raise;
926 end Anonymous_Task_Type;
928 -----------------
929 -- Environment --
930 -----------------
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;
941 begin
942 -- Wait the Partition_RPC_Receiver to be set
944 accept Start;
945 D (D_Elaborate, "Environment task elaborated");
947 loop
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
957 (Partition,
958 Message_Size,
959 Protocol,
960 Garlic.Remote_Call);
961 D (D_Communication,
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)
969 D (D_Communication,
970 "Environment task - Receive Header from partition" &
971 Partition_ID'Image (Partition));
972 Garlic.Receive
973 (Protocol.all,
974 Partition,
975 Header'Access);
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");
992 raise Program_Error;
994 end if;
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);
1005 else
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
1017 (Message_Id,
1018 Partition,
1019 Message_Size,
1020 Result_Size,
1021 Protocol);
1023 end if;
1025 -- Deallocate header : unnecessary - WARNING
1027 Streams.Deallocate (Header);
1029 end loop;
1031 exception
1032 when others =>
1033 D (D_Exception, "exception in Environment");
1034 raise;
1035 end Environnement;
1037 begin
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");
1054 end System.RPC;