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-- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 3, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. -- 17-- -- 18-- As a special exception under Section 7 of GPL version 3, you are granted -- 19-- additional permissions described in the GCC Runtime Library Exception, -- 20-- version 3.1, as published by the Free Software Foundation. -- 21-- -- 22-- You should have received a copy of the GNU General Public License and -- 23-- a copy of the GCC Runtime Library Exception along with this program; -- 24-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- 25-- <http://www.gnu.org/licenses/>. -- 26-- -- 27-- GNAT was originally developed by the GNAT team at New York University. -- 28-- Extensive contributions were provided by Ada Core Technologies Inc. -- 29-- -- 30------------------------------------------------------------------------------ 31 32-- Version for ??? 33 34with Unchecked_Deallocation; 35with Ada.Streams; 36 37with System.RPC.Net_Trace; 38with System.RPC.Garlic; 39with System.RPC.Streams; 40pragma Elaborate (System.RPC.Garlic); 41 42package body System.RPC is 43 44 -- ??? general note: the debugging calls are very heavy, especially 45 -- those that create exception handlers in every procedure. Do we 46 -- really still need all this stuff? 47 48 use type Ada.Streams.Stream_Element_Count; 49 use type Ada.Streams.Stream_Element_Offset; 50 51 use type Garlic.Protocol_Access; 52 use type Garlic.Lock_Method; 53 54 Max_Of_Message_Id : constant := 127; 55 56 subtype Message_Id_Type is 57 Integer range -Max_Of_Message_Id .. Max_Of_Message_Id; 58 -- A message id is either a request id or reply id. A message id is 59 -- provided with a message to a receiving stub which uses the opposite 60 -- as a reply id. A message id helps to retrieve to which task is 61 -- addressed a reply. When the environment task receives a message, the 62 -- message id is extracted : a positive message id stands for a call, a 63 -- negative message id stands for a reply. A null message id stands for 64 -- an asynchronous request. 65 66 subtype Request_Id_Type is Message_Id_Type range 1 .. Max_Of_Message_Id; 67 -- When a message id is positive, it is a request 68 69 type Message_Length_Per_Request is array (Request_Id_Type) 70 of Ada.Streams.Stream_Element_Count; 71 72 Header_Size : Ada.Streams.Stream_Element_Count := 73 Streams.Get_Integer_Initial_Size + 74 Streams.Get_SEC_Initial_Size; 75 -- Initial size needed for frequently used header streams 76 77 Stream_Error : exception; 78 -- Occurs when a read procedure is executed on an empty stream 79 -- or when a write procedure is executed on a full stream 80 81 Partition_RPC_Receiver : RPC_Receiver; 82 -- Cache the RPC_Receiver passed by Establish_RPC_Receiver 83 84 type Anonymous_Task_Node; 85 86 type Anonymous_Task_Node_Access is access Anonymous_Task_Node; 87 -- Types we need to construct a singly linked list of anonymous tasks 88 -- This pool is maintained to avoid a task creation each time a RPC 89 -- occurs - to be cont'd 90 91 task type Anonymous_Task_Type (Self : Anonymous_Task_Node_Access) is 92 93 entry Start 94 (Message_Id : Message_Id_Type; 95 Partition : Partition_ID; 96 Params_Size : Ada.Streams.Stream_Element_Count; 97 Result_Size : Ada.Streams.Stream_Element_Count; 98 Protocol : Garlic.Protocol_Access); 99 -- This entry provides an anonymous task a remote call to perform. 100 -- This task calls for a Request id is provided to construct the 101 -- reply id by using -Request. Partition is used to send the reply 102 -- message. Params_Size is the size of the calling stub Params stream. 103 -- Then Protocol (used by the environment task previously) allows 104 -- extraction of the message following the header (The header is 105 -- extracted by the environment task) 106 -- Note: grammar in above is obscure??? needs cleanup 107 108 end Anonymous_Task_Type; 109 110 type Anonymous_Task_Access is access Anonymous_Task_Type; 111 112 type Anonymous_Task_List is record 113 Head : Anonymous_Task_Node_Access; 114 Tail : Anonymous_Task_Node_Access; 115 end record; 116 117 type Anonymous_Task_Node is record 118 Element : Anonymous_Task_Access; 119 Next : Anonymous_Task_Node_Access; 120 end record; 121 -- Types we need to construct a singly linked list of anonymous tasks. 122 -- This pool is maintained to avoid a task creation each time a RPC occurs. 123 124 protected Garbage_Collector is 125 126 procedure Allocate 127 (Item : out Anonymous_Task_Node_Access); 128 -- Anonymous task pool management : if there is an anonymous task 129 -- left, use it. Otherwise, allocate a new one 130 131 procedure Deallocate 132 (Item : in out Anonymous_Task_Node_Access); 133 -- Anonymous task pool management : queue this task in the pool 134 -- of inactive anonymous tasks. 135 136 private 137 138 Anonymous_List : Anonymous_Task_Node_Access; 139 -- The list root of inactive anonymous tasks 140 141 end Garbage_Collector; 142 143 task Dispatcher is 144 145 entry New_Request (Request : out Request_Id_Type); 146 -- To get a new request 147 148 entry Wait_On (Request_Id_Type) 149 (Length : out Ada.Streams.Stream_Element_Count); 150 -- To block the calling stub when it waits for a reply 151 -- When it is resumed, we provide the size of the reply 152 153 entry Wake_Up 154 (Request : Request_Id_Type; 155 Length : Ada.Streams.Stream_Element_Count); 156 -- To wake up the calling stub when the environment task has 157 -- received a reply for this request 158 159 end Dispatcher; 160 161 task Environnement is 162 163 entry Start; 164 -- Receive no message until Partition_Receiver is set 165 -- Establish_RPC_Receiver decides when the environment task 166 -- is allowed to start 167 168 end Environnement; 169 170 protected Partition_Receiver is 171 172 entry Is_Set; 173 -- Blocks if the Partition_RPC_Receiver has not been set 174 175 procedure Set; 176 -- Done by Establish_RPC_Receiver when Partition_RPC_Receiver 177 -- is known 178 179 private 180 181 Was_Set : Boolean := False; 182 -- True when Partition_RPC_Receiver has been set 183 184 end Partition_Receiver; 185 -- Anonymous tasks have to wait for the Partition_RPC_Receiver 186 -- to be established 187 188 type Debug_Level is 189 (D_Elaborate, -- About the elaboration of this package 190 D_Communication, -- About calls to Send and Receive 191 D_Debug, -- Verbose 192 D_Exception); -- Exception handler 193 -- Debugging levels 194 195 package Debugging is new System.RPC.Net_Trace (Debug_Level, "RPC : "); 196 -- Debugging package 197 198 procedure D 199 (Flag : Debug_Level; Info : String) renames Debugging.Debug; 200 -- Shortcut 201 202 ------------------------ 203 -- Partition_Receiver -- 204 ------------------------ 205 206 protected body Partition_Receiver is 207 208 ------------------------------- 209 -- Partition_Receiver.Is_Set -- 210 ------------------------------- 211 212 entry Is_Set when Was_Set is 213 begin 214 null; 215 end Is_Set; 216 217 ---------------------------- 218 -- Partition_Receiver.Set -- 219 ---------------------------- 220 221 procedure Set is 222 begin 223 Was_Set := True; 224 end Set; 225 226 end Partition_Receiver; 227 228 --------------- 229 -- Head_Node -- 230 --------------- 231 232 procedure Head_Node 233 (Index : out Packet_Node_Access; 234 Stream : Params_Stream_Type) 235 is 236 begin 237 Index := Stream.Extra.Head; 238 239 exception 240 when others => 241 D (D_Exception, "exception in Head_Node"); 242 raise; 243 end Head_Node; 244 245 --------------- 246 -- Tail_Node -- 247 --------------- 248 249 procedure Tail_Node 250 (Index : out Packet_Node_Access; 251 Stream : Params_Stream_Type) 252 is 253 begin 254 Index := Stream.Extra.Tail; 255 256 exception 257 when others => 258 D (D_Exception, "exception in Tail_Node"); 259 raise; 260 end Tail_Node; 261 262 --------------- 263 -- Null_Node -- 264 --------------- 265 266 function Null_Node (Index : Packet_Node_Access) return Boolean is 267 begin 268 return Index = null; 269 270 exception 271 when others => 272 D (D_Exception, "exception in Null_Node"); 273 raise; 274 end Null_Node; 275 276 ---------------------- 277 -- Delete_Head_Node -- 278 ---------------------- 279 280 procedure Delete_Head_Node (Stream : in out Params_Stream_Type) is 281 282 procedure Free is 283 new Unchecked_Deallocation 284 (Packet_Node, Packet_Node_Access); 285 286 Next_Node : Packet_Node_Access := Stream.Extra.Head.Next; 287 288 begin 289 -- Delete head node and free memory usage 290 291 Free (Stream.Extra.Head); 292 Stream.Extra.Head := Next_Node; 293 294 -- If the extra storage is empty, update tail as well 295 296 if Stream.Extra.Head = null then 297 Stream.Extra.Tail := null; 298 end if; 299 300 exception 301 when others => 302 D (D_Exception, "exception in Delete_Head_Node"); 303 raise; 304 end Delete_Head_Node; 305 306 --------------- 307 -- Next_Node -- 308 --------------- 309 310 procedure Next_Node (Node : in out Packet_Node_Access) is 311 begin 312 -- Node is set to the next node 313 -- If not possible, Stream_Error is raised 314 315 if Node = null then 316 raise Stream_Error; 317 else 318 Node := Node.Next; 319 end if; 320 321 exception 322 when others => 323 D (D_Exception, "exception in Next_Node"); 324 raise; 325 end Next_Node; 326 327 --------------------- 328 -- Append_New_Node -- 329 --------------------- 330 331 procedure Append_New_Node (Stream : in out Params_Stream_Type) is 332 Index : Packet_Node_Access; 333 334 begin 335 -- Set Index to the end of the linked list 336 337 Tail_Node (Index, Stream); 338 339 if Null_Node (Index) then 340 341 -- The list is empty : set head as well 342 343 Stream.Extra.Head := new Packet_Node; 344 Stream.Extra.Tail := Stream.Extra.Head; 345 346 else 347 -- The list is not empty : link new node with tail 348 349 Stream.Extra.Tail.Next := new Packet_Node; 350 Stream.Extra.Tail := Stream.Extra.Tail.Next; 351 352 end if; 353 354 exception 355 when others => 356 D (D_Exception, "exception in Append_New_Node"); 357 raise; 358 end Append_New_Node; 359 360 ---------- 361 -- Read -- 362 ---------- 363 364 procedure Read 365 (Stream : in out Params_Stream_Type; 366 Item : out Ada.Streams.Stream_Element_Array; 367 Last : out Ada.Streams.Stream_Element_Offset) 368 renames System.RPC.Streams.Read; 369 370 ----------- 371 -- Write -- 372 ----------- 373 374 procedure Write 375 (Stream : in out Params_Stream_Type; 376 Item : Ada.Streams.Stream_Element_Array) 377 renames System.RPC.Streams.Write; 378 379 ----------------------- 380 -- Garbage_Collector -- 381 ----------------------- 382 383 protected body Garbage_Collector is 384 385 -------------------------------- 386 -- Garbage_Collector.Allocate -- 387 -------------------------------- 388 389 procedure Allocate (Item : out Anonymous_Task_Node_Access) is 390 New_Anonymous_Task_Node : Anonymous_Task_Node_Access; 391 Anonymous_Task : Anonymous_Task_Access; 392 393 begin 394 -- If the list is empty, allocate a new anonymous task 395 -- Otherwise, reuse the first queued anonymous task 396 397 if Anonymous_List = null then 398 399 -- Create a new anonymous task 400 -- Provide this new task with its id to allow it 401 -- to enqueue itself into the free anonymous task list 402 -- with the function Deallocate 403 404 New_Anonymous_Task_Node := new Anonymous_Task_Node; 405 Anonymous_Task := 406 new Anonymous_Task_Type (New_Anonymous_Task_Node); 407 New_Anonymous_Task_Node.all := (Anonymous_Task, null); 408 409 else 410 -- Extract one task from the list 411 -- Set the Next field to null to avoid possible bugs 412 413 New_Anonymous_Task_Node := Anonymous_List; 414 Anonymous_List := Anonymous_List.Next; 415 New_Anonymous_Task_Node.Next := null; 416 417 end if; 418 419 -- Item is an out parameter 420 421 Item := New_Anonymous_Task_Node; 422 423 exception 424 when others => 425 D (D_Exception, "exception in Allocate (Anonymous Task)"); 426 raise; 427 end Allocate; 428 429 ---------------------------------- 430 -- Garbage_Collector.Deallocate -- 431 ---------------------------------- 432 433 procedure Deallocate (Item : in out Anonymous_Task_Node_Access) is 434 begin 435 -- Enqueue the task in the free list 436 437 Item.Next := Anonymous_List; 438 Anonymous_List := Item; 439 440 exception 441 when others => 442 D (D_Exception, "exception in Deallocate (Anonymous Task)"); 443 raise; 444 end Deallocate; 445 446 end Garbage_Collector; 447 448 ------------ 449 -- Do_RPC -- 450 ------------ 451 452 procedure Do_RPC 453 (Partition : Partition_ID; 454 Params : access Params_Stream_Type; 455 Result : access Params_Stream_Type) 456 is 457 Protocol : Protocol_Access; 458 Request : Request_Id_Type; 459 Header : aliased Params_Stream_Type (Header_Size); 460 R_Length : Ada.Streams.Stream_Element_Count; 461 462 begin 463 -- Parameters order : 464 -- Opcode (provided and used by garlic) 465 -- (1) Size (provided by s-rpc and used by garlic) 466 -- (size of (2)+(3)+(4)+(5)) 467 -- (2) Request (provided by calling stub (resp receiving stub) and 468 -- used by anonymous task (resp Do_RPC)) 469 -- *** ZERO IF APC *** 470 -- (3) Res.len. (provided by calling stubs and used by anonymous task) 471 -- *** ZERO IF APC *** 472 -- (4) Receiver (provided by calling stubs and used by anonymous task) 473 -- (5) Params (provided by calling stubs and used by anonymous task) 474 475 -- The call is a remote call or a local call. A local call occurs 476 -- when the pragma All_Calls_Remote has been specified. Do_RPC is 477 -- called and the execution has to be performed in the PCS 478 479 if Partition /= Garlic.Get_My_Partition_ID then 480 481 -- Get a request id to be resumed when the reply arrives 482 483 Dispatcher.New_Request (Request); 484 485 -- Build header = request (2) + result.initial_size (3) 486 487 D (D_Debug, "Do_RPC - Build header"); 488 Streams.Allocate (Header); 489 Streams.Integer_Write_Attribute -- (2) 490 (Header'Access, Request); 491 System.RPC.Streams.SEC_Write_Attribute -- (3) 492 (Header'Access, Result.Initial_Size); 493 494 -- Get a protocol method to communicate with the remote partition 495 -- and give the message size 496 497 D (D_Communication, 498 "Do_RPC - Lookup for protocol to talk to partition" & 499 Partition_ID'Image (Partition)); 500 Garlic.Initiate_Send 501 (Partition, 502 Streams.Get_Stream_Size (Header'Access) + 503 Streams.Get_Stream_Size (Params), -- (1) 504 Protocol, 505 Garlic.Remote_Call); 506 507 -- Send the header by using the protocol method 508 509 D (D_Communication, "Do_RPC - Send Header to partition" & 510 Partition_ID'Image (Partition)); 511 Garlic.Send 512 (Protocol.all, 513 Partition, 514 Header'Access); -- (2) + (3) 515 516 -- The header is deallocated 517 518 Streams.Deallocate (Header); 519 520 -- Send Params from Do_RPC 521 522 D (D_Communication, "Do_RPC - Send Params to partition" & 523 Partition_ID'Image (Partition)); 524 Garlic.Send 525 (Protocol.all, 526 Partition, 527 Params); -- (4) + (5) 528 529 -- Let Garlic know we have nothing else to send 530 531 Garlic.Complete_Send 532 (Protocol.all, 533 Partition); 534 D (D_Debug, "Do_RPC - Suspend"); 535 536 -- Wait for a reply and get the reply message length 537 538 Dispatcher.Wait_On (Request) (R_Length); 539 D (D_Debug, "Do_RPC - Resume"); 540 541 declare 542 New_Result : aliased Params_Stream_Type (R_Length); 543 begin 544 -- Adjust the Result stream size right now to be able to load 545 -- the stream in one receive call. Create a temporary result 546 -- that will be substituted to Do_RPC one 547 548 Streams.Allocate (New_Result); 549 550 -- Receive the reply message from receiving stub 551 552 D (D_Communication, "Do_RPC - Receive Result from partition" & 553 Partition_ID'Image (Partition)); 554 Garlic.Receive 555 (Protocol.all, 556 Partition, 557 New_Result'Access); 558 559 -- Let Garlic know we have nothing else to receive 560 561 Garlic.Complete_Receive 562 (Protocol.all, 563 Partition); 564 565 -- Update calling stub Result stream 566 567 D (D_Debug, "Do_RPC - Reconstruct Result"); 568 Streams.Deallocate (Result.all); 569 Result.Initial := New_Result.Initial; 570 Streams.Dump ("|||", Result.all); 571 572 end; 573 574 else 575 -- Do RPC locally and first wait for Partition_RPC_Receiver to be 576 -- set 577 578 Partition_Receiver.Is_Set; 579 D (D_Debug, "Do_RPC - Locally"); 580 Partition_RPC_Receiver.all (Params, Result); 581 582 end if; 583 584 exception 585 when others => 586 D (D_Exception, "exception in Do_RPC"); 587 raise; 588 end Do_RPC; 589 590 ------------ 591 -- Do_APC -- 592 ------------ 593 594 procedure Do_APC 595 (Partition : Partition_ID; 596 Params : access Params_Stream_Type) 597 is 598 Message_Id : Message_Id_Type := 0; 599 Protocol : Protocol_Access; 600 Header : aliased Params_Stream_Type (Header_Size); 601 602 begin 603 -- For more information, see above 604 -- Request = 0 as we are not waiting for a reply message 605 -- Result length = 0 as we don't expect a result at all 606 607 if Partition /= Garlic.Get_My_Partition_ID then 608 609 -- Build header = request (2) + result.initial_size (3) 610 -- As we have an APC, the request id is null to indicate 611 -- to the receiving stub that we do not expect a reply 612 -- This comes from 0 = -0 613 614 D (D_Debug, "Do_APC - Build Header"); 615 Streams.Allocate (Header); 616 Streams.Integer_Write_Attribute 617 (Header'Access, Integer (Message_Id)); 618 Streams.SEC_Write_Attribute 619 (Header'Access, 0); 620 621 -- Get a protocol method to communicate with the remote partition 622 -- and give the message size 623 624 D (D_Communication, 625 "Do_APC - Lookup for protocol to talk to partition" & 626 Partition_ID'Image (Partition)); 627 Garlic.Initiate_Send 628 (Partition, 629 Streams.Get_Stream_Size (Header'Access) + 630 Streams.Get_Stream_Size (Params), 631 Protocol, 632 Garlic.Remote_Call); 633 634 -- Send the header by using the protocol method 635 636 D (D_Communication, "Do_APC - Send Header to partition" & 637 Partition_ID'Image (Partition)); 638 Garlic.Send 639 (Protocol.all, 640 Partition, 641 Header'Access); 642 643 -- The header is deallocated 644 645 Streams.Deallocate (Header); 646 647 -- Send Params from Do_APC 648 649 D (D_Communication, "Do_APC - Send Params to partition" & 650 Partition_ID'Image (Partition)); 651 Garlic.Send 652 (Protocol.all, 653 Partition, 654 Params); 655 656 -- Let Garlic know we have nothing else to send 657 658 Garlic.Complete_Send 659 (Protocol.all, 660 Partition); 661 else 662 663 declare 664 Result : aliased Params_Stream_Type (0); 665 begin 666 -- Result is here a dummy parameter 667 -- No reason to deallocate as it is not allocated at all 668 669 Partition_Receiver.Is_Set; 670 D (D_Debug, "Do_APC - Locally"); 671 Partition_RPC_Receiver.all (Params, Result'Access); 672 673 end; 674 675 end if; 676 677 exception 678 when others => 679 D (D_Exception, "exception in Do_APC"); 680 raise; 681 end Do_APC; 682 683 ---------------------------- 684 -- Establish_RPC_Receiver -- 685 ---------------------------- 686 687 procedure Establish_RPC_Receiver 688 (Partition : Partition_ID; 689 Receiver : RPC_Receiver) 690 is 691 begin 692 -- Set Partition_RPC_Receiver and allow RPC mechanism 693 694 Partition_RPC_Receiver := Receiver; 695 Partition_Receiver.Set; 696 D (D_Elaborate, "Partition_Receiver is set"); 697 698 exception 699 when others => 700 D (D_Exception, "exception in Establish_RPC_Receiver"); 701 raise; 702 end Establish_RPC_Receiver; 703 704 ---------------- 705 -- Dispatcher -- 706 ---------------- 707 708 task body Dispatcher is 709 Last_Request : Request_Id_Type := Request_Id_Type'First; 710 Current_Rqst : Request_Id_Type := Request_Id_Type'First; 711 Current_Size : Ada.Streams.Stream_Element_Count; 712 713 begin 714 loop 715 -- Three services: 716 717 -- New_Request to get an entry in Dispatcher table 718 719 -- Wait_On for Do_RPC calls 720 721 -- Wake_Up called by environment task when a Do_RPC receives 722 -- the result of its remote call 723 724 select 725 accept New_Request (Request : out Request_Id_Type) do 726 Request := Last_Request; 727 728 -- << TODO >> 729 -- ??? Availability check 730 731 if Last_Request = Request_Id_Type'Last then 732 Last_Request := Request_Id_Type'First; 733 else 734 Last_Request := Last_Request + 1; 735 end if; 736 737 end New_Request; 738 739 or 740 accept Wake_Up 741 (Request : Request_Id_Type; 742 Length : Ada.Streams.Stream_Element_Count) 743 do 744 -- The environment reads the header and has been notified 745 -- of the reply id and the size of the result message 746 747 Current_Rqst := Request; 748 Current_Size := Length; 749 750 end Wake_Up; 751 752 -- << TODO >> 753 -- ??? Must be select with delay for aborted tasks 754 755 select 756 757 accept Wait_On (Current_Rqst) 758 (Length : out Ada.Streams.Stream_Element_Count) 759 do 760 Length := Current_Size; 761 end Wait_On; 762 763 or 764 -- To free the Dispatcher when a task is aborted 765 766 delay 1.0; 767 768 end select; 769 770 or 771 terminate; 772 end select; 773 774 end loop; 775 776 exception 777 when others => 778 D (D_Exception, "exception in Dispatcher body"); 779 raise; 780 end Dispatcher; 781 782 ------------------------- 783 -- Anonymous_Task_Type -- 784 ------------------------- 785 786 task body Anonymous_Task_Type is 787 Whoami : Anonymous_Task_Node_Access := Self; 788 C_Message_Id : Message_Id_Type; -- Current Message Id 789 C_Partition : Partition_ID; -- Current Partition 790 Params_S : Ada.Streams.Stream_Element_Count; -- Params message size 791 Result_S : Ada.Streams.Stream_Element_Count; -- Result message size 792 C_Protocol : Protocol_Access; -- Current Protocol 793 794 begin 795 loop 796 -- Get a new RPC to execute 797 798 select 799 accept Start 800 (Message_Id : Message_Id_Type; 801 Partition : Partition_ID; 802 Params_Size : Ada.Streams.Stream_Element_Count; 803 Result_Size : Ada.Streams.Stream_Element_Count; 804 Protocol : Protocol_Access) 805 do 806 C_Message_Id := Message_Id; 807 C_Partition := Partition; 808 Params_S := Params_Size; 809 Result_S := Result_Size; 810 C_Protocol := Protocol; 811 end Start; 812 or 813 terminate; 814 end select; 815 816 declare 817 Params : aliased Params_Stream_Type (Params_S); 818 Result : aliased Params_Stream_Type (Result_S); 819 Header : aliased Params_Stream_Type (Header_Size); 820 821 begin 822 -- We reconstruct all the client context : Params and Result 823 -- with the SAME size, then we receive Params from calling stub 824 825 D (D_Communication, 826 "Anonymous Task - Receive Params from partition" & 827 Partition_ID'Image (C_Partition)); 828 Garlic.Receive 829 (C_Protocol.all, 830 C_Partition, 831 Params'Access); 832 833 -- Let Garlic know we don't receive anymore 834 835 Garlic.Complete_Receive 836 (C_Protocol.all, 837 C_Partition); 838 839 -- Check that Partition_RPC_Receiver has been set 840 841 Partition_Receiver.Is_Set; 842 843 -- Do it locally 844 845 D (D_Debug, 846 "Anonymous Task - Perform Partition_RPC_Receiver for request" & 847 Message_Id_Type'Image (C_Message_Id)); 848 Partition_RPC_Receiver (Params'Access, Result'Access); 849 850 -- If this was a RPC we send the result back 851 -- Otherwise, do nothing else than deallocation 852 853 if C_Message_Id /= 0 then 854 855 -- Build Header = -C_Message_Id + Result Size 856 -- Provide the request id to the env task of the calling 857 -- stub partition We get the real result stream size : the 858 -- calling stub (in Do_RPC) updates its size to this one 859 860 D (D_Debug, "Anonymous Task - Build Header"); 861 Streams.Allocate (Header); 862 Streams.Integer_Write_Attribute 863 (Header'Access, Integer (-C_Message_Id)); 864 Streams.SEC_Write_Attribute 865 (Header'Access, 866 Streams.Get_Stream_Size (Result'Access)); 867 868 -- Get a protocol method to communicate with the remote 869 -- partition and give the message size 870 871 D (D_Communication, 872 "Anonymous Task - Lookup for protocol talk to partition" & 873 Partition_ID'Image (C_Partition)); 874 Garlic.Initiate_Send 875 (C_Partition, 876 Streams.Get_Stream_Size (Header'Access) + 877 Streams.Get_Stream_Size (Result'Access), 878 C_Protocol, 879 Garlic.Remote_Call); 880 881 -- Send the header by using the protocol method 882 883 D (D_Communication, 884 "Anonymous Task - Send Header to partition" & 885 Partition_ID'Image (C_Partition)); 886 Garlic.Send 887 (C_Protocol.all, 888 C_Partition, 889 Header'Access); 890 891 -- Send Result toDo_RPC 892 893 D (D_Communication, 894 "Anonymous Task - Send Result to partition" & 895 Partition_ID'Image (C_Partition)); 896 Garlic.Send 897 (C_Protocol.all, 898 C_Partition, 899 Result'Access); 900 901 -- Let Garlic know we don't send anymore 902 903 Garlic.Complete_Send 904 (C_Protocol.all, 905 C_Partition); 906 Streams.Deallocate (Header); 907 end if; 908 909 Streams.Deallocate (Params); 910 Streams.Deallocate (Result); 911 end; 912 913 -- Enqueue into the anonymous task free list : become inactive 914 915 Garbage_Collector.Deallocate (Whoami); 916 917 end loop; 918 919 exception 920 when others => 921 D (D_Exception, "exception in Anonymous_Task_Type body"); 922 raise; 923 end Anonymous_Task_Type; 924 925 ----------------- 926 -- Environment -- 927 ----------------- 928 929 task body Environnement is 930 Partition : Partition_ID; 931 Message_Size : Ada.Streams.Stream_Element_Count; 932 Result_Size : Ada.Streams.Stream_Element_Count; 933 Message_Id : Message_Id_Type; 934 Header : aliased Params_Stream_Type (Header_Size); 935 Protocol : Protocol_Access; 936 Anonymous : Anonymous_Task_Node_Access; 937 938 begin 939 -- Wait the Partition_RPC_Receiver to be set 940 941 accept Start; 942 D (D_Elaborate, "Environment task elaborated"); 943 944 loop 945 -- We receive first a fixed size message : the header 946 -- Header = Message Id + Message Size 947 948 Streams.Allocate (Header); 949 950 -- Garlic provides the size of the received message and the 951 -- protocol to use to communicate with the calling partition 952 953 Garlic.Initiate_Receive 954 (Partition, 955 Message_Size, 956 Protocol, 957 Garlic.Remote_Call); 958 D (D_Communication, 959 "Environment task - Receive protocol to talk to active partition" & 960 Partition_ID'Image (Partition)); 961 962 -- Extract the header to route the message either to 963 -- an anonymous task (Message Id > 0 <=> Request Id) 964 -- or to a waiting task (Message Id < 0 <=> Reply Id) 965 966 D (D_Communication, 967 "Environment task - Receive Header from partition" & 968 Partition_ID'Image (Partition)); 969 Garlic.Receive 970 (Protocol.all, 971 Partition, 972 Header'Access); 973 974 -- Evaluate the remaining size of the message 975 976 Message_Size := Message_Size - 977 Streams.Get_Stream_Size (Header'Access); 978 979 -- Extract from header : message id and message size 980 981 Streams.Integer_Read_Attribute (Header'Access, Message_Id); 982 Streams.SEC_Read_Attribute (Header'Access, Result_Size); 983 984 if Streams.Get_Stream_Size (Header'Access) /= 0 then 985 986 -- If there are stream elements left in the header ??? 987 988 D (D_Exception, "Header is not empty"); 989 raise Program_Error; 990 991 end if; 992 993 if Message_Id < 0 then 994 995 -- The message was sent by a receiving stub : wake up the 996 -- calling task - We have a reply there 997 998 D (D_Debug, "Environment Task - Receive Reply from partition" & 999 Partition_ID'Image (Partition)); 1000 Dispatcher.Wake_Up (-Message_Id, Result_Size); 1001 1002 else 1003 -- The message was send by a calling stub : get an anonymous 1004 -- task to perform the job 1005 1006 D (D_Debug, "Environment Task - Receive Request from partition" & 1007 Partition_ID'Image (Partition)); 1008 Garbage_Collector.Allocate (Anonymous); 1009 1010 -- We subtracted the size of the header from the size of the 1011 -- global message in order to provide immediately Params size 1012 1013 Anonymous.Element.Start 1014 (Message_Id, 1015 Partition, 1016 Message_Size, 1017 Result_Size, 1018 Protocol); 1019 1020 end if; 1021 1022 -- Deallocate header : unnecessary - WARNING 1023 1024 Streams.Deallocate (Header); 1025 1026 end loop; 1027 1028 exception 1029 when others => 1030 D (D_Exception, "exception in Environment"); 1031 raise; 1032 end Environnement; 1033 1034begin 1035 -- Set debugging information 1036 1037 Debugging.Set_Environment_Variable ("RPC"); 1038 Debugging.Set_Debugging_Name ("D", D_Debug); 1039 Debugging.Set_Debugging_Name ("E", D_Exception); 1040 Debugging.Set_Debugging_Name ("C", D_Communication); 1041 Debugging.Set_Debugging_Name ("Z", D_Elaborate); 1042 D (D_Elaborate, "To be elaborated"); 1043 1044 -- When this body is elaborated we should ensure that RCI name server 1045 -- has been already elaborated : this means that Establish_RPC_Receiver 1046 -- has already been called and that Partition_RPC_Receiver is set 1047 1048 Environnement.Start; 1049 D (D_Elaborate, "ELABORATED"); 1050 1051end System.RPC; 1052