From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 Path: utzoo!utgpu!water!watmath!clyde!att!ucbvax!IBM.COM!NCOHEN From: NCOHEN@IBM.COM (Norman Cohen) Newsgroups: comp.lang.ada Subject: Deallocation of T'STORAGE_SIZE for a terminated task Message-ID: <092288.092151.ncohen@ibm.com> Date: 22 Sep 88 13:21:48 GMT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The Internet List-Id: Ref: INFO-ADA Digest Volume 88 Issue 200 (Thu, Sep 22, 1988) Item #2 Consider the following program: PROCEDURE Main IS TYPE Work_Item_Type IS ...; TASK TYPE Work_Processor_Type IS ENTRY Assign_Work (Work: IN Work_Item_Type); END Work_Processor_Type; TYPE Work_Processor_Pointer_Type IS ACCESS Work_Processor_Type; Work_Item : Work_Item_Type; New_Work_Processor : Work_Processor_Pointer_Type; PROCEDURE Deallocate_Work_Processor IS NEW Unchecked_Deallocation (Work_Processor_Type, Work_Processor_Pointer_Type); TASK BODY Work_Processor_Type IS SEPARATE; PROCEDURE Wait_For_Work (Work_Item: OUT Work_Item_Type); BEGIN LOOP Wait_For_Work (Work_Item); New_Work_Processor := NEW Work_Processor_Type; New_Work_Processor.Assign_Work (Work_Item); Deallocate_Work_Processor (New_Work_Processor); END LOOP; END Main; Work processors are assigned as work items arrive. Several work processors may be active simultaneously, asynchronously processing their assigned work items. The intent of the last statement in the loop is to deallocate storage for each work-processor task when it completes its work, so that the storage may be used for other work processors. If the task allocated in the third statement of the loop completes its work and terminates before the main program advances to the fourth statement in the loop, we would expect the storage for the task object to be reclaimed as for an allocated object of any other type. However, if (as is likely) the task is still active when the fourth statement of the loop is reached, the call on Deallocate_Work_Processor has no effect on the task. (In particular, the task is not aborted so that storage for the task object can be reclaimed.) That is the point of Reference Manual paragraph 3.10.1(8) (which is a note, not a rule). There are several options available to the friendly designer of a run- time system, and several recourses available to the user whose run-time- system designer was not inclined to be friendly. First, we must distinguish between two kinds of storage associated with tasks, the task control block (data maintained by the run-time system for such purposes as task scheduling and task communication) and the task stack (used for application data local to the task body or local to subprograms invoked by the task). A typical implementation has a task object corresponding to a task control block and a representation clause for T'Storage_Size, where T is a task type, determining the size of the stack allocated when a task of the type is activated. Options available to the friendly designer of a run-time system include: - Deallocating the task stack (Work_Procesor_Type'Storage_Size bytes) immediately upon task termination, even if the task control block (Work_Processor_Type'Size bits) must remain in existence for such purposes as evaluating the 'Terminated attribute or raising Tasking_Error in any other task that calls an entry of the terminated task. - Implementing a task object as a pointer to a task control block, but representing the task object of a terminated task by a null pointer and deallocating storage for the task control block itself as soon as the task has terminated. - Automatically reclaiming storage for allocated task objects as soon as the task has terminated, provided that the task object is no longer accessible by access values. (This is a restricted form of incremental garbage collection in which reference counts can be used.) - Having instances of Unchecked_Deallocation set a "deallocation pending" flag in the task control block if the task objects for which deallocation was requested designate still-active tasks. Upon termination, the task control block would be deallocated if its "deallocation pending" flag were set. Options available to the user of a run-time system whose designer was not inclined to be friendly include the following: - Introduce another task, of low-priority, to explicitly manage allocation and deallocation of task objects. Thus the assignment New_Work_Processor := NEW Work_Processor_Type; in the program above would be replaced by an entry call on this new task: Work_Processor_Manager.Get_New_Task (New_Work_Processor); The low-priority task would maintain a list of currently allocated tasks and periodically query the 'Terminated attribute of tasks on the list, deallocating a task object and removing the pointer to that object from the list whenever the designated task is found to be terminated. - If there is a known maximum on the number of work processors that will be active simultaneously, declare an array of that many Work_Processor_Type objects. Add an entry, called once at program start-up, to tell a Work_Processor_Type task its index within this array. Declare a list of indices of currently idle tasks, initialized to a list containing every task index. Modify the Work_Processor_Type task body so that, rather than terminating when it is done with its work, it adds its index to the list of indices of idle tasks and loops back to its Assign_Work entry to wait for more work. The assignment statement allocating a new task would be replaced by a statement removing the first idle-task index from the list, then calling the Assign_Work entry of the corresponding array element. Norman Cohen IBM Research