Reclamation of memory for dynamic Ada tasking

Philip J. Lefebvre · 1987

While working on several large-scale Ada projects, I have found what I consider a major problem with the Ada Tasking mechanism, that is, the reclamation of memory allocated to a dynamic task after the task has been terminated. I have written my own utility package to specifically deallocate the memory assigned to any such task.The problem arises from the fact that dynamically created tasks are generated by the use of allocators. The Ada Language Reference Manual ( LRM ) states“An implementation must guarantee that any object created by the evaluation of an allocator remains allocated for as long as this object or one of its subcomponents is accessible directly or indirectly, that is, as long as it can be denoted by some name.”1This stipulation presents an interesting problem when applied to tasks. If the access type of a task is created within a library unit, memory allocated to execute this task will remain allocated for the entire span of the execution of program, even though the actual task object may have been terminated. Diagram 1 illustrates that memory is retained after a task is terminated.A more truly dynamic tasking model is needed in the Ada language. The model which is provided within the language does allow for the creation of tasks at runtime. This facility is useful when creating tasks that exist for the lifetime of the program, or for applications where memory management is not relevant. The problem with the current tasking model is that it does not allow a task, whose master is a library unit, to be created dynamically, to perform a specific action, and then to terminate and release all the memory reserved for the execution of the task.This failure to properly deallocate memory seems to be a problem inherent in the Ada language. It was at first believed that the algorithms used in Ada compilers to implement dynamic allocation of objects would enable them to perform sufficient garbage collection to improve management of the heap at runtime. This, however, did not prove to be the case. An optional Unchecked_Deallocation procedure was added to the standard predefined library units that may be delivered with an Ada development system. The Unchecked_Deallocation procedure does solve the problem of most storage reclamation, but the developers of the language did not allow memory allocated to dynamically created task objects to be reclaimed in a similar manner. The LRM states “If X designates a task object, the call FREE(X) has no effect on the task designated by the value of this task object.”2 I suspect that this specification was an attempt to prevent deallocating a currently active task.Because the language implementors are specifically prohibited from properly deallocating dynamic task memory, it is left to the individual Ada programmer to implement his or her own solution. For my solution I have identified two major functions which any algorithm attempting to solve this problem must address. First, the algorithm must have the ability to dynamically create tasks whose masters are blocks that can be exited, reclaiming the memory used to execute the tasks. Second, the algorithm must increase the scope of this task to areas outside of this block to allow task communication. This increase of scope must be done within the confines of the Ada Language so that the utility is portable.The concept behind the utility is the declaration of an access type of a task type within a block statement or a subprogram that can be exited after the completion of the task ( see diagram 2 ). I will refer to this block as the Master Block. Since the access type is declare inside the Master Block, any task that is created by an allocator of that access type ( referred to as the Dynamic Task ) will have the Master Block as its master. After the task is terminated, the block is exited and all the storage allocated to that task is reclaimed.Note that if the Environment Task ( the task that calls the main program ) were to call the Master Block, all other activity within the Environment Task would be suspended until the Dynamic Task completed. Upon completion, control would be released from the Master Block and given back to the Environment Task. The same effect would be exhibited by any other task calling the Master Block. Obviously, this reduction of execution to a fully sequential path is not acceptable; a second task must be created which can call the Master Block. I will refer to this task at the Base Task.Task communication can be accomplished by use of the Unchecked_Conversion utility ( see diagram 2 ). To provide visibility to the dynamically created task, the access type within the Master Block is not checked when converting it to an object of a second access task type who's master is the program unit. This point will be elaborated on in the task communication section.Several more complex questions remain in the description of the algorithm. How does the algorithm create more than one task?How does the algorithm determine when a task is terminated?How does the algorithm control access to the pointers to prevent access to deallocated storage?How does the algorithm allow for rendezvous with these tasks?These questions are addressed individually below.

Read the paper · More papers on PaperTik