Control stack and region memory.
Flyology has separate controls for stack capacity, dormant stack residency, and task-private object lifetime. None of these controls is a process memory limit.
- Stack capacity
- Use Ada
Storage_Sizeand the stack-pool snapshot described in Task stack sizing. This controls usable stack sizing; it does not request paging. - Dormant stack residency
- Use
Flyology.Dormancyfor a lightweight task that will wait only on a sufficiently distant timer and can tolerate a slower wake. - Task-private object lifetime
- Use
Flyology.Memory_Regionswhen a group of allocations belongs to one task phase and can be finalized and released together. - Shared or transferred data
- Keep it in an explicitly shared owner or bounded pool. A task-owned region is not a shared allocator, and references into it must not outlive the region.
Opt a timer sleeper into stack reclamation
Prompt is the default dormancy policy. On supported Linux hosts, Reclaimable asks the kernel to mark applicable stack pages as cold. Page_Out asks the kernel to reclaim applicable pages through the configured swap path.
Set_Policy applies the selected policy to the calling task. Both nondefault policies apply only after a lightweight task switches to its scheduler stack. The task must wait only on a timer with at least Minimum_Wait remaining.
with Flyology.Dormancy;
Flyology.Dormancy.Set_Policy
(Flyology.Dormancy.Page_Out, Minimum_Wait => 30.0);
delay 300.0;
Flyology.Dormancy.Set_Policy (Flyology.Dormancy.Prompt);
Descriptor waits are excluded because scheduler links can remain on the suspended stack. File waits are excluded because the kernel can own a stack-backed buffer. Native tasks accept only Prompt. On unsupported hosts, the capability queries return false and Flyology requests no page advice.
Use Cold_Advice_Supported and Pageout_Advice_Supported before you report a host capability. Group snapshots report eligible timer waits, advised stacks and bytes, attempts, accepted calls, and failures.
Release task-private allocations as one region
The native or lightweight task that declares Flyology.Memory_Regions.Task_Pool owns it. Each region grows in backing chunks when named-subpool allocators request storage. Explicit release finalizes controlled objects and returns all backing chunks. Pool finalization releases all regions that remain live.
Create_Region returns a Region_Handle for allocations that share one lifetime. A pool declared in a task body is finalized when the task ends, and its live regions are released automatically. Call Release when the region has an earlier lifetime boundary.
Task termination does not reclaim a dynamically allocated pool. The application must finalize and deallocate that pool.
with Flyology.Memory_Regions;
procedure Memory_Region_Example is
task Worker;
task body Worker is
Pool : aliased Flyology.Memory_Regions.Task_Pool;
type Node is record
Value : Integer;
end record;
type Node_Access is access Node;
for Node_Access'Storage_Pool use Pool;
Region : Flyology.Memory_Regions.Region_Handle :=
Flyology.Memory_Regions.Create_Region
(Pool, Chunk_Storage => 64 * 1_024);
Head : Node_Access := new (Region) Node'(Value => 42);
begin
Head.Value := Head.Value + 1;
-- Worker termination now finalizes Pool and releases Region.
end Worker;
begin
null;
end Memory_Region_Example;
Every allocator for an access type associated with the pool must name a region. An unnamed allocator raises Program_Error. A call from another task raises Ownership_Error. Statistics reports live regions, consumed storage with allocator overhead, and reserved chunk capacity.
Understand the region cost model
Regions group objects that have the same lifetime. The pool allocates these objects from larger chunks and releases them at one cleanup boundary.
- Task pool
- Stores fixed ownership and accounting state with the Ada subpool controller. Flyology adds no per-pool mutex because only the owning task can use the pool. The tasking runtime briefly locks its subpool list during region attachment and detachment.
- Region creation
- Allocates one Flyology region descriptor and one runtime registration node while attaching it to the pool. The first object allocation creates the first backing chunk lazily.
- Common allocation
- Checks task ownership, aligns an address, advances the current chunk offset, and updates counters. The operation takes no region lock. It does not call the underlying heap while the current chunk has room.
- Chunk growth
- Allocates and links one new chunk when the current chunk is full. The default payload capacity is 64 KiB. A larger object receives enough capacity for its size and alignment.
- Bulk cleanup
- Finalizes controlled objects and frees the registration node, backing chunks, and region descriptor. Explicit
Releasecleans one region. Task-end pool finalization cleans all live regions.
For N object allocations in R regions and K chunks, the runtime makes approximately 2R + K management allocations: one descriptor and one registration node per region, plus the chunks. Most of the N object allocations are bump operations in an existing chunk, so this arrangement is most useful when R + K is much smaller than N.
Reclamation is synchronous and frees the corresponding management allocations, although controlled objects still require individual finalization. A lightweight task with many chunks or expensive finalizers can therefore occupy its event-loop pthread until cleanup finishes. Because the allocator checks only the current chunk, unused space in older chunks remains reserved until release.
Reserved_Storage counts chunk payload capacity, not region descriptors, chunk headers, or underlying allocator metadata. Use smaller phase regions and explicit release boundaries when cleanup time or unused chunk space matters.
The current implementation has no region quota, retained-chunk cache, trimming operation, or connection to dormant-stack advice. It does not redirect ordinary Ada allocation. Set admission limits for potentially large phases and inspect region statistics before release. Every access value into a released region is invalid.