comp.lang.ada
 help / color / mirror / Atom feed
* Task origin track from a class
@ 2011-07-12  3:24 Rego, P.
  2011-07-12  5:57 ` Simon Wright
  2011-07-12  7:41 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 12+ messages in thread
From: Rego, P. @ 2011-07-12  3:24 UTC (permalink / raw)


I have a class Def_Class which defines a record which is a task. Say:
	task type My_Task_Kind;
	
	type Def_Class is tagged limited
		record
			Some_Element : Integer; -- or other type anyway
			My_Task : My_Task_Kind;
		end record;
		
and I want to access my class inside the task body, something like
	type body My_Task_Kind (Origin: Def_Class) is
	begin
		if Origin.Some_Element = 1 then
			(...)
		end if;
	end My_Task_Kind;

So how can I do it? (I tried to use an entry type, but got problems with limited/non limited types, so asking for help!!)



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-12  3:24 Task origin track from a class Rego, P.
@ 2011-07-12  5:57 ` Simon Wright
  2011-07-12  7:41 ` Dmitry A. Kazakov
  1 sibling, 0 replies; 12+ messages in thread
From: Simon Wright @ 2011-07-12  5:57 UTC (permalink / raw)


"Rego, P." <pvrego@gmail.com> writes:

> I have a class Def_Class which defines a record which is a task. Say:
> 	task type My_Task_Kind;
>
> 	type Def_Class is tagged limited
> 		record
> 			Some_Element : Integer; -- or other type anyway
> 			My_Task : My_Task_Kind;
> 		end record;
>
> and I want to access my class inside the task body, something like
> 	type body My_Task_Kind (Origin: Def_Class) is
> 	begin
> 		if Origin.Some_Element = 1 then
> 			(...)
> 		end if;
> 	end My_Task_Kind;
>
> So how can I do it? (I tried to use an entry type, but got problems
> with limited/non limited types, so asking for help!!)

Using a constraint:

   package Rego is

      type C;

      task type T (The_C : access C);

      type C is tagged limited record
         The_T : T (C'Access);
         Done : Boolean := False;
      end record;

   end Rego;


   package body Rego is

      task body T is
      begin
         The_C.Done := True;
      end;

   end Rego;


   with Ada.Text_IO; use Ada.Text_IO;
   with Rego;
   procedure Rego_D is
      The_C : Rego.C;
   begin
      Put_Line (Boolean'Image (The_C.Done));
   end Rego_D;



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-12  3:24 Task origin track from a class Rego, P.
  2011-07-12  5:57 ` Simon Wright
@ 2011-07-12  7:41 ` Dmitry A. Kazakov
  2011-07-12 10:29   ` Simon Wright
  1 sibling, 1 reply; 12+ messages in thread
From: Dmitry A. Kazakov @ 2011-07-12  7:41 UTC (permalink / raw)


On Mon, 11 Jul 2011 20:24:04 -0700 (PDT), Rego, P. wrote:

> I have a class Def_Class which defines a record which is a task.

You shouldn't do that, because most likely you will later have serious
(unsolvable) problems with the object's finalization.

Unless the task has somewhere a select with an open terminate alternative,
the object's finalization will hang.

Note that deriving it from Ada.Finalization.Limited_Controlled won't help.
Consider this:

      type Parent;
      task type Worker (Data : not null access Parent'Class) is
         entry Do_Stuff;
         entry Stop;
      end Worker;
      type Parent is
         new Ada.Finalization.Limited_Controlled with
      record
         My_Task : Worker (Parent'Access);
      end record;
      overriding procedure Finalize (Object : in out Parent);

and the implementation:

      procedure Finalize (Object : in out Parent) is
      begin
         Object.My_Task.Stop; -- Kill the task
      end Finalize;
      
      task body Worker is
      begin
         loop
            select
               accept Do_Stuff;
                -- Some useful stuff to do
            or accept Stop;
               exit;
            end select;
         end loop;
      end Worker;

This does *not* work! The problem is that the task must complete *before*
Finalize of the containing object is called. It would work if the select of
the task would have:

   or terminate;  -- Complete if asked

(and then the Stop entry call removed from Finalize, of course).

The problem with this is that too frequently there is no way to add the
terminate alternative (for various reasons, which are irrelevant here).

So the unfortunate rule of the thumb is: never use task components, but
access to task instead. From Finalize you would call Stop entry or an
equivalent and then free the task object using Unchecked_Deallocation.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-12  7:41 ` Dmitry A. Kazakov
@ 2011-07-12 10:29   ` Simon Wright
  2011-07-12 10:31     ` Simon Wright
  0 siblings, 1 reply; 12+ messages in thread
From: Simon Wright @ 2011-07-12 10:29 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> So the unfortunate rule of the thumb is: never use task components,
> but access to task instead. From Finalize you would call Stop entry or
> an equivalent and then free the task object using
> Unchecked_Deallocation.

With GNAT, best not to free the task object until 'Terminated is True
(GNAT's I have used would silently fail to actually free the TCB!
resulting in an insidious memory leak).



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-12 10:29   ` Simon Wright
@ 2011-07-12 10:31     ` Simon Wright
  2011-07-13  0:36       ` Shark8
  0 siblings, 1 reply; 12+ messages in thread
From: Simon Wright @ 2011-07-12 10:31 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>
>> So the unfortunate rule of the thumb is: never use task components,
>> but access to task instead. From Finalize you would call Stop entry or
>> an equivalent and then free the task object using
>> Unchecked_Deallocation.
>
> With GNAT, best not to free the task object until 'Terminated is True
> (GNAT's I have used would silently fail to actually free the TCB!
> resulting in an insidious memory leak).

Oops, I forgot to add that I'd aborted the task first (as Dmitry said,
it's not always possible to arrange a clean shutdown).



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-12 10:31     ` Simon Wright
@ 2011-07-13  0:36       ` Shark8
  2011-07-13  2:57         ` Rego, P.
  2011-07-13  7:41         ` Dmitry A. Kazakov
  0 siblings, 2 replies; 12+ messages in thread
From: Shark8 @ 2011-07-13  0:36 UTC (permalink / raw)


On Jul 12, 5:31 am, Simon Wright <si...@pushface.org> wrote:
> Simon Wright <si...@pushface.org> writes:
> > "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> writes:
>
> >> So the unfortunate rule of the thumb is: never use task components,
> >> but access to task instead. From Finalize you would call Stop entry or
> >> an equivalent and then free the task object using
> >> Unchecked_Deallocation.
>
> > With GNAT, best not to free the task object until 'Terminated is True
> > (GNAT's I have used would silently fail to actually free the TCB!
> > resulting in an insidious memory leak).
>
> Oops, I forgot to add that I'd aborted the task first (as Dmitry said,
> it's not always possible to arrange a clean shutdown).

Hm, would it be a usable idea for say the memory manager for an OS,
such that the requests to the manager from programs (and perhaps even
compilers) are delegated to the task; after all you don't want to shut
the memory-manager down (terminate the task) at any point in normal
operation.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-13  0:36       ` Shark8
@ 2011-07-13  2:57         ` Rego, P.
  2011-07-13  7:41         ` Dmitry A. Kazakov
  1 sibling, 0 replies; 12+ messages in thread
From: Rego, P. @ 2011-07-13  2:57 UTC (permalink / raw)


Thanks people. I'm going to study your suggestions.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-13  0:36       ` Shark8
  2011-07-13  2:57         ` Rego, P.
@ 2011-07-13  7:41         ` Dmitry A. Kazakov
  2011-07-13  8:43           ` Georg Bauhaus
  2011-07-13 16:31           ` Shark8
  1 sibling, 2 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2011-07-13  7:41 UTC (permalink / raw)


On Tue, 12 Jul 2011 17:36:29 -0700 (PDT), Shark8 wrote:

> On Jul 12, 5:31�am, Simon Wright <si...@pushface.org> wrote:
>> Simon Wright <si...@pushface.org> writes:
>>> "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> writes:
>>
>>>> So the unfortunate rule of the thumb is: never use task components,
>>>> but access to task instead. From Finalize you would call Stop entry or
>>>> an equivalent and then free the task object using
>>>> Unchecked_Deallocation.
>>
>>> With GNAT, best not to free the task object until 'Terminated is True
>>> (GNAT's I have used would silently fail to actually free the TCB!
>>> resulting in an insidious memory leak).
>>
>> Oops, I forgot to add that I'd aborted the task first (as Dmitry said,
>> it's not always possible to arrange a clean shutdown).
> 
> Hm, would it be a usable idea for say the memory manager for an OS,
> such that the requests to the manager from programs (and perhaps even
> compilers) are delegated to the task; after all you don't want to shut
> the memory-manager down (terminate the task) at any point in normal
> operation.

The issue has nothing to do with memory management. The actual problems
are:

1. The procedure of destruction of the objects having task components.
Tasks are completed *before* Finalize is called. Ada's approach to
construction/destruction is very much broken. This is just one example of
this.

2. The usage of the terminate alternative which cannot be mixed with for
example the delay alternative.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-13  7:41         ` Dmitry A. Kazakov
@ 2011-07-13  8:43           ` Georg Bauhaus
  2011-07-13 11:59             ` Dmitry A. Kazakov
  2011-07-13 16:31           ` Shark8
  1 sibling, 1 reply; 12+ messages in thread
From: Georg Bauhaus @ 2011-07-13  8:43 UTC (permalink / raw)


On 7/13/11 9:41 AM, Dmitry A. Kazakov wrote:
> On Tue, 12 Jul 2011 17:36:29 -0700 (PDT), Shark8 wrote:
>
> The actual problems are:
>
> 1. The procedure of destruction of the objects having task components.
> Tasks are completed *before* Finalize is called. Ada's approach to
> construction/destruction is very much broken.

When the life time of objects is determined by Ada's
language rules (and not by the type system), isn't it
normal to expect that the language defined wrecking
ball smashes the thing only after it has finished?

What would be the alternative?  Would it be that the
programmer then has to actively manage all parts of
destruction  himself?

When an implementation collects garbage, when would
the "destructor" run?  Do finalization and RAII destruction(?)
have to be separate things?



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-13  8:43           ` Georg Bauhaus
@ 2011-07-13 11:59             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2011-07-13 11:59 UTC (permalink / raw)


On Wed, 13 Jul 2011 10:43:15 +0200, Georg Bauhaus wrote:

> On 7/13/11 9:41 AM, Dmitry A. Kazakov wrote:
>> On Tue, 12 Jul 2011 17:36:29 -0700 (PDT), Shark8 wrote:
>>
>> The actual problems are:
>>
>> 1. The procedure of destruction of the objects having task components.
>> Tasks are completed *before* Finalize is called. Ada's approach to
>> construction/destruction is very much broken.
> 
> When the life time of objects is determined by Ada's
> language rules (and not by the type system), isn't it
> normal to expect that the language defined wrecking
> ball smashes the thing only after it has finished?

Finalize is expected to have the object fully operational if called for the
first time. Which is not the case for the task components.

> What would be the alternative?  Would it be that the
> programmer then has to actively manage all parts of
> destruction  himself?

Not at all. The alternative is for the user-defined
constructor/destructor's hook to meet all components valid when called.
Finalize is not such a hook.

> When an implementation collects garbage, when would
> the "destructor" run?

The destructor of the type T to be called before the memory allocated for
the object loses its attribution to the type T. Note that this does not
imply deallocation. For instance when S is demoted to its base type T, the
destructor of S must be called to make a T out of S.

>  Do finalization and RAII destruction(?)
> have to be separate things?

Finalization is another word for destruction. (I am not a language lawyer
and don't about what RM might say about it)

Again, observe that promotion requires a partial construction while
demotion does a partial destruction. The primitive operation Finalize is a
partial destructor. A complete destruction includes the bodies of the
Finalize from all bases and destructors of all components.

Note also that a consistent model must also provide hooks for
promotion/demotion to the class (e.g. S -> T'Class, T'Class -> S).

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-13  7:41         ` Dmitry A. Kazakov
  2011-07-13  8:43           ` Georg Bauhaus
@ 2011-07-13 16:31           ` Shark8
  2011-07-13 17:22             ` Dmitry A. Kazakov
  1 sibling, 1 reply; 12+ messages in thread
From: Shark8 @ 2011-07-13 16:31 UTC (permalink / raw)


On Jul 13, 2:41 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> On Tue, 12 Jul 2011 17:36:29 -0700 (PDT), Shark8 wrote:
> > On Jul 12, 5:31 am, Simon Wright <si...@pushface.org> wrote:
> >> Simon Wright <si...@pushface.org> writes:
> >>> "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> writes:
>
> >>>> So the unfortunate rule of the thumb is: never use task components,
> >>>> but access to task instead. From Finalize you would call Stop entry or
> >>>> an equivalent and then free the task object using
> >>>> Unchecked_Deallocation.
>
> >>> With GNAT, best not to free the task object until 'Terminated is True
> >>> (GNAT's I have used would silently fail to actually free the TCB!
> >>> resulting in an insidious memory leak).
>
> >> Oops, I forgot to add that I'd aborted the task first (as Dmitry said,
> >> it's not always possible to arrange a clean shutdown).
>
> > Hm, would it be a usable idea for say the memory manager for an OS,
> > such that the requests to the manager from programs (and perhaps even
> > compilers) are delegated to the task; after all you don't want to shut
> > the memory-manager down (terminate the task) at any point in normal
> > operation.
>
> The issue has nothing to do with memory management.

You misunderstand me; I was asking that if it's generally impossible
to destroy such a construct then would the use of such a construct be
allowable (or desirable) in the cases where the destruction of such
construct is itself generally undesirable/invalid.

> The actual problems
> are:
>
> 1. The procedure of destruction of the objects having task components.
> Tasks are completed *before* Finalize is called.

Shouldn't they be completed before Finalization of the object?
And, if they are still running, shouldn't a finalize force termination?



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Task origin track from a class
  2011-07-13 16:31           ` Shark8
@ 2011-07-13 17:22             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry A. Kazakov @ 2011-07-13 17:22 UTC (permalink / raw)


On Wed, 13 Jul 2011 09:31:47 -0700 (PDT), Shark8 wrote:

> On Jul 13, 2:41�am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>> On Tue, 12 Jul 2011 17:36:29 -0700 (PDT), Shark8 wrote:
>>> On Jul 12, 5:31�am, Simon Wright <si...@pushface.org> wrote:
>>>> Simon Wright <si...@pushface.org> writes:
>>>>> "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> writes:
>>
>>>>>> So the unfortunate rule of the thumb is: never use task components,
>>>>>> but access to task instead. From Finalize you would call Stop entry or
>>>>>> an equivalent and then free the task object using
>>>>>> Unchecked_Deallocation.
>>
>>>>> With GNAT, best not to free the task object until 'Terminated is True
>>>>> (GNAT's I have used would silently fail to actually free the TCB!
>>>>> resulting in an insidious memory leak).
>>
>>>> Oops, I forgot to add that I'd aborted the task first (as Dmitry said,
>>>> it's not always possible to arrange a clean shutdown).
>>
>>> Hm, would it be a usable idea for say the memory manager for an OS,
>>> such that the requests to the manager from programs (and perhaps even
>>> compilers) are delegated to the task; after all you don't want to shut
>>> the memory-manager down (terminate the task) at any point in normal
>>> operation.
>>
>> The issue has nothing to do with memory management.
> 
> You misunderstand me; I was asking that if it's generally impossible
> to destroy such a construct then would the use of such a construct be
> allowable (or desirable) in the cases where the destruction of such
> construct is itself generally undesirable/invalid.

It is possible, the requirement, as I said, is an open terminate
alternative.

>> The actual problems
>> are:
>>
>> 1. The procedure of destruction of the objects having task components.
>> Tasks are completed *before* Finalize is called.
> 
> Shouldn't they be completed before Finalization of the object?

Yes, the question is at which part of finalization. Finalization is a
complex action.

BTW, it is not just Finalize. If you considered to pass some parameters to
a task component, you cannot do it from Initialize. The following does
*not* work:

      task type Worker is
         entry Start (Text : String);
      end Worker;
      type T is
         new Ada.Finalization.Limited_Controlled with
      record
         My_Task : Worker;
      end record;
      overriding procedure Initialize (Object : in out T);

      task body Worker is
      begin
         accept Start (Text : String) do
            Ada.Text_IO.Put_Line (Text);
         end Start;
      end Worker;
      procedure Initialize (Object : in out T) is
      begin
         Object.My_Task.Start ("Hey"); -- Beware, it will hang!
      end Initialize;

This is not a compiler bug, it is a mandated behavior.

> And, if they are still running, shouldn't a finalize force termination?

You cannot force task termination because the tasking model is cooperative.
In particular you should never use the abort statement unless the task was
carefully designed to be abortable. It should not allocate any resources
which might get lost upon a preemptive task termination. One way to make a
task abortable is to have a controlled object of which Finalize does the
cleanup:

   task Abortable is
      Resources : Controlled_Object;
   begin
      loop
         ...
      end loop;
   end Abortable;

when Aboortable is aborted the Resources' Finalize will be called so that
you could do the necessary cleanup before the task dies. Note that Finalize
is abort-deferred, it means that you cannot abort a Finalize (when Finalize
is called as a part of finalization), it must complete first.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-07-13 17:22 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-12  3:24 Task origin track from a class Rego, P.
2011-07-12  5:57 ` Simon Wright
2011-07-12  7:41 ` Dmitry A. Kazakov
2011-07-12 10:29   ` Simon Wright
2011-07-12 10:31     ` Simon Wright
2011-07-13  0:36       ` Shark8
2011-07-13  2:57         ` Rego, P.
2011-07-13  7:41         ` Dmitry A. Kazakov
2011-07-13  8:43           ` Georg Bauhaus
2011-07-13 11:59             ` Dmitry A. Kazakov
2011-07-13 16:31           ` Shark8
2011-07-13 17:22             ` Dmitry A. Kazakov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox