Version 1.4 of ai05s/ai05-0190-1.txt

Unformatted version of ai05s/ai05-0190-1.txt version 1.4
Other versions for file ai05s/ai05-0190-1.txt

!standard D.7(8)          10-02-24 AI05-0190-1/03
!class amendment 09-11-03
!status work item 09-11-03
!status received 09-11-03
!priority Low
!difficulty Easy
!subject Global storage pool controls
!summary
Provide a means to force the use of user-defined pools, and a means to specify a particular pool to be used by default.
!problem
Some applications need to keep tight control over heap allocation. For example, it is common for object-oriented applications to have many access-to-class-wide types, but few used for allocation. Another example is an embedded system for which is is inappropriate to rely on the implementation-provided pools.
This can be done by appplying "Storage_Size use 0" to all types that should not have allocators, and explicitly specifying a Storage_Pool for the few others. But this is error prone; one might forget the "Storage_Size use 0".
Another problem is that it is technically erroneous to deallocate from the "wrong" pool. But it is implementation defined which pool is used for each access type! Many Ada programmers don't know about this rule, and most Ada implementations use a single global heap by default, so it is common to write code that does "new" for one type, converts to another type, and does Unchecked_Deallocation. This common coding practise could be erroneous on some implementations. It is uncomfortable for erroneousness to be implementation defined in this way.
!proposal
(see summary)
!wording
Syntax
The form of a pragma Default_Storage_Pool is as follows:
pragma Default_Storage_Pool(storage_pool_indicator);
storage_pool_indicator ::= storage_pool_name | null
A pragma Default_Storage_Pool is allowed immediately within the visible part of a package_specification, immediately within a declarative_part, or as a configuration pragma.
Name Resolution Rules
The storage_pool_name is expected to be of type Root_Storage_Pool'Class.
Legality Rules
The storage_pool_name shall denote a variable.
If the pragma is used as a configuration pragma, the storage_pool_indicator shall be null, and it defines the "default pool" to be null within all applicable compilation units (see 10.1.5), except within the immediate scope of another pragma Default_Storage_Pool. Otherwise, Redundant[the pragma occurs immediately within a sequence of declarations], and it defines the default pool within the immediate scope of the pragma to be either null or the pool denoted by the storage_pool_name, except within the immediate scope of another pragma Default_Storage_Pool. Redundant[Thus, an inner pragma overrides an outer one.]
A pragma Default_Storage_Pool shall not be used as a configuration pragma within the immediate scope of another such pragma.
AARM Rationale: This is to prevent confusion in cases like this:
package Parent is pragma Default_Storage_Pool(...); ... end Parent;
pragma Default_Storage_Pool(...); -- Illegal! package Parent.Child is ... end Parent.Child;
where the Default_Storage_Pool on Parent.Child would not (if it were legal) override the one in Parent.
Static Semantics
For an access type to which no Storage_Pool nor Storage_Size clause applies:
If the default pool is null, the Storage_Size attribute is defined by the language to be zero. Redundant[Therefore, an allocator for such a type is illegal.]
If the default pool is a pool, the Storage_Pool attribute is that pool.
Otherwise, Redundant[there is no default pool]; the Storage_Pool attribute is implementation defined.
AARM Ramification: Default_Storage_Pool is the only way to specify the storage pool for an anonymous access type.
If an object has a coextension, the coextension is always allocated in the same pool as the object.
!discussion
Expected usage scenarios are:
- Default_Storage_Pool(null) as a configuration pragma applying to the whole
program.
To use an allocator for an access type, you have to apply a Storage_Pool or Storage_Size pragma to that type, or else put a Default_Storage_Pool pragma such that the type is within the pragma's immediate scope.
- Default_Storage_Pool in the spec of the root package of a program or
subsystem.
This default pool is used within the package and its children, but you can override it with a Storage_Pool or Storage_Size clause, or with another Default_Storage_Pool.
!example
!ACATS test
ACATS B and C tests are needed.
!appendix

From: Bob Duff
Sent: Thursday, November 19, 2009  12:52 PM

New version of AI05-0190-1. [This is version /02 of this AI. - ED]

The previous version used a Restriction to specify "no allocators allowed by
default".  I added pragma Default_Storage_Pool to specify a pool to be used by
default.  Having done that, it seemed better to use a pragma
No_Default_Storage_Pool instead of that Restriction.

I changed the !subject accordingly.

****************************************************************

From: Bob Duff
Sent: Sunday, November 22, 2009  1:16 PM

I wrote:

> Provide a means to force the use of user-defined pools, and a means to
> specify a particular pool to be used by default.

One interesting question, which comes from a private conversation I had with
Laurent Guerby, is:

What happens if pragma Default_Storage_Spool applies to an instantiation?
Does it apply to access types in the instance?
If so, does that provide a way to control the storage pool used for instances of
Ada.Constainers.Vectors and friends?

****************************************************************

From: Randy Brukardt
Sent: Tuesday, November 24, 2009  12:28 AM

It's clear that No_Default_Storage_Pool had better apply to instances, so that
any allocators in the generic units are detected. So I suppose from that it
implies that a similar capability exists in the other direction.

But such a capability would be next to useless. There is not (and better not be,
IMHO) any requirements on how the containers packages use the (default) storage
pool (except of course for the bounded forms, where using a pool at all is
disallowed). In particular, a container can request storage from the pool with
any size and any alignment, and as part of any operation. I suppose a program
tied to a particular implementation of the containers might be able to gain some
advantage from a custom pool, but such code is unlikely to be portable.

Note that this is true of any generic that allocates from the default pool.
Unless you are willing to "break privacy" by looking into the body of the
generic, you can't assume anything about how the pool will be called.

But almost all interesting user-defined storage pools make some assumptions
about the alignment and size that will be requested. Such pools would not work
on instances. It would of course be possible to create a monitoring pool that
passes the actual allocation requests to the default pool, but that is not going
to be very helpful in managing storage use.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, November 24, 2009  12:52 AM

> !wording

Minor issue - you didn't recommend some place to put this new wording. It can't
be floating in space!!

The old positioning of D.7(8) related specifically to it being a restriction, so
that doesn't work. So some other suggestion is needed.

****************************************************************

From: Bob Duff
Sent: Tuesday, November 24, 2009   7:01 AM

Right.  I intended to suggest someplace in chap 13, but I forgot.
So I'd say it should be 13-dot-<rolldice>.

I'm presuming there was no deliberate intent to max this "optional annex" --
it's just where the Restrictions happen to live.

Actually, I guess it should be 13.11.3, "Default Storage Pools", and bump
"Pragma Controlled" up to 13.11.4.

What about the proposal overall?  Do people like it?
It's radically different from the previous version.

****************************************************************

From: Tucker Taft
Sent: Tuesday, November 24, 2009   7:36 AM

> But such a capability would be next to useless.

I don't agree this would be next to useless for a container instance.  Clearly
you would have to provide a general purpose storage pool if you are going to
apply it by default to your entire system.  But often all that is wanted is an
ability to replace the system-defined default storage pool with a
project-specific default storage pool.

Unlike your experience, most of the storage pools I create are general purpose
in the sense that they handle any size or alignment, but are more specific in
when/if any automatic reclamation occurs.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, November 24, 2009  5:45 PM

> I don't agree this would be next to useless for a container instance.
> Clearly you would have to provide a general purpose storage pool if
> you are going to apply it by default to your entire system.  But often
> all that is wanted is an ability to replace the system-defined default
> storage pool with a project-specific default storage pool.

Not sure that makes much sense (unless your vendor's pool is particularly bad,
or if you need additional monitoring capabilities).

> Unlike your experience, most of the storage pools I create are general
> purpose in the sense that they handle any size or alignment, but are
> more specific in when/if any automatic reclamation occurs.

Fine, but those aren't very necessary with the containers, which already are
handling storage management (they're required not to leak, after all). So you
are essentially repeating the existing storage management. Moreover, the
containers (other than the bounded ones) are using controlled objects, and
freeing storage in that case makes your program erroneous (and might very well
cause it to crash hard, depending on how controlled objects are implemented).
The only time it is safe to free storage is if the instance has gone away, and
in that case, the "no leak" rule means that the storage has already been freed.
So while I could see that this capability might be useful with your own
generics, it wouldn't have any real value with the unbounded/indefinite
containers.

One could imagine trying to constrain implementation choices for the unbounded
containers so that pools could be useful (for instance, we'd have to ban reusing
nodes in a different object after they're deleted -- a technique I was planning
to use). But that comes uncomfortably close to requiring the containers to have
a particular body, something that was previously rejected.

Anyway, I still think this capability would necessarily have to be provided in
Bob's proposal (it doesn't make sense otherwise), but I don't think it should be
suggested that it has any particular utility for the language-defined packages.

****************************************************************

From: Tucker Taft
Sent: Tuesday, November 24, 2009   7:39 AM

I don't understand why No_Default_Storage_Pool is made into its own pragma,
rather than relying on a restriction.  All you said was:

   ... it seemed better to use a pragma
   No_Default_Storage_Pool instead of that Restriction.

Could you provide a bit more rationale?  It smells and feels like a restriction,
so I don't see the advantage of not using the Restrictions pragma.

I also find the wording for No_Default_Storage_Pool a bit confusing, as it says
that an access type that

    ... has neither a specified Storage_Pool nor Storage_Size ...

ends up with Storage_Size 0.  But it isn't clear from the pragma
Default_Storage_Pool that this has the effect of giving an access type a
*specified* Storage_Pool. I think from a language point of view it is still
unspecified, but it picks up the Default_Storage_Pool precisely because it is
unspecified.  Hence I would recommend that you be more explicit and say that any
access type that is "not within the scope of a Default_Storage_Pool nor has a
specified Storage_Pool nor a specified Storage_Size..." ends up with a
Storage_Size of zero.

It is somewhat annoying that Default_Storage_Pool can't be a configuration
pragma, but I understand the problem.  It would be nice if you could just
specify it once and have it apply "everywhere." I suppose if you organize your
library units into a small number of large subsystems, then you would only need
one per top-level library package. For example, in the RTS you would only need
it in the specs for Ada, Interfaces, and System. Of course creating a storage
pool object that can live in a Pure package would be a bit of a challenge!
Especially if it has to depend on System.Storage_Pools... ;-)

****************************************************************

From: Randy Brukardt
Sent: Tuesday, November 24, 2009  5:50 PM

> I don't understand why No_Default_Storage_Pool is made into its own
> pragma, rather than relying on a restriction.

Bob might have a better reason, but to me it seems that
"No_Default_Storage_Pool" is just another form of specifying the default storage
pool. Perhaps it would be better to just use one pragma:

     pragma Default_Storage_Pool (null);

to mean no default pool, although that would require rather annoying resolution
and legality rules.

In that sense it isn't really a restriction, it is just the absence of a default
storage pool. (Every access type must have a pool before an allocator can be
used - Storage_Size = 0 could be thought of as the same as not having a pool. I
assume Bob worded it to the other way to minimize the wording changes needed.)

****************************************************************

From: Tucker Taft
Sent: Tuesday, November 24, 2009  7:17 PM

I don't think this accomplishes what Bob (and I want).
You want this to be a configuration pragma, and probably be one of those that
you give all by itself in a file, so it applies to the whole library. That's why
I think it makes the most sense as a restriction.

And yes, this is for cases where you want to monitor and/or control *all*
allocation, because you don't trust or you haven't certified the vendor-provided
default storage pool, or you simply have special requirements relating to
storage management in the given target environment.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, November 25, 2009  12:38 PM

I was assuming that this would be a configuration pragma. I'm not sure why you
assumed otherwise. Of course, you couldn't give an actual pool in that case
because none would be visible. But there would be no problem with giving "null"
in that usage. So only one pragma is needed, and there is no need to worry about
what happens when they conflict.

****************************************************************

From: Bob Duff
Sent: Wednesday, February 24, 2010  2:01 PM

New version of AI05-0190-1.

In the phone meeting, we said we didn't like allowing multiple
Default_Storage_Pools immediately within a single sequence of declarations, and
we said they should be at the start.  But that seems overly restrictive, and I
don't think the wording is that hard.  Seems like we want to allow:

    with ...;
    package P is
        My_Pool : ...;
        pragma Default_Storage_Pool(My_Pool);
        type T1 is access...;
        type T2 is access...;
    end P;

And it seems harmless and useful to allow:

    with ...;
    package P is
        My_Pool : ...;
        pragma Default_Storage_Pool(My_Pool);
        type T1 is access...;
        Other_Pool : ...;
        pragma Default_Storage_Pool(Other_Pool);
        type T2 is access...;
    end P;

So I wrote this wording:

   If the pragma occurs immediately within a package_specification or
   declarative_part, it shall precede all declarative_items (other than other
   pragmas).

   Only one such pragma is allowed immediately within a given sequence
   of declarations.

and then deleted it.  I'm including it here for the record.


The new wording and discussion sections are below; the rest of the AI remains
unchanged. [This is version /03 of the AI - Editor.]

P.S. I hate the way configuration pragmas work!

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 24, 2010  6:45 PM

I don't see any wording in here defining where these pragmas apply. You seem to
assume that it is scoped like Suppress, but that doesn't happen automatically;
there has to be some words like 11.5(7.1-2/2) somewhere.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 24, 2010  6:52 PM

Sorry. Found it in the Legality Rules. It was formatted as all one long line,
and didn't see that it was out to character 700. It seems weird to have it in
Legality Rules (it's a definition and seems to belong in Static Semantics), but
that isn't a huge issue.

****************************************************************

From: Bob Duff
Sent: Wednesday, February 24, 2010  7:00 PM

> I don't see any wording in here defining where these pragmas apply.
> You seem to assume that it is scoped like Suppress, but that doesn't
> happen automatically; there has to be some words like 11.5(7.1-2/2) somewhere.

If it's a configuration pragma, the general rules about those work.
If it's in a package spec or decl_part, then it says "within the pragma's
immediate scope", except within an inner one.  Isn't that sufficient?

****************************************************************

From: Bob Duff
Sent: Wednesday, February 24, 2010  8:08 PM

> Found it in the Legality Rules. It was formatted as all one long line,
> and didn't see that it was out to character 700.

That's odd.  I don't use an editor that does that sort of thing.
Maybe it was garbled on your end?  I don't normally produce texts with
700-character-long lines!

>... It seems weird to have it in
> Legality Rules (it's a definition and seems to belong in Static
>Semantics),  but that isn't a huge issue.

Not sure why I put in in Legality Rules -- probably just a mistake.
It's pretty messy, anyway.  I wish we just had some global way to say such
things...

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 24, 2010  8:59 PM

> That's odd.  I don't use an editor that does that sort of thing.
> Maybe it was garbled on your end?  I don't normally produce texts with
> 700-character-long lines!

Outlook 2003 seems to remove single line breaks when cutting-and-pasting. So you
might have sent something friendly, but it might have turned into a mess by the
time I filed it.

> >... It seems weird to have it in
> > Legality Rules (it's a definition and seems to belong in Static
> >Semantics),  but that isn't a huge issue.
>
> Not sure why I put in in Legality Rules -- probably just a mistake.
> It's pretty messy, anyway.  I wish we just had some global way to say
> such things...

Probably because the last Legality Rule depends on it slightly.

****************************************************************

Questions? Ask the ACAA Technical Agent