This change reimplements from scratch the Ada.Task_Attributes package, taking advantage of RM permission C.7.2(28), and putting a maximum number of task attributes supported to simplify the implementation and make it more efficient. In addition, a special ("Fast_Path") case is made for task attributes holding in an address/pointer and whose Initial_Value is 0/null, which is more efficient and doesn't require the use of an indirection (and therefore, no extra dynamic memory allocation, and no locking).
Tested on x86_64-pc-linux-gnu, committed on trunk 2014-07-30 Arnaud Charlet <char...@adacore.com> * s-taskin.ads (Direct_Index, Direct_Index_Range, Direct_Attribute_Element, Direct_Attribute_Array, Direct_Index_Vector, Direct_Attributes, Is_Defined, Indirect_Attributes): Removed. (Atomic_Address, Attribute_Array, Attributes): New. * s-tasini.ads, s-tasini.adb (Proc_T, Initialize_Attributes, Finalize_Attributes_Link, Initialize_Attributes_Link): Removed. (Finalize_Attributes): Reimplement. * s-tassta.adb (Create_Task): Remove call to Initialize_Attributes_Link (Free_Task, Vulnerable_Free_Task): Replace Finalize_Attributes_Link by Finalize_Attributes. * a-tasatt.ads, a-tasatt.adb, s-tataat.ads, s-tataat.adb: Reimplement from scratch, using a simpler and more efficient implementation. * s-tporft.adb (Register_Foreign_Thread): Remove now obsolete comment. * s-parame.ads, s-parame-hpux.ads, * s-parame-vms-alpha.ads, s-parame-vms-ia64.ads, * s-parame-vxworks.ads (Max_Attribute_Count): New, replace Default_Attribute_Count.
Index: s-tataat.adb =================================================================== --- s-tataat.adb (revision 213263) +++ s-tataat.adb (working copy) @@ -6,8 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1991-1994, Florida State University -- --- Copyright (C) 1995-2013, AdaCore -- +-- Copyright (C) 1995-2014, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -30,189 +29,60 @@ -- -- ------------------------------------------------------------------------------ -with Ada.Unchecked_Conversion; +with System.Parameters; use System.Parameters; +with System.Tasking.Initialization; use System.Tasking.Initialization; -with System.Task_Primitives.Operations; -with System.Tasking.Initialization; - package body System.Tasking.Task_Attributes is - use Task_Primitives.Operations; - use Tasking.Initialization; + ---------------- + -- Next_Index -- + ---------------- - function To_Access_Address is new Ada.Unchecked_Conversion - (Access_Node, Access_Address); - -- Store pointer to indirect attribute list + type Index_Info is record + Used, Require_Finalization : Boolean; + end record; + -- Used is True if a given index is used by an instantiation of + -- Ada.Task_Attributes, False otherwise. + -- Require_Finalization is True is the attribute requires finalization. - -------------- - -- Finalize -- - -------------- + Index_Array : array (1 .. Max_Attribute_Count) of Index_Info := + (others => (False, False)); - procedure Finalize (X : in out Instance) is - Q, To_Be_Freed : Access_Node; - Self_Id : constant Task_Id := Self; - + function Next_Index (Require_Finalization : Boolean) return Integer is + Self_Id : constant Task_Id := Self; begin - -- Defer abort. Note that we use the nestable versions of Defer_Abort - -- and Undefer_Abort, because abort can already deferred when this is - -- called during finalization, which would cause an assert failure - -- in Defer_Abort. + Task_Lock (Self_Id); - Defer_Abort_Nestable (Self_Id); - Lock_RTS; - - -- Remove this instantiation from the list of all instantiations - - declare - P : Access_Instance; - Q : Access_Instance := All_Attributes; - - begin - while Q /= null and then Q /= X'Unchecked_Access loop - P := Q; Q := Q.Next; - end loop; - - pragma Assert (Q /= null); - - if P = null then - All_Attributes := Q.Next; - else - P.Next := Q.Next; + for J in Index_Array'Range loop + if not Index_Array (J).Used then + Index_Array (J).Used := True; + Index_Array (J).Require_Finalization := Require_Finalization; + Task_Unlock (Self_Id); + return J; end if; - end; - - if X.Index /= 0 then - - -- Free location of this attribute, for reuse - - In_Use := In_Use and not (2**Natural (X.Index)); - - -- There is no need for finalization in this case, since controlled - -- types are too big to fit in the TCB. - - else - -- Remove nodes for this attribute from the lists of all tasks, - -- and deallocate the nodes. Deallocation does finalization, if - -- necessary. - - declare - C : System.Tasking.Task_Id := All_Tasks_List; - P : Access_Node; - - begin - while C /= null loop - Write_Lock (C); - - Q := To_Access_Node (C.Indirect_Attributes); - while Q /= null - and then Q.Instance /= X'Unchecked_Access - loop - P := Q; - Q := Q.Next; - end loop; - - if Q /= null then - if P = null then - C.Indirect_Attributes := To_Access_Address (Q.Next); - else - P.Next := Q.Next; - end if; - - -- Can't Deallocate now since we are holding RTS_Lock - - Q.Next := To_Be_Freed; - To_Be_Freed := Q; - end if; - - Unlock (C); - C := C.Common.All_Tasks_Link; - end loop; - end; - end if; - - Unlock_RTS; - - while To_Be_Freed /= null loop - Q := To_Be_Freed; - To_Be_Freed := To_Be_Freed.Next; - X.Deallocate.all (Q); end loop; - Undefer_Abort_Nestable (Self_Id); + Task_Unlock (Self_Id); + raise Storage_Error with "Out of task attributes"; + end Next_Index; - exception - when others => - null; - pragma Assert (False, - "Exception in task attribute instance finalization"); - end Finalize; + -------------- + -- Finalize -- + -------------- - ------------------------- - -- Finalize Attributes -- - ------------------------- - - -- This is to be called just before the ATCB is deallocated. - -- It relies on the caller holding T.L write-lock on entry. - - procedure Finalize_Attributes (T : Task_Id) is - P : Access_Node; - Q : Access_Node := To_Access_Node (T.Indirect_Attributes); - + procedure Finalize (Index : Integer) is + Self_Id : constant Task_Id := Self; begin - -- Deallocate all the indirect attributes of this task + pragma Assert (Index in Index_Array'Range); + Task_Lock (Self_Id); + Index_Array (Index).Used := False; + Task_Unlock (Self_Id); + end Finalize; - while Q /= null loop - P := Q; - Q := Q.Next; P.Instance.Deallocate.all (P); - end loop; - - T.Indirect_Attributes := null; - - exception - when others => - null; - pragma Assert (False, - "Exception in per-task attributes finalization"); - end Finalize_Attributes; - - --------------------------- - -- Initialize Attributes -- - --------------------------- - - -- This is to be called by System.Tasking.Stages.Create_Task - - procedure Initialize_Attributes (T : Task_Id) is - P : Access_Instance; - Self_Id : constant Task_Id := Self; - + function Require_Finalization (Index : Integer) return Boolean is begin - -- Note: we call [Un]Defer_Abort_Nestable, rather than [Un]Defer_Abort, - -- because Abort might already be deferred in Create_Task. + pragma Assert (Index in Index_Array'Range); + return Index_Array (Index).Require_Finalization; + end Require_Finalization; - Defer_Abort_Nestable (Self_Id); - Lock_RTS; - - -- Initialize all the direct-access attributes of this task - - P := All_Attributes; - - while P /= null loop - if P.Index /= 0 then - T.Direct_Attributes (P.Index) := - Direct_Attribute_Element - (System.Storage_Elements.To_Address (P.Initial_Value)); - end if; - - P := P.Next; - end loop; - - Unlock_RTS; - Undefer_Abort_Nestable (Self_Id); - - exception - when others => - null; - pragma Assert (False); - end Initialize_Attributes; - end System.Tasking.Task_Attributes; Index: s-tataat.ads =================================================================== --- s-tataat.ads (revision 213263) +++ s-tataat.ads (working copy) @@ -6,8 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1991-1994, Florida State University -- --- Copyright (C) 1995-2010, AdaCore -- +-- Copyright (C) 1995-2014, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -32,96 +31,41 @@ -- This package provides support for the body of Ada.Task_Attributes -with Ada.Finalization; +with Ada.Unchecked_Conversion; -with System.Storage_Elements; - package System.Tasking.Task_Attributes is - type Attribute is new Integer; - -- A stand-in for the generic formal type of Ada.Task_Attributes - -- in the following declarations. + type Deallocator is access procedure (Ptr : Atomic_Address); - type Node; - type Access_Node is access all Node; - -- This needs comments ??? - - function To_Access_Node is new Ada.Unchecked_Conversion - (Access_Address, Access_Node); - -- Used to fetch pointer to indirect attribute list. Declaration is in - -- spec to avoid any problems with aliasing assumptions. - - type Dummy_Wrapper; - type Access_Dummy_Wrapper is access all Dummy_Wrapper; - pragma No_Strict_Aliasing (Access_Dummy_Wrapper); - -- Needed to avoid possible incorrect aliasing situations from - -- instantiation of Unchecked_Conversion in body of Ada.Task_Attributes. - - for Access_Dummy_Wrapper'Storage_Size use 0; - -- Access_Dummy_Wrapper is a stand-in for the generic type Wrapper defined - -- in Ada.Task_Attributes. The real objects allocated are always - -- of type Wrapper, no Dummy_Wrapper objects are ever created. - - type Deallocator is access procedure (P : in out Access_Node); - -- Called to deallocate an Wrapper. P is a pointer to a Node within - - type Instance; - - type Access_Instance is access all Instance; - - type Instance is new Ada.Finalization.Limited_Controlled with record - Deallocate : Deallocator; - Initial_Value : aliased System.Storage_Elements.Integer_Address; - - Index : Direct_Index; - -- The index of the TCB location used by this instantiation, if it is - -- stored in the TCB, otherwise zero. - - Next : Access_Instance; - -- Next instance in All_Attributes list + type Attribute_Record is record + Free : Deallocator; end record; + -- The real type is declared in Ada.Task_Attributes body: Real_Attribute + -- As long as the first field is the deallocator we are good. - procedure Finalize (X : in out Instance); + type Attribute_Access is access all Attribute_Record; + pragma No_Strict_Aliasing (Attribute_Access); - type Node is record - Wrapper : Access_Dummy_Wrapper; - Instance : Access_Instance; - Next : Access_Node; - end record; + function To_Attribute is new + Ada.Unchecked_Conversion (Atomic_Address, Attribute_Access); - -- The following type is a stand-in for the actual wrapper type, which is - -- different for each instantiation of Ada.Task_Attributes. + function Next_Index (Require_Finalization : Boolean) return Integer; + -- Return the next attribute index available. + -- Require_Finalization is True if the attribute requires finalization + -- and in particular its deallocator (Free field in Attribute_Record) + -- should be called. + -- Raise Storage_Error if no index is available. - type Dummy_Wrapper is record - Dummy_Node : aliased Node; + function Require_Finalization (Index : Integer) return Boolean; + -- Return True if a given attribute index requires call to Free. + -- This call is not protected against concurrent access, should only + -- be called during finalization of the corresponding instantiation of + -- Ada.Task_Attributes, or during finalization of a task. - Value : aliased Attribute; - -- The generic formal type, may be controlled - end record; + procedure Finalize (Index : Integer); + -- Finalize given Index, possibly allowing future reuse - for Dummy_Wrapper'Alignment use Standard'Maximum_Alignment; - -- A number of unchecked conversions involving Dummy_Wrapper_Access - -- sources are performed in other units (e.g. Ada.Task_Attributes). - -- Ensure that the designated object is always strictly enough aligned. - - In_Use : Direct_Index_Vector := 0; - -- Set True for direct indexes that are already used (True??? type???) - - All_Attributes : Access_Instance; - -- A linked list of all indirectly access attributes, which includes all - -- those that require finalization. - - procedure Initialize_Attributes (T : Task_Id); - -- Initialize all attributes created via Ada.Task_Attributes for T. This - -- must be called by the creator of the task, inside Create_Task, via - -- soft-link Initialize_Attributes_Link. On entry, abort must be deferred - -- and the caller must hold no locks - - procedure Finalize_Attributes (T : Task_Id); - -- Finalize all attributes created via Ada.Task_Attributes for T. - -- This is to be called by the task after it is marked as terminated - -- (and before it actually dies), inside Vulnerable_Free_Task, via the - -- soft-link Finalize_Attributes_Link. On entry, abort must be deferred - -- and T.L must be write-locked. - +private + pragma Inline (Finalize); + pragma Inline (Require_Finalization); end System.Tasking.Task_Attributes; Index: s-parame-vms-alpha.ads =================================================================== --- s-parame-vms-alpha.ads (revision 213263) +++ s-parame-vms-alpha.ads (working copy) @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2014, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -183,9 +183,8 @@ -- Task Attributes -- --------------------- - Default_Attribute_Count : constant := 4; - -- Number of pre-allocated Address-sized task attributes stored in the - -- task control block. + Max_Attribute_Count : constant := 32; + -- Number of task attributes stored in the task control block. -------------------- -- Runtime Traces -- Index: s-parame-hpux.ads =================================================================== --- s-parame-hpux.ads (revision 213263) +++ s-parame-hpux.ads (working copy) @@ -180,9 +180,8 @@ -- Task Attributes -- --------------------- - Default_Attribute_Count : constant := 16; - -- Number of pre-allocated Address-sized task attributes stored in the - -- task control block. + Max_Attribute_Count : constant := 32; + -- Number of task attributes stored in the task control block. -------------------- -- Runtime Traces -- Index: s-tassta.adb =================================================================== --- s-tassta.adb (revision 213263) +++ s-tassta.adb (working copy) @@ -707,7 +707,6 @@ SSL.Create_TSD (T.Common.Compiler_Data); T.Common.Activation_Link := Chain.T_ID; Chain.T_ID := T; - Initialization.Initialize_Attributes_Link.all (T); Created_Task := T; Initialization.Undefer_Abort_Nestable (Self_ID); @@ -953,7 +952,7 @@ Initialization.Task_Lock (Self_Id); Lock_RTS; - Initialization.Finalize_Attributes_Link.all (T); + Initialization.Finalize_Attributes (T); Initialization.Remove_From_All_Tasks_List (T); Unlock_RTS; @@ -2076,7 +2075,7 @@ end if; Write_Lock (T); - Initialization.Finalize_Attributes_Link.all (T); + Initialization.Finalize_Attributes (T); Unlock (T); if Single_Lock then Index: s-tasini.adb =================================================================== --- s-tasini.adb (revision 213263) +++ s-tasini.adb (working copy) @@ -45,6 +45,7 @@ with System.Soft_Links; with System.Soft_Links.Tasking; with System.Tasking.Debug; +with System.Tasking.Task_Attributes; with System.Parameters; with System.Secondary_Stack; @@ -807,27 +808,23 @@ end if; end Wakeup_Entry_Caller; - ----------------------- - -- Soft-Link Dummies -- - ----------------------- + ------------------------- + -- Finalize_Attributes -- + ------------------------- - -- These are dummies for subprograms that are only needed by certain - -- optional run-time system packages. If they are needed, the soft links - -- will be redirected to the real subprogram by elaboration of the - -- subprogram body where the real subprogram is declared. - procedure Finalize_Attributes (T : Task_Id) is - pragma Unreferenced (T); + Attr : Atomic_Address; begin - null; + for J in T.Attributes'Range loop + Attr := T.Attributes (J); + + if Attr /= 0 and then Task_Attributes.Require_Finalization (J) then + Task_Attributes.To_Attribute (Attr).Free (Attr); + T.Attributes (J) := 0; + end if; + end loop; end Finalize_Attributes; - procedure Initialize_Attributes (T : Task_Id) is - pragma Unreferenced (T); - begin - null; - end Initialize_Attributes; - begin Init_RTS; end System.Tasking.Initialization; Index: s-tasini.ads =================================================================== --- s-tasini.ads (revision 213263) +++ s-tasini.ads (working copy) @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2012, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2014, Free Software Foundation, Inc. -- -- -- -- GNARL is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -37,27 +37,15 @@ procedure Remove_From_All_Tasks_List (T : Task_Id); -- Remove T from All_Tasks_List. Call this function with RTS_Lock taken + procedure Finalize_Attributes (T : Task_Id); + -- Finalize all attributes from T + -- This is to be called just before the ATCB is deallocated. + -- It relies on the caller holding T.L write-lock on entry. + --------------------------------- -- Tasking-Specific Soft Links -- --------------------------------- - -- These permit us to leave out certain portions of the tasking - -- run-time system if they are not used. They are only used internally - -- by the tasking run-time system. - - -- So far, the only example is support for Ada.Task_Attributes - - type Proc_T is access procedure (T : Task_Id); - - procedure Finalize_Attributes (T : Task_Id); - procedure Initialize_Attributes (T : Task_Id); - - Finalize_Attributes_Link : Proc_T := Finalize_Attributes'Access; - -- should be called with abort deferred and T.L write-locked - - Initialize_Attributes_Link : Proc_T := Initialize_Attributes'Access; - -- should be called with abort deferred, but holding no locks - ------------------------- -- Abort Defer/Undefer -- ------------------------- Index: s-parame-vms-ia64.ads =================================================================== --- s-parame-vms-ia64.ads (revision 213263) +++ s-parame-vms-ia64.ads (working copy) @@ -183,9 +183,8 @@ -- Task Attributes -- --------------------- - Default_Attribute_Count : constant := 16; - -- Number of pre-allocated Address-sized task attributes stored in the - -- task control block. + Max_Attribute_Count : constant := 32; + -- Number of task attributes stored in the task control block. -------------------- -- Runtime Traces -- Index: s-parame.ads =================================================================== --- s-parame.ads (revision 213263) +++ s-parame.ads (working copy) @@ -182,9 +182,8 @@ -- Task Attributes -- --------------------- - Default_Attribute_Count : constant := 16; - -- Number of pre-allocated Address-sized task attributes stored in the - -- task control block. + Max_Attribute_Count : constant := 32; + -- Number of task attributes stored in the task control block. -------------------- -- Runtime Traces -- Index: s-tporft.adb =================================================================== --- s-tporft.adb (revision 213263) +++ s-tporft.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 2002-2011, Free Software Foundation, Inc. -- +-- Copyright (C) 2002-2014, Free Software Foundation, Inc. -- -- -- -- GNARL is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -94,15 +94,6 @@ System.Soft_Links.Create_TSD (Self_Id.Common.Compiler_Data); - -- ??? - -- The following call is commented out to avoid dependence on the - -- System.Tasking.Initialization package. It seems that if we want - -- Ada.Task_Attributes to work correctly for C threads we will need to - -- raise the visibility of this soft link to System.Soft_Links. We are - -- putting that off until this new functionality is otherwise stable. - - -- System.Tasking.Initialization.Initialize_Attributes_Link.all (T); - Enter_Task (Self_Id); return Self_Id; Index: s-taskin.ads =================================================================== --- s-taskin.ads (revision 213263) +++ s-taskin.ads (working copy) @@ -938,23 +938,14 @@ type Entry_Call_Array is array (ATC_Level_Index) of aliased Entry_Call_Record; - type Direct_Index is range 0 .. Parameters.Default_Attribute_Count; - subtype Direct_Index_Range is Direct_Index range 1 .. Direct_Index'Last; - -- Attributes with indexes in this range are stored directly in the task - -- control block. Such attributes must be Address-sized. Other attributes - -- will be held in dynamically allocated records chained off of the task - -- control block. + type Atomic_Address is mod Memory_Size; + pragma Atomic (Atomic_Address); + type Attribute_Array is + array (1 .. Parameters.Max_Attribute_Count) of Atomic_Address; + -- Array of task attributes. + -- The value (Atomic_Address) will either be converted to a task + -- attribute if it fits, or to a pointer to a record by Ada.Task_Attributes - type Direct_Attribute_Element is mod Memory_Size; - pragma Atomic (Direct_Attribute_Element); - - type Direct_Attribute_Array is - array (Direct_Index_Range) of aliased Direct_Attribute_Element; - - type Direct_Index_Vector is mod 2 ** Parameters.Default_Attribute_Count; - -- This is a bit-vector type, used to store information about - -- the usage of the direct attribute fields. - type Task_Serial_Number is mod 2 ** 64; -- Used to give each task a unique serial number @@ -1139,16 +1130,9 @@ -- User-writeable location, for use in debugging tasks; also provides a -- simple task specific data. - Direct_Attributes : Direct_Attribute_Array; - -- For task attributes that have same size as Address + Attributes : Attribute_Array := (others => 0); + -- Task attributes - Is_Defined : Direct_Index_Vector := 0; - -- Bit I is 1 iff Direct_Attributes (I) is defined - - Indirect_Attributes : Access_Address; - -- A pointer to chain of records for other attributes that are not - -- address-sized, including all tagged types. - Entry_Queues : Task_Entry_Queue_Array (1 .. Entry_Num); -- An array of task entry queues -- Index: s-parame-vxworks.ads =================================================================== --- s-parame-vxworks.ads (revision 213263) +++ s-parame-vxworks.ads (working copy) @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2014, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -182,9 +182,8 @@ -- Task Attributes -- --------------------- - Default_Attribute_Count : constant := 4; - -- Number of pre-allocated Address-sized task attributes stored in the - -- task control block. + Max_Attribute_Count : constant := 16; + -- Number of task attributes stored in the task control block. -------------------- -- Runtime Traces -- Index: a-tasatt.adb =================================================================== --- a-tasatt.adb (revision 213263) +++ a-tasatt.adb (working copy) @@ -6,8 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1991-1994, Florida State University -- --- Copyright (C) 1995-2014, AdaCore -- +-- Copyright (C) 1995-2014, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -30,213 +29,189 @@ -- -- ------------------------------------------------------------------------------ -with System.Storage_Elements; -with System.Task_Primitives.Operations; with System.Tasking; with System.Tasking.Initialization; with System.Tasking.Task_Attributes; +pragma Elaborate_All (System.Tasking.Task_Attributes); -with Ada.Exceptions; +with System.Task_Primitives.Operations; + +with Ada.Finalization; use Ada.Finalization; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; -pragma Elaborate_All (System.Tasking.Task_Attributes); --- To ensure the initialization of object Local (below) will work - package body Ada.Task_Attributes is - use System.Tasking.Initialization, + use System, + System.Tasking.Initialization, System.Tasking, - System.Tasking.Task_Attributes, - Ada.Exceptions; + System.Tasking.Task_Attributes; - package POP renames System.Task_Primitives.Operations; + package STPO renames System.Task_Primitives.Operations; + type Attribute_Cleanup is new Limited_Controlled with null record; + procedure Finalize (Cleanup : in out Attribute_Cleanup); + -- Finalize all tasks' attribute for this package + + Cleanup : Attribute_Cleanup; + pragma Unreferenced (Cleanup); + -- Will call Finalize when this instantiation gets out of scope + --------------------------- -- Unchecked Conversions -- --------------------------- - -- The following type corresponds to Dummy_Wrapper, declared in - -- System.Tasking.Task_Attributes. + type Real_Attribute is record + Free : Deallocator; + Value : Attribute; + end record; + type Real_Attribute_Access is access all Real_Attribute; + pragma No_Strict_Aliasing (Real_Attribute_Access); + -- Each value in the task control block's Attributes array is either + -- mapped to the attribute value directly if Fast_Path is True, or + -- is in effect a Real_Attribute_Access. + -- Note: the Deallocator field must be first, for compatibility with + -- System.Tasking.Task_Attributes.Attribute_Record and to allow unchecked + -- conversions between Attribute_Access and Real_Attribute_Access. - type Wrapper; - type Access_Wrapper is access all Wrapper; + function New_Attribute (Val : Attribute) return Atomic_Address; + -- Create a new Real_Attribute using Val, and return its address. + -- The returned value can be converted via To_Real_Attribute. - pragma Warnings (Off); - -- We turn warnings off for the following To_Attribute_Handle conversions, - -- since these are used only for small attributes where we know that there - -- are no problems with alignment, but the compiler will generate warnings - -- for the occurrences in the large attribute case, even though they will - -- not actually be used. + procedure Deallocate (Ptr : Atomic_Address); + -- Free memory associated with Ptr, a Real_Attribute_Access in reality - function To_Attribute_Handle is new Ada.Unchecked_Conversion - (System.Address, Attribute_Handle); - function To_Direct_Attribute_Element is new Ada.Unchecked_Conversion - (System.Address, Direct_Attribute_Element); - -- For reference to directly addressed task attributes + function To_Real_Attribute is new + Ada.Unchecked_Conversion (Atomic_Address, Real_Attribute_Access); - type Access_Integer_Address is access all - System.Storage_Elements.Integer_Address; - - function To_Attribute_Handle is new Ada.Unchecked_Conversion - (Access_Integer_Address, Attribute_Handle); - -- For reference to directly addressed task attributes - + -- Kill warning about possible size mismatch + pragma Warnings (Off); + function To_Address is new + Ada.Unchecked_Conversion (Attribute, Atomic_Address); + function To_Attribute is new + Ada.Unchecked_Conversion (Atomic_Address, Attribute); pragma Warnings (On); - -- End warnings off region for directly addressed attribute conversions - function To_Access_Address is new Ada.Unchecked_Conversion - (Access_Node, Access_Address); - -- To store pointer to list of indirect attributes + function To_Address is new + Ada.Unchecked_Conversion (Real_Attribute_Access, Atomic_Address); + -- Kill warning about possible aliasing pragma Warnings (Off); - function To_Access_Wrapper is new Ada.Unchecked_Conversion - (Access_Dummy_Wrapper, Access_Wrapper); + function To_Handle is new + Ada.Unchecked_Conversion (System.Address, Attribute_Handle); pragma Warnings (On); - -- To fetch pointer to actual wrapper of attribute node. We turn off - -- warnings since this may generate an alignment warning. The warning can - -- be ignored since Dummy_Wrapper is only a non-generic standin for the - -- real wrapper type (we never actually allocate objects of type - -- Dummy_Wrapper). - function To_Access_Dummy_Wrapper is new Ada.Unchecked_Conversion - (Access_Wrapper, Access_Dummy_Wrapper); - -- To store pointer to actual wrapper of attribute node - function To_Task_Id is new Ada.Unchecked_Conversion (Task_Identification.Task_Id, Task_Id); -- To access TCB of identified task - type Local_Deallocator is access procedure (P : in out Access_Node); + procedure Free is new + Ada.Unchecked_Deallocation (Real_Attribute, Real_Attribute_Access); - function To_Lib_Level_Deallocator is new Ada.Unchecked_Conversion - (Local_Deallocator, Deallocator); - -- To defeat accessibility check + Fast_Path : constant Boolean := + Attribute'Size <= Atomic_Address'Size and then + To_Address (Initial_Value) = 0; + -- If the attribute fits in an Atomic_Address and Initial_Value is 0 (or + -- null), then we will map the attribute directly into + -- ATCB.Attributes (Index), otherwise we will create a level of indirection + -- and instead use Attributes (Index) as a Real_Attribute_Access. - ------------------------ - -- Storage Management -- - ------------------------ + Index : constant Integer := + Next_Index (Require_Finalization => not Fast_Path); + -- Index in the task control block's Attributes array - procedure Deallocate (P : in out Access_Node); - -- Passed to the RTS via unchecked conversion of a pointer to permit - -- finalization and deallocation of attribute storage nodes. + -------------- + -- Finalize -- + -------------- - -------------------------- - -- Instantiation Record -- - -------------------------- + procedure Finalize (Cleanup : in out Attribute_Cleanup) is + pragma Unreferenced (Cleanup); + begin + STPO.Lock_RTS; - Local : aliased Instance; - -- Initialized in package body + declare + C : System.Tasking.Task_Id := System.Tasking.All_Tasks_List; + begin + while C /= null loop + STPO.Write_Lock (C); - type Wrapper is record - Dummy_Node : aliased Node; + if C.Attributes (Index) /= 0 + and then Require_Finalization (Index) + then + Deallocate (C.Attributes (Index)); + C.Attributes (Index) := 0; + end if; - Value : aliased Attribute := Initial_Value; - -- The generic formal type, may be controlled - end record; + STPO.Unlock (C); + C := C.Common.All_Tasks_Link; + end loop; + end; - -- A number of unchecked conversions involving Wrapper_Access sources are - -- performed in this unit. We have to ensure that the designated object is - -- always strictly enough aligned. + Finalize (Index); + STPO.Unlock_RTS; + end Finalize; - for Wrapper'Alignment use Standard'Maximum_Alignment; + ---------------- + -- Deallocate -- + ---------------- - procedure Free is - new Ada.Unchecked_Deallocation (Wrapper, Access_Wrapper); - - procedure Deallocate (P : in out Access_Node) is - T : Access_Wrapper := To_Access_Wrapper (P.Wrapper); + procedure Deallocate (Ptr : Atomic_Address) is + Obj : Real_Attribute_Access := To_Real_Attribute (Ptr); begin - Free (T); + Free (Obj); end Deallocate; + ------------------- + -- New_Attribute -- + ------------------- + + function New_Attribute (Val : Attribute) return Atomic_Address is + Tmp : Real_Attribute_Access; + begin + Tmp := new Real_Attribute' + (Free => Deallocate'Unrestricted_Access, + Value => Val); + return To_Address (Tmp); + end New_Attribute; + --------------- -- Reference -- --------------- function Reference - (T : Task_Identification.Task_Id := Task_Identification.Current_Task) + (T : Task_Identification.Task_Id := Task_Identification.Current_Task) return Attribute_Handle is + Self_Id : Task_Id; TT : constant Task_Id := To_Task_Id (T); Error_Message : constant String := "Trying to get the reference of a "; + Result : Attribute_Handle; begin if TT = null then - Raise_Exception (Program_Error'Identity, Error_Message & "null task"); + raise Program_Error with Error_Message & "null task"; end if; if TT.Common.State = Terminated then - Raise_Exception (Tasking_Error'Identity, - Error_Message & "terminated task"); + raise Tasking_Error with Error_Message & "terminated task"; end if; - -- Directly addressed case - - if Local.Index /= 0 then - - -- Return the attribute handle. Warnings off because this return - -- statement generates alignment warnings for large attributes - -- (but will never be executed in this case anyway). - - pragma Warnings (Off); - return - To_Attribute_Handle (TT.Direct_Attributes (Local.Index)'Address); - pragma Warnings (On); - - -- Not directly addressed - + if Fast_Path then + return To_Handle (TT.Attributes (Index)'Address); else - declare - P : Access_Node := To_Access_Node (TT.Indirect_Attributes); - W : Access_Wrapper; - Self_Id : constant Task_Id := POP.Self; + Self_Id := STPO.Self; + Task_Lock (Self_Id); - begin - Defer_Abort (Self_Id); - POP.Lock_RTS; + if TT.Attributes (Index) = 0 then + TT.Attributes (Index) := New_Attribute (Initial_Value); + end if; - while P /= null loop - if P.Instance = Access_Instance'(Local'Unchecked_Access) then - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - return To_Access_Wrapper (P.Wrapper).Value'Access; - end if; + Result := To_Handle + (To_Real_Attribute (TT.Attributes (Index)).Value'Address); + Task_Unlock (Self_Id); - P := P.Next; - end loop; - - -- Unlock the RTS here to follow the lock ordering rule that - -- prevent us from using new (i.e the Global_Lock) while holding - -- any other lock. - - POP.Unlock_RTS; - W := new Wrapper' - ((null, Local'Unchecked_Access, null), Initial_Value); - POP.Lock_RTS; - - P := W.Dummy_Node'Unchecked_Access; - P.Wrapper := To_Access_Dummy_Wrapper (W); - P.Next := To_Access_Node (TT.Indirect_Attributes); - TT.Indirect_Attributes := To_Access_Address (P); - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - return W.Value'Access; - - exception - when others => - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - raise; - end; + return Result; end if; - - exception - when Tasking_Error | Program_Error => - raise; - - when others => - raise Program_Error; end Reference; ------------------ @@ -246,68 +221,37 @@ procedure Reinitialize (T : Task_Identification.Task_Id := Task_Identification.Current_Task) is + Self_Id : Task_Id; TT : constant Task_Id := To_Task_Id (T); Error_Message : constant String := "Trying to Reinitialize a "; begin if TT = null then - Raise_Exception (Program_Error'Identity, Error_Message & "null task"); + raise Program_Error with Error_Message & "null task"; end if; if TT.Common.State = Terminated then - Raise_Exception (Tasking_Error'Identity, - Error_Message & "terminated task"); + raise Tasking_Error with Error_Message & "terminated task"; end if; - if Local.Index /= 0 then - Set_Value (Initial_Value, T); + if Fast_Path then + -- No finalization needed, simply reset to Initial_Value + TT.Attributes (Index) := To_Address (Initial_Value); else - declare - P, Q : Access_Node; - W : Access_Wrapper; - Self_Id : constant Task_Id := POP.Self; + Self_Id := STPO.Self; + Task_Lock (Self_Id); + declare + Attr : Atomic_Address renames TT.Attributes (Index); begin - Defer_Abort (Self_Id); - POP.Lock_RTS; - Q := To_Access_Node (TT.Indirect_Attributes); - - while Q /= null loop - if Q.Instance = Access_Instance'(Local'Unchecked_Access) then - if P = null then - TT.Indirect_Attributes := To_Access_Address (Q.Next); - else - P.Next := Q.Next; - end if; - - W := To_Access_Wrapper (Q.Wrapper); - Free (W); - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - return; - end if; - - P := Q; - Q := Q.Next; - end loop; - - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - - exception - when others => - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - raise; + if Attr /= 0 then + Deallocate (Attr); + Attr := 0; + end if; end; - end if; - exception - when Tasking_Error | Program_Error => - raise; - - when others => - raise Program_Error; + Task_Unlock (Self_Id); + end if; end Reinitialize; --------------- @@ -318,85 +262,38 @@ (Val : Attribute; T : Task_Identification.Task_Id := Task_Identification.Current_Task) is + Self_Id : Task_Id; TT : constant Task_Id := To_Task_Id (T); Error_Message : constant String := "Trying to Set the Value of a "; begin if TT = null then - Raise_Exception (Program_Error'Identity, Error_Message & "null task"); + raise Program_Error with Error_Message & "null task"; end if; if TT.Common.State = Terminated then - Raise_Exception (Tasking_Error'Identity, - Error_Message & "terminated task"); + raise Tasking_Error with Error_Message & "terminated task"; end if; - -- Directly addressed case + if Fast_Path then + -- No finalization needed, simply set to Val + TT.Attributes (Index) := To_Address (Val); + else + Self_Id := STPO.Self; + Task_Lock (Self_Id); - if Local.Index /= 0 then - - -- Set attribute handle, warnings off, because this code can generate - -- alignment warnings with large attributes (but of course will not - -- be executed in this case, since we never have direct addressing in - -- such cases). - - pragma Warnings (Off); - To_Attribute_Handle - (TT.Direct_Attributes (Local.Index)'Address).all := Val; - pragma Warnings (On); - return; - end if; - - -- Not directly addressed - - declare - P : Access_Node := To_Access_Node (TT.Indirect_Attributes); - W : Access_Wrapper; - Self_Id : constant Task_Id := POP.Self; - - begin - Defer_Abort (Self_Id); - POP.Lock_RTS; - - while P /= null loop - - if P.Instance = Access_Instance'(Local'Unchecked_Access) then - To_Access_Wrapper (P.Wrapper).Value := Val; - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - return; + declare + Attr : Atomic_Address renames TT.Attributes (Index); + begin + if Attr /= 0 then + Deallocate (Attr); end if; - P := P.Next; - end loop; + Attr := New_Attribute (Val); + end; - -- Unlock RTS here to follow the lock ordering rule that prevent us - -- from using new (i.e the Global_Lock) while holding any other lock. - - POP.Unlock_RTS; - W := new Wrapper'((null, Local'Unchecked_Access, null), Val); - POP.Lock_RTS; - P := W.Dummy_Node'Unchecked_Access; - P.Wrapper := To_Access_Dummy_Wrapper (W); - P.Next := To_Access_Node (TT.Indirect_Attributes); - TT.Indirect_Attributes := To_Access_Address (P); - - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - - exception - when others => - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - raise; - end; - - exception - when Tasking_Error | Program_Error => - raise; - - when others => - raise Program_Error; + Task_Unlock (Self_Id); + end if; end Set_Value; ----------- @@ -407,167 +304,42 @@ (T : Task_Identification.Task_Id := Task_Identification.Current_Task) return Attribute is + Self_Id : Task_Id; TT : constant Task_Id := To_Task_Id (T); Error_Message : constant String := "Trying to get the Value of a "; begin if TT = null then - Raise_Exception (Program_Error'Identity, Error_Message & "null task"); + raise Program_Error with Error_Message & "null task"; end if; if TT.Common.State = Terminated then - Raise_Exception - (Program_Error'Identity, Error_Message & "terminated task"); + raise Tasking_Error with Error_Message & "terminated task"; end if; - -- Directly addressed case + if Fast_Path then + return To_Attribute (TT.Attributes (Index)); + else + Self_Id := STPO.Self; + Task_Lock (Self_Id); - if Local.Index /= 0 then - - -- Get value of attribute. We turn Warnings off, because for large - -- attributes, this code can generate alignment warnings. But of - -- course large attributes are never directly addressed so in fact - -- we will never execute the code in this case. - - pragma Warnings (Off); - return To_Attribute_Handle - (TT.Direct_Attributes (Local.Index)'Address).all; - pragma Warnings (On); - end if; - - -- Not directly addressed - - declare - P : Access_Node; - Result : Attribute; - Self_Id : constant Task_Id := POP.Self; - - begin - Defer_Abort (Self_Id); - POP.Lock_RTS; - P := To_Access_Node (TT.Indirect_Attributes); - - while P /= null loop - if P.Instance = Access_Instance'(Local'Unchecked_Access) then - Result := To_Access_Wrapper (P.Wrapper).Value; - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - return Result; - end if; - - P := P.Next; - end loop; - - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - return Initial_Value; - - exception - when others => - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - raise; - end; - - exception - when Tasking_Error | Program_Error => - raise; - - when others => - raise Program_Error; - end Value; - --- Start of elaboration code for package Ada.Task_Attributes - -begin - -- This unchecked conversion can give warnings when alignments are - -- incorrect, but they will not be used in such cases anyway, so the - -- warnings can be safely ignored. - - pragma Warnings (Off); - Local.Deallocate := To_Lib_Level_Deallocator (Deallocate'Access); - pragma Warnings (On); - - declare - Two_To_J : Direct_Index_Vector; - Self_Id : constant Task_Id := POP.Self; - begin - Defer_Abort (Self_Id); - - -- Need protection for updating links to per-task initialization and - -- finalization routines, in case some task is being created or - -- terminated concurrently. - - POP.Lock_RTS; - - -- Add this instantiation to the list of all instantiations - - Local.Next := System.Tasking.Task_Attributes.All_Attributes; - System.Tasking.Task_Attributes.All_Attributes := - Local'Unchecked_Access; - - -- Try to find space for the attribute in the TCB - - Local.Index := 0; - Two_To_J := 1; - - if Attribute'Size <= System.Address'Size then - for J in Direct_Index_Range loop - if (Two_To_J and In_Use) = 0 then - - -- Reserve location J for this attribute - - In_Use := In_Use or Two_To_J; - Local.Index := J; - - -- This unchecked conversion can give a warning when the - -- alignment is incorrect, but it will not be used in such - -- a case anyway, so the warning can be safely ignored. - - pragma Warnings (Off); - To_Attribute_Handle (Local.Initial_Value'Access).all := - Initial_Value; - pragma Warnings (On); - - exit; - end if; - - Two_To_J := Two_To_J * 2; - end loop; - end if; - - -- Attribute goes directly in the TCB - - if Local.Index /= 0 then - -- Replace stub for initialization routine that is called at task - -- creation. - - Initialization.Initialize_Attributes_Link := - System.Tasking.Task_Attributes.Initialize_Attributes'Access; - - -- Initialize the attribute, for all tasks - declare - C : System.Tasking.Task_Id := System.Tasking.All_Tasks_List; + Attr : Atomic_Address renames TT.Attributes (Index); begin - while C /= null loop - C.Direct_Attributes (Local.Index) := - To_Direct_Attribute_Element - (System.Storage_Elements.To_Address (Local.Initial_Value)); - C := C.Common.All_Tasks_Link; - end loop; + if Attr = 0 then + Task_Unlock (Self_Id); + return Initial_Value; + else + declare + Result : constant Attribute := + To_Real_Attribute (Attr).Value; + begin + Task_Unlock (Self_Id); + return Result; + end; + end if; end; - - -- Attribute goes into a node onto a linked list - - else - -- Replace stub for finalization routine called at task termination - - Initialization.Finalize_Attributes_Link := - System.Tasking.Task_Attributes.Finalize_Attributes'Access; end if; + end Value; - POP.Unlock_RTS; - Undefer_Abort (Self_Id); - end; end Ada.Task_Attributes;