1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- S Y S T E M . S T O R A G E _ P O O L S . S U B P O O L S -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2011-2019, 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 32with Ada.Exceptions; use Ada.Exceptions; 33with Ada.Unchecked_Conversion; 34 35with System.Address_Image; 36with System.Finalization_Masters; use System.Finalization_Masters; 37with System.IO; use System.IO; 38with System.Soft_Links; use System.Soft_Links; 39with System.Storage_Elements; use System.Storage_Elements; 40 41with System.Storage_Pools.Subpools.Finalization; 42use System.Storage_Pools.Subpools.Finalization; 43 44package body System.Storage_Pools.Subpools is 45 46 Finalize_Address_Table_In_Use : Boolean := False; 47 -- This flag should be set only when a successful allocation on a subpool 48 -- has been performed and the associated Finalize_Address has been added to 49 -- the hash table in System.Finalization_Masters. 50 51 function Address_To_FM_Node_Ptr is 52 new Ada.Unchecked_Conversion (Address, FM_Node_Ptr); 53 54 procedure Attach (N : not null SP_Node_Ptr; L : not null SP_Node_Ptr); 55 -- Attach a subpool node to a pool 56 57 ----------------------------------- 58 -- Adjust_Controlled_Dereference -- 59 ----------------------------------- 60 61 procedure Adjust_Controlled_Dereference 62 (Addr : in out System.Address; 63 Storage_Size : in out System.Storage_Elements.Storage_Count; 64 Alignment : System.Storage_Elements.Storage_Count) 65 is 66 Header_And_Padding : constant Storage_Offset := 67 Header_Size_With_Padding (Alignment); 68 begin 69 -- Expose the two hidden pointers by shifting the address from the 70 -- start of the object to the FM_Node equivalent of the pointers. 71 72 Addr := Addr - Header_And_Padding; 73 74 -- Update the size of the object to include the two pointers 75 76 Storage_Size := Storage_Size + Header_And_Padding; 77 end Adjust_Controlled_Dereference; 78 79 -------------- 80 -- Allocate -- 81 -------------- 82 83 overriding procedure Allocate 84 (Pool : in out Root_Storage_Pool_With_Subpools; 85 Storage_Address : out System.Address; 86 Size_In_Storage_Elements : System.Storage_Elements.Storage_Count; 87 Alignment : System.Storage_Elements.Storage_Count) 88 is 89 begin 90 -- Dispatch to the user-defined implementations of Allocate_From_Subpool 91 -- and Default_Subpool_For_Pool. 92 93 Allocate_From_Subpool 94 (Root_Storage_Pool_With_Subpools'Class (Pool), 95 Storage_Address, 96 Size_In_Storage_Elements, 97 Alignment, 98 Default_Subpool_For_Pool 99 (Root_Storage_Pool_With_Subpools'Class (Pool))); 100 end Allocate; 101 102 ----------------------------- 103 -- Allocate_Any_Controlled -- 104 ----------------------------- 105 106 procedure Allocate_Any_Controlled 107 (Pool : in out Root_Storage_Pool'Class; 108 Context_Subpool : Subpool_Handle; 109 Context_Master : Finalization_Masters.Finalization_Master_Ptr; 110 Fin_Address : Finalization_Masters.Finalize_Address_Ptr; 111 Addr : out System.Address; 112 Storage_Size : System.Storage_Elements.Storage_Count; 113 Alignment : System.Storage_Elements.Storage_Count; 114 Is_Controlled : Boolean; 115 On_Subpool : Boolean) 116 is 117 Is_Subpool_Allocation : constant Boolean := 118 Pool in Root_Storage_Pool_With_Subpools'Class; 119 120 Master : Finalization_Master_Ptr := null; 121 N_Addr : Address; 122 N_Ptr : FM_Node_Ptr; 123 N_Size : Storage_Count; 124 Subpool : Subpool_Handle := null; 125 126 Header_And_Padding : Storage_Offset; 127 -- This offset includes the size of a FM_Node plus any additional 128 -- padding due to a larger alignment. 129 130 begin 131 -- Step 1: Pool-related runtime checks 132 133 -- Allocation on a pool_with_subpools. In this scenario there is a 134 -- master for each subpool. The master of the access type is ignored. 135 136 if Is_Subpool_Allocation then 137 138 -- Case of an allocation without a Subpool_Handle. Dispatch to the 139 -- implementation of Default_Subpool_For_Pool. 140 141 if Context_Subpool = null then 142 Subpool := 143 Default_Subpool_For_Pool 144 (Root_Storage_Pool_With_Subpools'Class (Pool)); 145 146 -- Allocation with a Subpool_Handle 147 148 else 149 Subpool := Context_Subpool; 150 end if; 151 152 -- Ensure proper ownership and chaining of the subpool 153 154 if Subpool.Owner /= 155 Root_Storage_Pool_With_Subpools'Class (Pool)'Unchecked_Access 156 or else Subpool.Node = null 157 or else Subpool.Node.Prev = null 158 or else Subpool.Node.Next = null 159 then 160 raise Program_Error with "incorrect owner of subpool"; 161 end if; 162 163 Master := Subpool.Master'Unchecked_Access; 164 165 -- Allocation on a simple pool. In this scenario there is a master for 166 -- each access-to-controlled type. No context subpool should be present. 167 168 else 169 -- If the master is missing, then the expansion of the access type 170 -- failed to create one. This is a compiler bug. 171 172 pragma Assert 173 (Context_Master /= null, "missing master in pool allocation"); 174 175 -- If a subpool is present, then this is the result of erroneous 176 -- allocator expansion. This is not a serious error, but it should 177 -- still be detected. 178 179 if Context_Subpool /= null then 180 raise Program_Error 181 with "subpool not required in pool allocation"; 182 end if; 183 184 -- If the allocation is intended to be on a subpool, but the access 185 -- type's pool does not support subpools, then this is the result of 186 -- incorrect end-user code. 187 188 if On_Subpool then 189 raise Program_Error 190 with "pool of access type does not support subpools"; 191 end if; 192 193 Master := Context_Master; 194 end if; 195 196 -- Step 2: Master, Finalize_Address-related runtime checks and size 197 -- calculations. 198 199 -- Allocation of a descendant from [Limited_]Controlled, a class-wide 200 -- object or a record with controlled components. 201 202 if Is_Controlled then 203 204 -- Synchronization: 205 -- Read - allocation, finalization 206 -- Write - finalization 207 208 Lock_Task.all; 209 210 -- Do not allow the allocation of controlled objects while the 211 -- associated master is being finalized. 212 213 if Finalization_Started (Master.all) then 214 raise Program_Error with "allocation after finalization started"; 215 end if; 216 217 -- Check whether primitive Finalize_Address is available. If it is 218 -- not, then either the expansion of the designated type failed or 219 -- the expansion of the allocator failed. This is a compiler bug. 220 221 pragma Assert 222 (Fin_Address /= null, "primitive Finalize_Address not available"); 223 224 -- The size must account for the hidden header preceding the object. 225 -- Account for possible padding space before the header due to a 226 -- larger alignment. 227 228 Header_And_Padding := Header_Size_With_Padding (Alignment); 229 230 N_Size := Storage_Size + Header_And_Padding; 231 232 -- Non-controlled allocation 233 234 else 235 N_Size := Storage_Size; 236 end if; 237 238 -- Step 3: Allocation of object 239 240 -- For descendants of Root_Storage_Pool_With_Subpools, dispatch to the 241 -- implementation of Allocate_From_Subpool. 242 243 if Is_Subpool_Allocation then 244 Allocate_From_Subpool 245 (Root_Storage_Pool_With_Subpools'Class (Pool), 246 N_Addr, N_Size, Alignment, Subpool); 247 248 -- For descendants of Root_Storage_Pool, dispatch to the implementation 249 -- of Allocate. 250 251 else 252 Allocate (Pool, N_Addr, N_Size, Alignment); 253 end if; 254 255 -- Step 4: Attachment 256 257 if Is_Controlled then 258 259 -- Note that we already did "Lock_Task.all;" in Step 2 above 260 261 -- Map the allocated memory into a FM_Node record. This converts the 262 -- top of the allocated bits into a list header. If there is padding 263 -- due to larger alignment, the header is placed right next to the 264 -- object: 265 266 -- N_Addr N_Ptr 267 -- | | 268 -- V V 269 -- +-------+---------------+----------------------+ 270 -- |Padding| Header | Object | 271 -- +-------+---------------+----------------------+ 272 -- ^ ^ ^ 273 -- | +- Header_Size -+ 274 -- | | 275 -- +- Header_And_Padding --+ 276 277 N_Ptr := 278 Address_To_FM_Node_Ptr (N_Addr + Header_And_Padding - Header_Size); 279 280 -- Prepend the allocated object to the finalization master 281 282 -- Synchronization: 283 -- Write - allocation, deallocation, finalization 284 285 Attach_Unprotected (N_Ptr, Objects (Master.all)); 286 287 -- Move the address from the hidden list header to the start of the 288 -- object. This operation effectively hides the list header. 289 290 Addr := N_Addr + Header_And_Padding; 291 292 -- Homogeneous masters service the following: 293 294 -- 1) Allocations on / Deallocations from regular pools 295 -- 2) Named access types 296 -- 3) Most cases of anonymous access types usage 297 298 -- Synchronization: 299 -- Read - allocation, finalization 300 -- Write - outside 301 302 if Master.Is_Homogeneous then 303 304 -- Synchronization: 305 -- Read - finalization 306 -- Write - allocation, outside 307 308 Set_Finalize_Address_Unprotected (Master.all, Fin_Address); 309 310 -- Heterogeneous masters service the following: 311 312 -- 1) Allocations on / Deallocations from subpools 313 -- 2) Certain cases of anonymous access types usage 314 315 else 316 -- Synchronization: 317 -- Read - finalization 318 -- Write - allocation, deallocation 319 320 Set_Heterogeneous_Finalize_Address_Unprotected (Addr, Fin_Address); 321 Finalize_Address_Table_In_Use := True; 322 end if; 323 324 Unlock_Task.all; 325 326 -- Non-controlled allocation 327 328 else 329 Addr := N_Addr; 330 end if; 331 332 exception 333 when others => 334 335 -- Unlock the task in case the allocation step failed and reraise the 336 -- exception. 337 338 if Is_Controlled then 339 Unlock_Task.all; 340 end if; 341 342 raise; 343 end Allocate_Any_Controlled; 344 345 ------------ 346 -- Attach -- 347 ------------ 348 349 procedure Attach (N : not null SP_Node_Ptr; L : not null SP_Node_Ptr) is 350 begin 351 -- Ensure that the node has not been attached already 352 353 pragma Assert (N.Prev = null and then N.Next = null); 354 355 Lock_Task.all; 356 357 L.Next.Prev := N; 358 N.Next := L.Next; 359 L.Next := N; 360 N.Prev := L; 361 362 Unlock_Task.all; 363 364 -- Note: No need to unlock in case of an exception because the above 365 -- code can never raise one. 366 end Attach; 367 368 ------------------------------- 369 -- Deallocate_Any_Controlled -- 370 ------------------------------- 371 372 procedure Deallocate_Any_Controlled 373 (Pool : in out Root_Storage_Pool'Class; 374 Addr : System.Address; 375 Storage_Size : System.Storage_Elements.Storage_Count; 376 Alignment : System.Storage_Elements.Storage_Count; 377 Is_Controlled : Boolean) 378 is 379 N_Addr : Address; 380 N_Ptr : FM_Node_Ptr; 381 N_Size : Storage_Count; 382 383 Header_And_Padding : Storage_Offset; 384 -- This offset includes the size of a FM_Node plus any additional 385 -- padding due to a larger alignment. 386 387 begin 388 -- Step 1: Detachment 389 390 if Is_Controlled then 391 Lock_Task.all; 392 393 begin 394 -- Destroy the relation pair object - Finalize_Address since it is 395 -- no longer needed. 396 397 if Finalize_Address_Table_In_Use then 398 399 -- Synchronization: 400 -- Read - finalization 401 -- Write - allocation, deallocation 402 403 Delete_Finalize_Address_Unprotected (Addr); 404 end if; 405 406 -- Account for possible padding space before the header due to a 407 -- larger alignment. 408 409 Header_And_Padding := Header_Size_With_Padding (Alignment); 410 411 -- N_Addr N_Ptr Addr (from input) 412 -- | | | 413 -- V V V 414 -- +-------+---------------+----------------------+ 415 -- |Padding| Header | Object | 416 -- +-------+---------------+----------------------+ 417 -- ^ ^ ^ 418 -- | +- Header_Size -+ 419 -- | | 420 -- +- Header_And_Padding --+ 421 422 -- Convert the bits preceding the object into a list header 423 424 N_Ptr := Address_To_FM_Node_Ptr (Addr - Header_Size); 425 426 -- Detach the object from the related finalization master. This 427 -- action does not need to know the prior context used during 428 -- allocation. 429 430 -- Synchronization: 431 -- Write - allocation, deallocation, finalization 432 433 Detach_Unprotected (N_Ptr); 434 435 -- Move the address from the object to the beginning of the list 436 -- header. 437 438 N_Addr := Addr - Header_And_Padding; 439 440 -- The size of the deallocated object must include the size of the 441 -- hidden list header. 442 443 N_Size := Storage_Size + Header_And_Padding; 444 445 Unlock_Task.all; 446 447 exception 448 when others => 449 450 -- Unlock the task in case the computations performed above 451 -- fail for some reason. 452 453 Unlock_Task.all; 454 raise; 455 end; 456 else 457 N_Addr := Addr; 458 N_Size := Storage_Size; 459 end if; 460 461 -- Step 2: Deallocation 462 463 -- Dispatch to the proper implementation of Deallocate. This action 464 -- covers both Root_Storage_Pool and Root_Storage_Pool_With_Subpools 465 -- implementations. 466 467 Deallocate (Pool, N_Addr, N_Size, Alignment); 468 end Deallocate_Any_Controlled; 469 470 ------------------------------ 471 -- Default_Subpool_For_Pool -- 472 ------------------------------ 473 474 function Default_Subpool_For_Pool 475 (Pool : in out Root_Storage_Pool_With_Subpools) 476 return not null Subpool_Handle 477 is 478 pragma Unreferenced (Pool); 479 begin 480 return raise Program_Error with 481 "default Default_Subpool_For_Pool called; must be overridden"; 482 end Default_Subpool_For_Pool; 483 484 ------------ 485 -- Detach -- 486 ------------ 487 488 procedure Detach (N : not null SP_Node_Ptr) is 489 begin 490 -- Ensure that the node is attached to some list 491 492 pragma Assert (N.Next /= null and then N.Prev /= null); 493 494 Lock_Task.all; 495 496 N.Prev.Next := N.Next; 497 N.Next.Prev := N.Prev; 498 N.Prev := null; 499 N.Next := null; 500 501 Unlock_Task.all; 502 503 -- Note: No need to unlock in case of an exception because the above 504 -- code can never raise one. 505 end Detach; 506 507 -------------- 508 -- Finalize -- 509 -------------- 510 511 overriding procedure Finalize (Controller : in out Pool_Controller) is 512 begin 513 Finalize_Pool (Controller.Enclosing_Pool.all); 514 end Finalize; 515 516 ------------------- 517 -- Finalize_Pool -- 518 ------------------- 519 520 procedure Finalize_Pool (Pool : in out Root_Storage_Pool_With_Subpools) is 521 Curr_Ptr : SP_Node_Ptr; 522 Ex_Occur : Exception_Occurrence; 523 Raised : Boolean := False; 524 525 function Is_Empty_List (L : not null SP_Node_Ptr) return Boolean; 526 -- Determine whether a list contains only one element, the dummy head 527 528 ------------------- 529 -- Is_Empty_List -- 530 ------------------- 531 532 function Is_Empty_List (L : not null SP_Node_Ptr) return Boolean is 533 begin 534 return L.Next = L and then L.Prev = L; 535 end Is_Empty_List; 536 537 -- Start of processing for Finalize_Pool 538 539 begin 540 -- It is possible for multiple tasks to cause the finalization of a 541 -- common pool. Allow only one task to finalize the contents. 542 543 if Pool.Finalization_Started then 544 return; 545 end if; 546 547 -- Lock the pool to prevent the creation of additional subpools while 548 -- the available ones are finalized. The pool remains locked because 549 -- either it is about to be deallocated or the associated access type 550 -- is about to go out of scope. 551 552 Pool.Finalization_Started := True; 553 554 while not Is_Empty_List (Pool.Subpools'Unchecked_Access) loop 555 Curr_Ptr := Pool.Subpools.Next; 556 557 -- Perform the following actions: 558 559 -- 1) Finalize all objects chained on the subpool's master 560 -- 2) Remove the subpool from the owner's list of subpools 561 -- 3) Deallocate the doubly linked list node associated with the 562 -- subpool. 563 -- 4) Call Deallocate_Subpool 564 565 begin 566 Finalize_And_Deallocate (Curr_Ptr.Subpool); 567 568 exception 569 when Fin_Occur : others => 570 if not Raised then 571 Raised := True; 572 Save_Occurrence (Ex_Occur, Fin_Occur); 573 end if; 574 end; 575 end loop; 576 577 -- If the finalization of a particular master failed, reraise the 578 -- exception now. 579 580 if Raised then 581 Reraise_Occurrence (Ex_Occur); 582 end if; 583 end Finalize_Pool; 584 585 ------------------------------ 586 -- Header_Size_With_Padding -- 587 ------------------------------ 588 589 function Header_Size_With_Padding 590 (Alignment : System.Storage_Elements.Storage_Count) 591 return System.Storage_Elements.Storage_Count 592 is 593 Size : constant Storage_Count := Header_Size; 594 595 begin 596 if Size mod Alignment = 0 then 597 return Size; 598 599 -- Add enough padding to reach the nearest multiple of the alignment 600 -- rounding up. 601 602 else 603 return ((Size + Alignment - 1) / Alignment) * Alignment; 604 end if; 605 end Header_Size_With_Padding; 606 607 ---------------- 608 -- Initialize -- 609 ---------------- 610 611 overriding procedure Initialize (Controller : in out Pool_Controller) is 612 begin 613 Initialize_Pool (Controller.Enclosing_Pool.all); 614 end Initialize; 615 616 --------------------- 617 -- Initialize_Pool -- 618 --------------------- 619 620 procedure Initialize_Pool (Pool : in out Root_Storage_Pool_With_Subpools) is 621 begin 622 -- The dummy head must point to itself in both directions 623 624 Pool.Subpools.Next := Pool.Subpools'Unchecked_Access; 625 Pool.Subpools.Prev := Pool.Subpools'Unchecked_Access; 626 end Initialize_Pool; 627 628 --------------------- 629 -- Pool_Of_Subpool -- 630 --------------------- 631 632 function Pool_Of_Subpool 633 (Subpool : not null Subpool_Handle) 634 return access Root_Storage_Pool_With_Subpools'Class 635 is 636 begin 637 return Subpool.Owner; 638 end Pool_Of_Subpool; 639 640 ---------------- 641 -- Print_Pool -- 642 ---------------- 643 644 procedure Print_Pool (Pool : Root_Storage_Pool_With_Subpools) is 645 Head : constant SP_Node_Ptr := Pool.Subpools'Unrestricted_Access; 646 Head_Seen : Boolean := False; 647 SP_Ptr : SP_Node_Ptr; 648 649 begin 650 -- Output the contents of the pool 651 652 -- Pool : 0x123456789 653 -- Subpools : 0x123456789 654 -- Fin_Start : TRUE <or> FALSE 655 -- Controller: OK <or> NOK 656 657 Put ("Pool : "); 658 Put_Line (Address_Image (Pool'Address)); 659 660 Put ("Subpools : "); 661 Put_Line (Address_Image (Pool.Subpools'Address)); 662 663 Put ("Fin_Start : "); 664 Put_Line (Pool.Finalization_Started'Img); 665 666 Put ("Controlled: "); 667 if Pool.Controller.Enclosing_Pool = Pool'Unrestricted_Access then 668 Put_Line ("OK"); 669 else 670 Put_Line ("NOK (ERROR)"); 671 end if; 672 673 SP_Ptr := Head; 674 while SP_Ptr /= null loop -- Should never be null 675 Put_Line ("V"); 676 677 -- We see the head initially; we want to exit when we see the head a 678 -- second time. 679 680 if SP_Ptr = Head then 681 exit when Head_Seen; 682 683 Head_Seen := True; 684 end if; 685 686 -- The current element is null. This should never happend since the 687 -- list is circular. 688 689 if SP_Ptr.Prev = null then 690 Put_Line ("null (ERROR)"); 691 692 -- The current element points back to the correct element 693 694 elsif SP_Ptr.Prev.Next = SP_Ptr then 695 Put_Line ("^"); 696 697 -- The current element points to an erroneous element 698 699 else 700 Put_Line ("? (ERROR)"); 701 end if; 702 703 -- Output the contents of the node 704 705 Put ("|Header: "); 706 Put (Address_Image (SP_Ptr.all'Address)); 707 if SP_Ptr = Head then 708 Put_Line (" (dummy head)"); 709 else 710 Put_Line (""); 711 end if; 712 713 Put ("| Prev: "); 714 715 if SP_Ptr.Prev = null then 716 Put_Line ("null"); 717 else 718 Put_Line (Address_Image (SP_Ptr.Prev.all'Address)); 719 end if; 720 721 Put ("| Next: "); 722 723 if SP_Ptr.Next = null then 724 Put_Line ("null"); 725 else 726 Put_Line (Address_Image (SP_Ptr.Next.all'Address)); 727 end if; 728 729 Put ("| Subp: "); 730 731 if SP_Ptr.Subpool = null then 732 Put_Line ("null"); 733 else 734 Put_Line (Address_Image (SP_Ptr.Subpool.all'Address)); 735 end if; 736 737 SP_Ptr := SP_Ptr.Next; 738 end loop; 739 end Print_Pool; 740 741 ------------------- 742 -- Print_Subpool -- 743 ------------------- 744 745 procedure Print_Subpool (Subpool : Subpool_Handle) is 746 begin 747 if Subpool = null then 748 Put_Line ("null"); 749 return; 750 end if; 751 752 -- Output the contents of a subpool 753 754 -- Owner : 0x123456789 755 -- Master: 0x123456789 756 -- Node : 0x123456789 757 758 Put ("Owner : "); 759 if Subpool.Owner = null then 760 Put_Line ("null"); 761 else 762 Put_Line (Address_Image (Subpool.Owner'Address)); 763 end if; 764 765 Put ("Master: "); 766 Put_Line (Address_Image (Subpool.Master'Address)); 767 768 Put ("Node : "); 769 if Subpool.Node = null then 770 Put ("null"); 771 772 if Subpool.Owner = null then 773 Put_Line (" OK"); 774 else 775 Put_Line (" (ERROR)"); 776 end if; 777 else 778 Put_Line (Address_Image (Subpool.Node'Address)); 779 end if; 780 781 Print_Master (Subpool.Master); 782 end Print_Subpool; 783 784 ------------------------- 785 -- Set_Pool_Of_Subpool -- 786 ------------------------- 787 788 procedure Set_Pool_Of_Subpool 789 (Subpool : not null Subpool_Handle; 790 To : in out Root_Storage_Pool_With_Subpools'Class) 791 is 792 N_Ptr : SP_Node_Ptr; 793 794 begin 795 -- If the subpool is already owned, raise Program_Error. This is a 796 -- direct violation of the RM rules. 797 798 if Subpool.Owner /= null then 799 raise Program_Error with "subpool already belongs to a pool"; 800 end if; 801 802 -- Prevent the creation of a new subpool while the owner is being 803 -- finalized. This is a serious error. 804 805 if To.Finalization_Started then 806 raise Program_Error 807 with "subpool creation after finalization started"; 808 end if; 809 810 Subpool.Owner := To'Unchecked_Access; 811 812 -- Create a subpool node and decorate it. Since this node is not 813 -- allocated on the owner's pool, it must be explicitly destroyed by 814 -- Finalize_And_Detach. 815 816 N_Ptr := new SP_Node; 817 N_Ptr.Subpool := Subpool; 818 Subpool.Node := N_Ptr; 819 820 Attach (N_Ptr, To.Subpools'Unchecked_Access); 821 822 -- Mark the subpool's master as being a heterogeneous collection of 823 -- controlled objects. 824 825 Set_Is_Heterogeneous (Subpool.Master); 826 end Set_Pool_Of_Subpool; 827 828end System.Storage_Pools.Subpools; 829