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=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,df149c0eae46ddaf X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Freeing pointer to task? Date: 1999/03/20 Message-ID: #1/1 X-Deja-AN: 457022259 Sender: matt@mheaney.ni.net References: NNTP-Posting-Date: Sat, 20 Mar 1999 14:23:08 PDT Newsgroups: comp.lang.ada Date: 1999-03-20T00:00:00+00:00 List-Id: "joeprogrammer" writes: > Say you dynamically create a task using the "new" operator, the task runs > and terminates normally. Should you then use an instantiation of > Unchecked_Deallocation() to free the memory allocated to the pointer to the > task as you would with any other data type? Or is that not needed with > tasks? Do you really have to deallocate the task? I prefer to use a storage pool, so that when you're done with an allocated task, you can put it into an idle state just before returning it to the pool. Like this: type Node_Type; type Node_Access is access Node_Type; task type T is entry Start_Up; entry Shut_Down; entry ; end T; type Node_T is limited record O : T; Next : Node_Access; end record; task body T is begin <> null; select accept Start_Up; or terminate; end select; <
> null; ... accept Shut_Down; goto Idle; ... goto Main; end T; Free_List : Node_Access; function New_Task return Node_Access is Node : Node_Access; begin if Free_List = null then Node := new Node_Type; else Node := Free_List; Free_List := Free_List.Next; Node.Next := null; end if; Node.O.Start_Up; <--!!! return Node; end New_Task; procedure Free (Node : in out Node_Access) is begin if Node /= null then Node.O.Shut_Down; <--!!! Node.Next := Free_List; Free_List := Node; end if; end Free; > Can not find any details on this topic. I only know that it is a no-no to > free the pointer as a means of terminating the task. There are really two entities you have to be aware of: the "task" and the "task object." When you declare a task, like this: My_Task : My_Task_Type; you are really declaring a "task object" that is a handle of some kind to the actual "task." The task object elaborates at its point of declaration, but the task itself "activates" later, immediately after the "begin" keyword of the declarative region. So My_Task is a task object, not a task. The task object may only be 4 or 8 bytes -- whatever representation is needed by the compiler to identify the actual task. The rule is slightly different for tasks on the heap: the task object elaborates in the normal way, but the task it designates activates right away. So if you do this: task type My_Task_Type is ...; type My_Task_Access is access My_Task_Type; procedure Free is new Unchecked_Deallocation (My_Task_Type, My_Task_Access); My_Task : My_Task_Access := new My_Task_Type; and then you later call Free: Free (My_Task); then what you are really freeing is the task object, not the task. Maybe you freed 4 or 8 bytes worth of task object, but you probably did not free the memory associated with the task itself. The task is alive and well thank you very much (unless it has been terminated), but now you've destroyed your only way to identify it, and now you can't even make entry calls. If you want the task to get deallocated as a result of deallocating the memory for the task object, it requires a run-time that is smart enough to know that what you're deallocating is a task handle, and should do some extra work for this special case. But most memory management implementations just work in terms of raw bytes, and don't know anything about what's in those bytes. Tucker had wanted to make it a new language rule that if you free a task object whose associated task wasn't yet terminated that you'd get Program_Error. However, this wasn't backwards compatible. However, in Ada95, tasks can have a discriminant. So if you try to deallocate a non-terminated task that has a discriminant, this task must have been written using an Ada95 compiler, and in this case the implementation is allowed to raise Tasking_Error, or Program_Error, or indeed do nothing. See RM95 13.11.2 (11-14). So a little trick you can do, if you really want to deallocate tasks, is to give the task a dummy discriminant, so the Ada95 rules will apply. But this is all implementation dependent anyway. And even if you the task is terminated, there's still no guarantee that the memory for the task will get deallocated. My advice to you is to not deallocate tasks. Put tasks on a linked list as I showed above, so that you can reuse tasks that have already been allocated. In this way, you avoid having to ask questions like, How do I free the memory for the task? The answer is: don't bother trying.