13.11.4 Storage Subpools
{
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
{
AI05-0111-3}
The following language-defined library package exists:
package System.Storage_Pools.Subpools
is
pragma Preelaborate (Subpools);
type Root_Storage_Pool_With_Subpools
is
abstract new Root_Storage_Pool
with private;
type Root_Subpool
is abstract tagged limited private;
type Subpool_Handle
is access all Root_Subpool'Class;
for Subpool_Handle'Storage_Size
use 0;
function Create_Subpool (Pool :
in out Root_Storage_Pool_With_Subpools)
return not null Subpool_Handle
is abstract;
{
AI05-0252-1}
--
The following operations are intended for pool implementers:
function Pool_of_Subpool (Subpool :
not null Subpool_Handle)
return access Root_Storage_Pool_With_Subpools'Class;
procedure Set_Pool_of_Subpool (
Subpool :
in not null Subpool_Handle;
To :
in out Root_Storage_Pool_With_Subpools'Class);
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 :
in not null Subpool_Handle)
is abstract
with Pre'Class => Pool_of_Subpool(Subpool) = Pool'Access;
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;
{
AI05-0298-1}
function Default_Subpool_for_Pool (
Pool :
in out Root_Storage_Pool_With_Subpools)
return not null Subpool_Handle;
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);
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;
{
AI05-0298-1}
overriding
function Storage_Size (Pool : Root_Storage_Pool_With_Subpools)
return Storage_Elements.Storage_Count
is (Storage_Elements.Storage_Count'Last);
private
... -- not specified by the language
end System.Storage_Pools.Subpools;
{
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.
{
AI05-0111-3}
{
AI05-0269-1}
A
subpool object is an object of a type descended from Root_Subpool.
[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.]
Proof: We know that subpool handles designate
subpool objects because the declaration of Subpool_Handle says so.
{
AI05-0111-3}
{
AI05-0145-1}
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. If Set_Pool_of_Subpool
has not yet been called for a subpool, Pool_of_Subpool returns
null.
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.
{
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.
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).
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
{
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.
{
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
{
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:
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
the accessibility level of the access type is not
deeper than that of the storage pool object.
{
AI05-0252-1}
Program_Error is raised if either of these checks fail.
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.
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.
{
AI05-0111-3}
A call to Subpools.Allocate(P, Addr, Size, Align) does the following:
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)));
{
AI05-0111-3}
An
allocator
that allocates in a subpool raises Program_Error if the allocated object
has task parts.
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.
{
AI05-0111-3}
Unless overridden, Default_Subpool_for_Pool propagates Program_Error.
Erroneous Execution
{
AI12-0142-1}
If Allocate_From_Subpool does not meet one or more
of the requirements on the Allocate procedure as given in the Erroneous
Execution rules of
13.11, then the program
execution is erroneous.
Implementation Permissions
{
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.]
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.
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.
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 {
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 {
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 {
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 nontrivial 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
Wording Changes from Ada 2012
{
AI12-0142-1}
Corrigendum: Clarified that an incorrect implementation of Allocate_From_Subpool
causes execution to become erroneous. The wording already said that the
requirements of Allocate apply to Allocate_From_Subpool, so we're just
confirming the consequences of violating those requirements also apply.
{
AI12-0145-1}
Corrigendum: Clarified that Pool_of_Subpool returns
null
if Set_Pool_of_Subpool has not been called. As that can be inferred from
the definition, and all known existing implementations return
null
in this case, we document this as a wording change rather than a possible
inconsistency.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe