From bobduff Wed Dec 16 15:55:40 1992 From: bobduff (Bob Duff) To: ada9x-mrt To: iso@ajpo.sei.cmu.edu Subject: LSN-1061 on Multiple Task Attributes !topic LSN on Multiple Task Attributes !key LSN-1061 on Multiple Task Attributes !reference MS-G.5 !from Offer Pazy $Date: 92/12/16 15:52:44 $ $Revision: 1.6 $ !discussion This Language Study Note discusses the issues of supporting multiple task attributes in the Systems Programming annex. This LSN is in response to resolution number 9-E of the ISO/WG9 Salem meeting. INTRODUCTION: ------------- Previous versions of the Systems Programming Annex contained a proposal for the support of a single task attribute, in the form of a general access value. In various meetings (ISO/WG9 at Salem, DR's, IRTWA6, and ARTEWG), concerns were raised regarding the suitability of this approach for large programs. In particular, when several, independently-developed, subsystems are to co-exist, the use of this single attribute becomes impractical without the prior knowledge of all the subsystems, and the existence of some module that will multiplex the use. In light of these problems, the MRT was instructed to investigate the possibility of introducing an alternate package in the annex which will support multiple attributes. Below is such a proposal. THE PREDEFINED PACKAGE: ----------------------- generic type Attribute is private; Default_Value : Attribute; package Task_Attributes is type Attribute_Ptr is access all Attribute; function Value (T: Task_ID := Current_Task) return Attribute; procedure Set_Value (Val : Attribute; T : Task_ID := Current_Task); function Reference (T : Task_ID := Current_Task) return Attribute_Ptr; function Attribute_Initialized(T : Task_ID := Current_Task) return boolean; procedure Delete (T : Task_ID := Current_Task); end Task_Attributes; DESCRIPTION: ----------- The generic formal type Attribute is non-limited to allow assignment. Each instantiation of this package defines a new task attribute. The attribute objects will be allocated from an internal per task "heap". The Delete operation finalizes the attribute if necessary, and reclaims its space. This also happens automatically upon task termination. The Value and Set_Value operations set and return the attribute value respectively. The Reference operation returns a pointer to the internal attribute object allowing reading or updating. The first time that an attribute is accessed for a given task, or reaccessed after a Delete, it will be allocated and initialized with the value of Default_Value. The Attribute_Initialized returns true if the corresponding attribute has been initialized for the specified task (and not subsequently deleted), and false otherwise. OTHER ALTERNATIVES CONSIDERED: ------------------------------ An important question that we have to tackle in the design of this package, was the issue of when an attribute object comes into existence, what if further attributes are defined after tasks are already running, and what are the error conditions if a non-existing attribute is accessed ? Previous proposals suggested that the attribute creation "phase" will be limited to "elaboration time", i.e. before the main subprogram starts execution. This restriction would imply that attribute creation (or definition), by means of instantiating the generic package, will be limited to library-level units only. We have rejected this approach since it does not solve the problem completely. Even within the sequence of library-level package elaboration, tasks may be created and start using the attributes even before the main subprogram starts. The elaboration phase is not always used for "elaboration" only, in fact, some programs do all the work during this phase. Therefore, the problem of accessing attributes before they are created still exists and in fact is compounded by the fact that the order of elaboration may be unknown to the programmer. IMPLEMENTATION: --------------- There are several possible implementation strategies (plus various combinations, depending on size of attribute, etc.): - Single pointer in the TCB pointing to an array of pointers indexed by the attribute ID. The array may be in the per-task heap as well as the attribute objects themselves. - K pointer slots per TCB, implementation limit on number of instantiations (K). - N bytes of storage reserved in TCB, attributes stored directly in TCB. If a fixed-size array (of pointers) is used and then more attributes are defined, a new array can be allocated, and the old one copied to it. Some variations on the above exist such as preallocation of pointers, preallocation of small attributes, minimizing levels of indirection, etc. A special case here is the treatment of 32-bit attributes, and the possibility of storing them directly in the TCB. Another possibility is a pragma specifying the maximum storage size for the attributes of a task. A POSSIBLE IMPLEMENTATION MODEL: -------------------------------- Below we show how the first (the general) approach can be implemented. This one is probably the simplest and the most straightforward one, but it is still quite efficient. The package Attrib_Support is not shown here. Its purpose is to manage the attributes in the per-task heap (in whatever approach that is chosen). It exports {Set,Get}_Attribute for a read/write access to an attribute based on the index. The private package Task_Attributes.Per_Task_Allocation is given after Task_Attributes. with Attrib_Support; use Attrib_Support; with Task_Attributes.Per_Task_Allocation; -- See below pragma Elaborate(Per_Task_Allocation); package body Task_Attributes is -- Implementation strategy: -- Each instantiation is assigned a unique attribute index. The -- Attrib_Support package then uses that as in index into an array of -- general attribute pointers. This array is itself allocated out of the -- per-task heap, of a size determined by the highest attribute index -- assigned at the time the first attribute of the task is allocated. -- On the off chance that more instantiations happen thereafter, the -- array can be copied into a larger space in the same per-task heap. Index : Attrib_Index := Bump_Index; -- Assign next attrib index package Allocation is new Per_Task_Allocation(Attribute); function To_Genl_Ptr is new Unchecked_Conversion (Allocation.Ptr, Attrib_Support.Genl_Ptr); function To_Attrib_Ptr is new Unchecked_Conversion (Attrib_Support.Genl_Ptr, Allocation.Ptr); procedure Allocate (T : Task_ID := Current_Task) is P : Attrib_Ptr := To_Genl_Ptr(Allocation.Allocate(T)); begin Set_Attrib (T, Index, P); P.all := Default_Value; end Allocate; function Value (T: Task_ID := Current_Task) return Attribute is P : Attrib_Ptr: = To_Attrib_Ptr (Get_Attrib(T, Index)); begin if P = null then Allocate (T); return Default_Value; -- Instead of querying again end if; return P.all; end Value; procedure Set_Value (Val : Attribute; T : Task_ID := Current_Task) is P : Attrib_Ptr: = To_Attrib_Ptr (Get_Attrib(T, Index)); begin if P = null then Allocate (T); P := To_Attrib_Ptr (Get_Attrib(T, Index)); end if; P.all := Val; end Set_Value; function Reference (T : Task_ID := Current_Task) return Attribute_Ptr is P : Attrib_Ptr: = To_Attrib_Ptr (Get_Attrib(T, Index)); begin if P = null then Allocate (T); return To_Attrib_Ptr (Get_Attrib(T, Index)); else return P; end if; end Reference; function Attribute_Initialized(T : Task_ID := Current_Task) return boolean is begin return Get_Attrib(T, Index) /= null; end Attribute_Initialized; procedure Delete (T : Task_ID := Current_Task) is P : Allocation.Ptr := Allocation.Ptr(Reference(T)); begin Allocation.Deallocate (P, T); Set_Attrib (T, Index, null); end Delete; end Task_Attributes; The following package implements a per-task heap. In the current proposal, we do not currently plan to export this package to the user; it is used by Task_Attributes only. private generic type Obj is limited private; package Task_Attributes.Per_Task_Allocation is -- This package provides allocation and deallocation from a per-task -- "heap". All objects are finalized (if necessary) and reclaimed after -- task completion. The space is presumed to come from some default -- (global) heap. (However, an implementation might define a pragma in -- a task body that can be used to specify the storage-size of its heap.) type Ptr is access all Obj; function Allocate (T : Task_ID := Current_Task) return Ptr; procedure Deallocate (P : in out Ptr; T : Task_ID := Current_Task); end Task_Attributes.Per_Task_Allocation; ------ Output from automsg.perl ------ Mail received from bobduff Missing version number in reference: MS-G.5 *** Key LSN-1061 given to topic 'LSN on Multiple Task Attributes' ----------- End of output ------------