13.11.4 Storage Subpools
1/3
{
AI05-0111-3}
This subclause defines a package to support the
partitioning of a storage pool into subpools. A subpool may be specified
as the default to be used for allocation from the associated storage
pool, or a particular subpool may be specified as part of an allocator
(see 4.8).
Static Semantics
2/3
{
AI05-0111-3}
The following language-defined library package
exists:
3/3
package System.Storage_Pools.Subpools is
pragma Preelaborate (Subpools);
4/3
type Root_Storage_Pool_With_Subpools is
abstract new Root_Storage_Pool with private;
5/3
type Root_Subpool is abstract tagged limited private;
6/3
type Subpool_Handle is access all Root_Subpool'Class;
for Subpool_Handle'Storage_Size use 0;
7/3
function Create_Subpool (Pool : in out Root_Storage_Pool_With_Subpools)
return not null Subpool_Handle is abstract;
8/3
{
AI05-0252-1}
-- The following operations are intended for pool implementers:
9/3
function Pool_of_Subpool (Subpool : not null Subpool_Handle)
return access Root_Storage_Pool_With_Subpools'Class;
10/3
procedure Set_Pool_of_Subpool (
Subpool : not null Subpool_Handle;
To : in out Root_Storage_Pool_With_Subpools'Class);
11/3
procedure Allocate_From_Subpool (
Pool : in out Root_Storage_Pool_With_Subpools;
Storage_Address : out Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count;
Subpool : not null Subpool_Handle) is abstract
with Pre'Class => Pool_of_Subpool(Subpool) = Pool'Access;
12/3
procedure Deallocate_Subpool (
Pool : in out Root_Storage_Pool_With_Subpools;
Subpool : in out Subpool_Handle) is abstract
with Pre'Class => Pool_of_Subpool(Subpool) = Pool'Access;
13/3
function Default_Subpool_for_Pool (
Pool : in Root_Storage_Pool_With_Subpools)
return not null Subpool_Handle;
14/3
overriding
procedure Allocate (
Pool : in out Root_Storage_Pool_With_Subpools;
Storage_Address : out Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count);
15/3
overriding
procedure Deallocate (
Pool : in out Root_Storage_Pool_With_Subpools;
Storage_Address : in Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count) is null;
16/3
overriding
function Storage_Size (Pool : Root_Storage_Pool_With_Subpools)
return Storage_Count is (Storage_Elements.Storage_Count'Last);
17/3
private
... -- not specified by the language
end System.Storage_Pools.Subpools;
18/3
{
AI05-0111-3}
A
subpool is a separately reclaimable portion of a storage pool,
identified by an object of type Subpool_Handle (a subpool handle).
A subpool handle also identifies the enclosing storage pool, a storage
pool that supports subpools, which is a storage pool whose type is
descended from Root_Storage_Pool_With_Subpools. A subpool is created
by calling Create_Subpool or a similar constructor; the constructor returns
the subpool handle.
19/3
{
AI05-0111-3}
A subpool object is an object of a type
descended from Root_Subpool_Type. [Typically, subpool objects are managed
by the containing storage pool; only the handles need be exposed to clients
of the storage pool. Subpool objects are designated by subpool handles,
and are the run-time representation of a subpool.]
19.a/3
Proof: We know
that subpool handles designate subpool objects because the declaration
of Subpool_Handle says so.
20/3
{
AI05-0111-3}
Each subpool belongs
to a single storage pool [(which will always be a pool that supports
subpools)]. An access to the pool that a subpool belongs to can be obtained
by calling Pool_of_Subpool with the subpool handle. Set_Pool_of_Subpool
causes the subpool of the subpool handle to belong to the given pool[;
this is intended to be called from subpool constructors like Create_Subpool.]
Set_Pool_of_Subpool propagates Program_Error if the subpool already belongs
to a pool.
20.a/3
Discussion: Pool_of_Subpool
and Set_Pool_of_Subpool are provided by the Ada implementation and typically
will not be overridden by the pool implementer.
21/3
{
AI05-0111-3}
When an allocator
for a type whose storage pool supports subpools is evaluated, a call
is made on Allocate_From_Subpool passing in a Subpool_Handle, in addition
to the parameters as defined for calls on Allocate (see 13.11).
The subpool designated by the subpool_handle_name
is used, if specified in an allocator.
Otherwise, Default_Subpool_for_Pool of the Pool is used to provide a
subpool handle. All requirements on the Allocate procedure also apply
to Allocate_from_Subpool.
21.a/3
Discussion: Deallocate_Subpool
is expected to do whatever is needed to deallocate all of the objects
contained in the subpool; it is called from Unchecked_Deallocate_Subpool
(see 13.11.5).
21.b/3
Typically, the pool implementer
will not override Allocate. In the canonical definition of the language,
it will never be called for a pool that supports subpools (there is an
Implementation Permission below that allows it to be called in certain
rare cases).
Legality Rules
22/3
{
AI05-0111-3}
If a storage pool that supports subpools is specified
as the Storage_Pool for an access type, the access type is called a subpool
access type. A subpool access
type shall be a pool-specific access type.
23/3
{
AI05-0111-3}
{
AI05-0252-1}
The accessibility level of a subpool access type
shall not be statically deeper than that of the storage pool object.
If the specified storage pool object is a storage pool that supports
subpools, then the name
that denotes the object shall not denote part of a formal parameter,
nor shall it denote part of a dereference of a value of a non-library-level
general access type. In addition to the places where
Legality Rules normally apply (see 12.3),
these rules also apply in the private part of an instance of a generic
unit.
Dynamic Semantics
24/3
{
AI05-0111-3}
{
AI05-0252-1}
When an access type with a specified storage pool
is frozen (see 13.14), if the tag of the
storage pool object identifies a storage pool that supports subpools,
the following checks are made:
25/3
the name
used to specify the storage pool object does not denote part of a formal
parameter nor part of a dereference of a value of a non-library-level
general access type; and
26/3
the accessibility level of
the access type is not deeper than that of the storage pool object.
27/3
{
AI05-0252-1}
Program_Error is raised if either of these checks
fail.
27.a/3
Reason: This check
(and its static counterpart) ensures that the type of the allocated objects
exists at least as long as the storage pool object, so that the subpools
are finalized (which finalizes any remaining allocated objects) before
the type of the objects ceases to exist. The access type itself (and
the associated collection) will cease to exist before the storage pool
ceases to exist.
27.b/3
We also disallow the use
of formal parameters and dereferences of non-library-level general access
types when specifying a storage pool object if it supports subpools,
because the "apparent" accessibility level is potentially deeper
than that of the underlying object. Neither of these cases is very likely
to occur in practice.
28/3
{
AI05-0111-3}
A call to Subpools.Allocate(P, Addr, Size, Align)
does the following:
29/3
Allocate_From_Subpool
(Root_Storage_Pool_With_Subpools'Class(P),
Addr, Size, Align,
Subpool => Default_Subpool_for_Pool
(Root_Storage_Pool_With_Subpools'Class(P)));
30/3
{
AI05-0111-3}
An allocator
that allocates in a subpool raises Program_Error if the allocated object
has task parts.
30.a/3
Reason: This is
to ease implementation. We envision relaxing this restriction in a future
version of Ada, once implementation experience has been gained. At this
time, we are unable to come up with a set of rules for task termination
that is both useful, and surely feasible to implement.
31/3
{
AI05-0111-3}
Unless overridden, Default_Subpool_for_Pool propagates
Program_Error.
Implementation Permissions
32/3
{
AI05-0111-3}
When an allocator for a type whose storage pool
is of type Root_Storage_Pool'Class is evaluated, but supports subpools,
the implementation may call Allocate rather than Allocate_From_Subpool.
[This will have the same effect, so long as Allocate has not been overridden.]
32.a/3
Reason:
This ensures either of two implementation models are possible for
an allocator
with no subpool_specification.
Note that the "supports subpools" property is not known at
compile time for a pool of the class-wide type.
32.b/3
The implementation can
dispatch to Storage_Pools.Allocate. If the pool supports subpools, this
will call Allocate_From_Subpool with the default subpool so long as Allocate
has not been overridden.
32.c/3
The implementation can
declare Allocate_From_Subpool as a primitive of Root_Storage_Pool in
the private part of Storage_Pools. This means that the Allocate_From_Subpool
for Root_Storage_Pool_With_Subpools overrides that private one. The implementation
can thus call the private one, which will call Allocate for non-subpool-supporting
pools. The effect of this implementation does not change if Allocate
is overridden for a pool that supports subpools.
33/3
34 {
AI05-0111-3}
A user-defined storage pool type that supports
subpools can be implemented by extending the Root_Storage_Pool_With_Subpools
type, and overriding the primitive subprograms Create_Subpool, Allocate_From_Subpool,
and Deallocate_Subpool. Create_Subpool should call Set_Pool_Of_Subpool
before returning the subpool handle. To make use of such a pool, a user
would declare an object of the type extension, use it to define the Storage_Pool
attribute of one or more access types, and then call Create_Subpool to
obtain subpool handles associated with the pool.
34/3
35 {
AI05-0111-3}
A user-defined storage pool type that supports
subpools may define additional subpool constructors similar to Create_Subpool
(these typically will have additional parameters).
35/3
36 {
AI05-0111-3}
The pool implementor should override Default_Subpool_For_Pool
if the pool is to support a default subpool for the pool. The implementor
can override Deallocate if individual object reclamation is to be supported,
and can override Storage_Size if there is some limit on the total size
of the storage pool. The implementor can override Initialize and Finalize
if there is any need for non-trivial initialization and finalization
for the pool as a whole. For example, Finalize might reclaim blocks of
storage that are allocated over and above the space occupied by the pool
object itself. The pool implementor may extend the Root_Subpool type
as necessary to carry additional information with each subpool provided
by Create_Subpool.
Extensions to Ada 2005
35.a/3
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe