Description
Selects and observes event-loop execution groups for lightweight tasks.
Example:
Flyology.Execution_Groups.Migrate (1);
Automatic_Placement_Policy
type Automatic_Placement_Policy is (Round_Robin);
Automatic assignment policy for tasks without a CPU aspect.
Enumeration literals
- Round_Robin
Select successive groups in the configured pool
Configure_Loop_Thread
function Configure_Loop_Thread
(Group : Group_Id; Kind : Loop_Thread_Placement; Value : Placement_Value := 0)
return Placement_Configuration_Result
Configure a scheduler thread before Group starts. The same request is idempotent after startup; changing or clearing it then reports Group_Already_Started. Strict_CPU is a Linux OS CPU in the process's allowed set. Advisory_Tag must be positive. No_Placement requires zero.
Parameters
- Group
Execution group whose scheduler thread is configured
- Kind
Host placement mechanism
- Value
Linux logical CPU, Darwin advisory tag, or zero
Return value
Explicit configuration result; this starts no group
Raised exceptions
- Group_Error
The runtime returns an unknown result
Configured_Placement
function Configured_Placement return Automatic_Placement_Policy
Return the automatic policy without starting any group.
Return value
Configured placement policy
Raised exceptions
- Group_Error
The runtime reports an unknown policy
Configured_Pool_Size
function Configured_Pool_Size return Loop_Pool_Size
Return the automatic pool size without starting any group. The value of FLYOLOGY_LOOP_POOL_SIZE is captured once at process startup, defaults to one when absent, and establishes the initial size before task activation. Runtime growth or reduction may change it later. A lightweight task without a specific CPU is assigned among groups 0 .. Result - 1.
Return value
Configured shared-group pool size
Raised exceptions
- Group_Error
The runtime reports an invalid size
Create_Dedicated
function Create_Dedicated return Dedicated_Group_Id
Reserve an empty reusable dedicated group for the calling lightweight task. Migrating out consumes the reservation; call Create_Dedicated again before re-entering a dedicated group. The same id is normally reused.
Return value
Reserved group in 128 .. 255
Raised exceptions
- Group_Error
The caller is native or no group can be reserved
Current
function Current return Group_Id
Return the calling lightweight task's current execution group.
Return value
Current group identifier
Raised exceptions
- Group_Error
The caller is native or runtime result is invalid
Current_Processor
function Current_Processor return Integer
Return the calling thread's current logical processor where the host provides a stable public query (Linux), otherwise No_Processor.
Return value
Current zero-based logical CPU or No_Processor
Dedicated_Group_Id
subtype Dedicated_Group_Id is Group_Id range 128 .. Group_Id'Last;
Exclusively reserved groups returned by Create_Dedicated.
Default_Group
Default_Group : constant Shared_Group_Id := 0;
First shared group. Ada reserves CPU 0 as Not_A_Specific_CPU, so no CPU aspect names this group; reach it through automatic placement, Migrate, or Topology.Cross_To_Shard.
For_CPU
function For_CPU (CPU : Group_Selecting_CPU) return Shared_Group_Id
Convert an Ada CPU value in 1 .. 127 to its shared Flyology group. Constraint_Error reports a value outside that range, including the reserved Not_A_Specific_CPU, which names no group.
Parameters
- CPU
Ada CPU aspect value that names a shared group
Return value
Shared group with the same numeric value
Group_Error
Group_Error : exception;
Raised when a group query, reservation, or pin operation cannot complete.
Group_Id
type Group_Id is range 0 .. 255;
Identifier of one permanent event-loop execution group.
Group_Selecting_CPU
subtype Group_Selecting_CPU is
System.Multiprocessors.CPU_Range range 1 .. System.Multiprocessors.CPU_Range (Shared_Group_Id'Last);
Ada CPU aspect values that name a shared execution group. The reserved value 0 is excluded because Ada defines it as Not_A_Specific_CPU, which requests automatic placement rather than Default_Group.
Grow_Configured_Pool
procedure Grow_Configured_Pool (Minimum_Size : Loop_Pool_Size)
Ensure the automatic pool contains at least Minimum_Size shared groups. Concurrent calls converge on the largest requested value. A request at or below the current size is an idempotent no-op. Growth is rejected while a reduction is still draining. Existing tasks remain on their current groups, while future automatic placements use the enlarged pool. Newly included groups remain lazy. Growing changes the modulus used by Topology.Shard_For_Hash.
Parameters
- Minimum_Size
Minimum automatic pool size after the call
Raised exceptions
- Group_Error
The runtime lifecycle does not permit growth
In_Configured_Pool
function In_Configured_Pool (Group : Group_Id) return Boolean
Test membership in the automatic pool without starting a group.
Parameters
- Group
Group to test
Return value
True when Group is below Configured_Pool_Size
Raised exceptions
- Group_Error
The runtime reports an invalid pool size
Is_Dedicated
function Is_Dedicated (Group : Group_Id) return Boolean
Test the numeric group class; this starts no group.
Parameters
- Group
Group identifier to classify
Return value
True for groups 128 .. 255
Is_Thread_Pinned
function Is_Thread_Pinned return Boolean
Report whether the caller is pinned. Native tasks always report True.
Return value
True for a native task or a lightweight task with a live pin
Loop_Pool_Size
subtype Loop_Pool_Size is Positive range 1 .. 128;
Number of shared groups participating in automatic placement.
Loop_Thread_Placement
type Loop_Thread_Placement is (No_Placement, Strict_CPU, Advisory_Tag);
Optional placement of an execution group's scheduler thread. This is independent from an Ada CPU aspect, which selects an execution group.
Enumeration literals
- No_Placement
Do not request host placement
- Strict_CPU
Bind to one Linux logical CPU; unsupported on Darwin
- Advisory_Tag
Apply a Darwin cache-locality tag, not a CPU number
Loop_Thread_Status
function Loop_Thread_Status (Group : Group_Id) return Placement_Status
Observe Group's placement request without starting it.
Parameters
- Group
Execution group to inspect
Return value
Current placement status
Raised exceptions
- Group_Error
The runtime query or returned encoding is invalid
Migrate
procedure Migrate (Group : Group_Id)
Migrate the calling lightweight task at this cooperative safe point and return on Group's scheduler thread. A live Thread_Pin prevents movement to another group. Native tasks cannot migrate because GNARL owns their stacks and threads. Leaving a dedicated group consumes its reservation. Migrate is a potentially blocking operation and must not be called inside a protected action: the protected object's lock belongs to the source event-loop thread and cannot follow the task. The call is not syntactically visible to GNAT's check on protected bodies, so a lightweight caller inside a protected action raises Program_Error before any movement, whatever Group names, and the normal unwinding releases the lock on the thread that holds it. A native caller inside a protected action keeps raising Migration_Error.
Parameters
- Group
Destination execution group
Raised exceptions
- Migration_Error
Caller is native, pinned, or cannot enter Group
- Program_Error
Lightweight caller is inside a protected action
Migration_Error
Migration_Error : exception;
Raised when the calling task cannot migrate to the requested group.
No_Processor
No_Processor : constant Integer := -1;
Current_Processor result when no supported stable query exists.
Pin_To_Current_Thread
function Pin_To_Current_Thread return Thread_Pin
Acquire one pin level for a lightweight caller, or a no-op for a native caller.
Return value
Guard that releases the lightweight pin or finalizes the native no-op
Raised exceptions
- Group_Error
The runtime cannot pin the caller
Placement_Configuration_Result
type Placement_Configuration_Result is
(Configured, Unchanged, Unsupported, Invalid_Value, Group_Already_Started, Runtime_Unavailable);
Result of a loop-thread configuration request.
Enumeration literals
- Configured
New configuration was recorded before startup
- Unchanged
The identical configuration was already recorded
- Unsupported
The host does not implement this placement kind
- Invalid_Value
Value is invalid for Kind or unavailable to process
- Group_Already_Started
Group entered lazy startup before this change
- Runtime_Unavailable
Runtime lifecycle does not permit configuration
Placement_State
type Placement_State is (Not_Requested, Pending_Startup, Applied, Failed, Unavailable);
Observed application state of a placement request.
Enumeration literals
- Not_Requested
No placement was configured
- Pending_Startup
The request is stored for lazy group startup
- Applied
The group thread applied the request
- Failed
The host call failed; inspect Error_Code
- Unavailable
The requested mechanism is unavailable
Placement_Status
type Placement_Status is record
Kind : Loop_Thread_Placement := No_Placement;
Value : Placement_Value := 0;
State : Placement_State := Not_Requested;
Error_Code : Integer := 0;
end record;
Current loop-thread placement status.
Record fields
- Kind
Requested host placement mechanism
- Value
Requested CPU or advisory tag
- State
Request lifecycle state
- Error_Code
Host error for Failed, otherwise zero
Placement_Supported
function Placement_Supported (Kind : Loop_Thread_Placement) return Boolean
Test whether the host supports Kind without starting a group.
Parameters
- Kind
Placement mechanism to test
Return value
True when the current host supports Kind
Placement_Value
subtype Placement_Value is Natural range 0 .. 2_147_483_647;
Host placement value: zero-based Linux CPU or positive Darwin tag.
Placement_Value_Available
function Placement_Value_Available (Kind : Loop_Thread_Placement; Value : Placement_Value) return Boolean
Test a placement value without starting a group. On Linux this may lazily snapshot the process's inherited affinity allowance.
Parameters
- Kind
Placement mechanism
- Value
Candidate CPU or advisory tag
Return value
True when the host can accept the value
Pool_Reduction
function Pool_Reduction return Pool_Reduction_Status
Return a momentary reduction-progress snapshot without waiting. Calling this function also recognizes completion after the final task or pre-cutover placement claim drains.
Return value
Current reduction lifecycle, target, and blocker counts
Raised exceptions
- Group_Error
The runtime cannot provide a valid snapshot
Pool_Reduction_Phase
type Pool_Reduction_Phase is (No_Reduction, Draining, Drained);
Lifecycle of the most recent automatic-pool reduction.
Enumeration literals
- No_Reduction
No reduction is active or retained for observation
- Draining
New placement uses Target_Size while eligible tasks move
- Drained
No automatically managed task remains above Target_Size
Pool_Reduction_Request_Result
type Pool_Reduction_Request_Result is (Reduction_Started, Already_At_Or_Below, Reduction_In_Progress);
Result of a request to lower the automatic-placement ceiling.
Enumeration literals
- Reduction_Started
New automatic placements now use Target_Size and eligible existing tasks will drain cooperatively
- Already_At_Or_Below
The current ceiling already satisfies the request
- Reduction_In_Progress
A previous reduction must finish first
Pool_Reduction_Status
type Pool_Reduction_Status is record
Phase : Pool_Reduction_Phase := No_Reduction;
Target_Size : Loop_Pool_Size := Loop_Pool_Size'First;
Automatic_Tasks : Natural := 0;
Pinned_Automatic_Tasks : Natural := 0;
Waiting_Automatic_Tasks : Natural := 0;
Explicit_Tasks : Natural := 0;
Placement_Claims : Natural := 0;
end record;
Progress and blockers for an automatic-pool reduction. Explicit_Tasks reports tasks outside Target_Size that are not managed by the automatic pool; they do not prevent Drained. Counts are a momentary snapshot.
Record fields
- Phase
Current reduction lifecycle
- Target_Size
Current automatic-placement ceiling
- Automatic_Tasks
Automatically managed tasks still above target
- Pinned_Automatic_Tasks
Such tasks currently pinned to a thread
- Waiting_Automatic_Tasks
Such tasks suspended until another event
- Explicit_Tasks
Explicitly placed tasks above the target
- Placement_Claims
Creations that selected an above-target group before the reduction cutover and have not registered yet
Request_Pool_Reduction
function Request_Pool_Reduction (Maximum_Size : Loop_Pool_Size) return Pool_Reduction_Request_Result
Lower the ceiling used by future automatic placements immediately. Automatically managed tasks in removed groups migrate to Default_Group when they next become ready at an unpinned cooperative safe point. Waiting, pinned, or CPU-bound tasks may delay completion indefinitely. Tasks created with a CPU aspect or moved explicitly with Migrate remain where the caller put them and are reported as Explicit_Tasks. If migration is required, this call may synchronously start Default_Group as its drainage destination and wait for that startup. An already-drained request starts no group. The call does not wait for drainage and does not reclaim threads. Use Pool_Reduction to observe drainage with an application deadline.
Parameters
- Maximum_Size
New automatic-placement ceiling
Return value
Whether reduction started, was already satisfied, or is busy
Raised exceptions
- Group_Error
The runtime lifecycle rejects the request
Shared_Group_Id
subtype Shared_Group_Id is Group_Id range 0 .. 127;
Shared groups selected by CPU aspects and automatic placement.
Thread_Pin
type Thread_Pin is limited private;
Task-owned scope guard that keeps a lightweight task on its current scheduler thread. Pins nest and each object releases one level. Declare, use, and finalize a lightweight-acquired guard in its acquiring task; do not transfer it. Finalization of that guard by another task raises Program_Error in that task and does not release the acquiring task's pin level. Native tasks accept pins as no-ops because their thread is permanent; native-acquired guards also finalize as no-ops, even in another task. @field Active Whether this guard still needs finalization @field Owner Runtime identity of the acquiring lightweight task, or null for a native-acquired no-op