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