comp.lang.ada
 help / color / mirror / Atom feed
* Class with task destructor
@ 2011-11-23  1:50 Rego, P.
  2011-11-23  2:44 ` Adam Beneschan
                   ` (2 more replies)
  0 siblings, 3 replies; 50+ messages in thread
From: Rego, P. @ 2011-11-23  1:50 UTC (permalink / raw)


So now I have a class with a task inside and a Constructor, and I want to implement a destructor.

--test_pkg.ads
with Unchecked_Deallocation;
package Test_Pkg is

   type Test_Class is tagged;
   type Test_Class_Ptr is access all Test_Class;
   
   function Construct return Test_Class_Ptr;
   procedure Destruct (T : access Test_Class);
 
   task type Primary_Task (This : not null access Test_Class) is 
      entry Start;
      entry Pause;
      entry Release;
      entry Finish;
   end Primary_Task;
   
   type Test_Class is tagged limited
      record
         Some_Info : Integer;
         Primary   : Primary_Task (Test_Class'Access);
      end record;
   
   procedure Free is new Unchecked_Deallocation (Object => Test_Class,
                                                 Name   => Test_Class_Ptr);
end Test_Pkg;

--test_pkg_main.adb
with Test_Pkg; use Test_Pkg;

procedure Test_Pkg_Main is
   Obj_Ptr : Test_Class_Ptr;
begin
   Obj_Ptr := Construct;
   delay 5.0;
   Obj_Ptr.Destruct;

end Test_Pkg_Main;

--test_pkg.adb
with Text_IO; use Text_IO;
package body Test_Pkg_Rev661 is
   task body Primary_Task is
   begin
      Outer_Loop : loop
         select
            accept Start;
            Main_Loop : loop
               select
                  accept Pause;
                  select
                     accept Release;
                  or
                     accept Finish;
                     exit Outer_Loop;
                  or
                     terminate;
                  end select;
               or
                  accept Finish;
                  exit Outer_Loop;
               else
                  Put ("^"&Integer'Image (This.Some_Info));
                  delay 0.5;
               end select;
            end loop Main_Loop;
         or
            terminate;
         end select;
      end loop Outer_Loop;
   end Primary_Task;

   function Construct return Test_Class_Ptr is
      T_Ptr : constant Test_Class_Ptr := new Test_Class;
   begin
      T_Ptr.Some_Info := 1;
      T_Ptr.Primary.Start;
      return T_Ptr;
   end Construct;

   procedure Destruct (T : access Test_Class) is
   ...
   end Destruct;
end Test_Pkg_Rev661;

--
(1) So, the first implementation I tried was
   procedure Destruct (T : access Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
   begin
      Free (T_Ptr);
   end Destruct;

So I thought that if I unallocate the object, the task inside would be dead too, because the object would be its master. It looks that I'm wrong, because the execution led me to

^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 6295912^ 6295912^ (...)
then the task is not dead after the object dies. 
So why is this implementation wrong?

(2) The second one implementation I tried, which looks me that led me to a (happy) program termination was 
   procedure Destruct (T : access Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
   begin
      T.Primary.Finish;
      Free (T_Ptr);
   end Destruct;

and the execution leds me to
^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1 (and no more)

I agree that in this case the task is dead, because of the forced termination. And so on the object itself. But is this implementation preferable over the first one?

Thank you again.



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

* Re: Class with task destructor
  2011-11-23  1:50 Class with task destructor Rego, P.
@ 2011-11-23  2:44 ` Adam Beneschan
  2011-11-23  5:04   ` Yannick Duchêne (Hibou57)
  2011-11-23  8:35 ` Dmitry A. Kazakov
  2011-11-23 10:26 ` Brian Drummond
  2 siblings, 1 reply; 50+ messages in thread
From: Adam Beneschan @ 2011-11-23  2:44 UTC (permalink / raw)


Although I haven't looked into this too rigorously, I think the
problem (with the first implementation) is that neither "terminate"
alternative in the task is given a chance to work.  First of all, you
have "select accept Start; ... or terminate;" (the second "or
terminate, toward the end of Primary_Task).  Start is called right
away, so we go into that branch.  Then we go into Main_Loop, and you
have a select with three alternatives: accept Pause; accept Finish; or
an "else" that will get executed right away if nobody is calling Pause
and Finish.  Pause isn't called anywhere, and in your first
implementation Finish isn't called everywhere.  Thus, the select goes
right to the "else" branch, which does a Put and a delay, then you
loop back to do it again, and since Pause and Finish aren't still
being called, it goes to the Put and delay again, and it keeps going
round and round and round.  The inner "select" that has the terminate
alternative never gets executed since you have to accept Pause first,
and the outer "select" with the terminate alternative never gets
executed since you never get out of Main_Loop.  So the "terminate"
alternatives in your task never have any effect.

The language rules say that Unchecked_Deallocation doesn't force tasks
to terminate.  I believe he only way to terminate a task that doesn't
terminate on its own (either by leaving the task body, or by a
terminate alternative) is to use ABORT (or
Ada.Task_Identification.Abort_Task).  And I wouldn't do that if there
are other ways to get a task to terminate.

                        -- Adam




On Nov 22, 5:50 pm, "Rego, P." <pvr...@gmail.com> wrote:
> So now I have a class with a task inside and a Constructor, and I want to implement a destructor.
>
> --test_pkg.ads
> with Unchecked_Deallocation;
> package Test_Pkg is
>
>    type Test_Class is tagged;
>    type Test_Class_Ptr is access all Test_Class;
>
>    function Construct return Test_Class_Ptr;
>    procedure Destruct (T : access Test_Class);
>
>    task type Primary_Task (This : not null access Test_Class) is
>       entry Start;
>       entry Pause;
>       entry Release;
>       entry Finish;
>    end Primary_Task;
>
>    type Test_Class is tagged limited
>       record
>          Some_Info : Integer;
>          Primary   : Primary_Task (Test_Class'Access);
>       end record;
>
>    procedure Free is new Unchecked_Deallocation (Object => Test_Class,
>                                                  Name   => Test_Class_Ptr);
> end Test_Pkg;
>
> --test_pkg_main.adb
> with Test_Pkg; use Test_Pkg;
>
> procedure Test_Pkg_Main is
>    Obj_Ptr : Test_Class_Ptr;
> begin
>    Obj_Ptr := Construct;
>    delay 5.0;
>    Obj_Ptr.Destruct;
>
> end Test_Pkg_Main;
>
> --test_pkg.adb
> with Text_IO; use Text_IO;
> package body Test_Pkg_Rev661 is
>    task body Primary_Task is
>    begin
>       Outer_Loop : loop
>          select
>             accept Start;
>             Main_Loop : loop
>                select
>                   accept Pause;
>                   select
>                      accept Release;
>                   or
>                      accept Finish;
>                      exit Outer_Loop;
>                   or
>                      terminate;
>                   end select;
>                or
>                   accept Finish;
>                   exit Outer_Loop;
>                else
>                   Put ("^"&Integer'Image (This.Some_Info));
>                   delay 0.5;
>                end select;
>             end loop Main_Loop;
>          or
>             terminate;
>          end select;
>       end loop Outer_Loop;
>    end Primary_Task;
>
>    function Construct return Test_Class_Ptr is
>       T_Ptr : constant Test_Class_Ptr := new Test_Class;
>    begin
>       T_Ptr.Some_Info := 1;
>       T_Ptr.Primary.Start;
>       return T_Ptr;
>    end Construct;
>
>    procedure Destruct (T : access Test_Class) is
>    ...
>    end Destruct;
> end Test_Pkg_Rev661;
>
> --
> (1) So, the first implementation I tried was
>    procedure Destruct (T : access Test_Class) is
>       T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
>    begin
>       Free (T_Ptr);
>    end Destruct;
>
> So I thought that if I unallocate the object, the task inside would be dead too, because the object would be its master. It looks that I'm wrong, because the execution led me to
>
> ^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 6295912^ 6295912^ (...)
> then the task is not dead after the object dies.
> So why is this implementation wrong?
>
> (2) The second one implementation I tried, which looks me that led me to a (happy) program termination was
>    procedure Destruct (T : access Test_Class) is
>       T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
>    begin
>       T.Primary.Finish;
>       Free (T_Ptr);
>    end Destruct;
>
> and the execution leds me to
> ^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1 (and no more)
>
> I agree that in this case the task is dead, because of the forced termination. And so on the object itself. But is this implementation preferable over the first one?
>
> Thank you again.




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

* Re: Class with task destructor
  2011-11-23  2:44 ` Adam Beneschan
@ 2011-11-23  5:04   ` Yannick Duchêne (Hibou57)
  2011-11-23  6:14     ` Adam Beneschan
  0 siblings, 1 reply; 50+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2011-11-23  5:04 UTC (permalink / raw)


Le Wed, 23 Nov 2011 03:44:39 +0100, Adam Beneschan <adam@irvine.com> a  
écrit:
> The language rules say that Unchecked_Deallocation doesn't force tasks
> to terminate.
But it should, because unless I missed something, it seems in this example  
case at least, this lead to a dangling reference.

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: [Epigrams on Programming — Alan J. — P. Yale University]



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

* Re: Class with task destructor
  2011-11-23  5:04   ` Yannick Duchêne (Hibou57)
@ 2011-11-23  6:14     ` Adam Beneschan
  2011-11-24  0:15       ` Randy Brukardt
  0 siblings, 1 reply; 50+ messages in thread
From: Adam Beneschan @ 2011-11-23  6:14 UTC (permalink / raw)


On Nov 22, 9:04 pm, Yannick Duchêne (Hibou57)
<yannick_duch...@yahoo.fr> wrote:
> Le Wed, 23 Nov 2011 03:44:39 +0100, Adam Beneschan <a...@irvine.com> a
> écrit:> The language rules say that Unchecked_Deallocation doesn't force tasks
> > to terminate.
>
> But it should, because unless I missed something, it seems in this example
> case at least, this lead to a dangling reference.

*Any* use of Unchecked_Deallocation can lead to a dangling reference,
which is why it's called Unchecked.  But also note that the language
explicitly says that if you use Unchecked_Deallocation on an object
that contains tasks, the object might not actually disappear
(13.11.2(9)).  I'm not sure if there are language rules that say that
the object *must* not be deallocated immediately in a case like this,
where the task has a discriminant that refers to the object being
freed.  I don't have time to look into it at the moment.  Maybe
someone else knows?

                           -- Adam




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

* Re: Class with task destructor
  2011-11-23  1:50 Class with task destructor Rego, P.
  2011-11-23  2:44 ` Adam Beneschan
@ 2011-11-23  8:35 ` Dmitry A. Kazakov
  2011-11-23  9:05   ` Simon Wright
                     ` (2 more replies)
  2011-11-23 10:26 ` Brian Drummond
  2 siblings, 3 replies; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-11-23  8:35 UTC (permalink / raw)


On Tue, 22 Nov 2011 17:50:45 -0800 (PST), Rego, P. wrote:

> So now I have a class with a task inside and a Constructor, and I want to implement a destructor.
[...]

If you have Start and Finish entries, you don't need terminate alternative.
Use Ada.Finalization.Limited_Controlled as the base. Make task an access to
task component. Initialize should allocate the task. You don't need Start
entry at all. (The only use for Start is passing additional parameters to
the task) From Finalize you call to Finish and then free the task. The
constructing function *shall* not use pointers.

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



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

* Re: Class with task destructor
  2011-11-23  8:35 ` Dmitry A. Kazakov
@ 2011-11-23  9:05   ` Simon Wright
  2011-11-23 10:41     ` Dmitry A. Kazakov
                       ` (3 more replies)
  2011-11-25  2:44   ` Rego, P.
       [not found]   ` <28489797.1088.1322188495508.JavaMail.geo-discussion-forums@yqf20>
  2 siblings, 4 replies; 50+ messages in thread
From: Simon Wright @ 2011-11-23  9:05 UTC (permalink / raw)


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

> On Tue, 22 Nov 2011 17:50:45 -0800 (PST), Rego, P. wrote:
>
>> So now I have a class with a task inside and a Constructor, and I
>> want to implement a destructor.
> [...]
>
> If you have Start and Finish entries, you don't need terminate
> alternative.  Use Ada.Finalization.Limited_Controlled as the
> base. Make task an access to task component. Initialize should
> allocate the task. You don't need Start entry at all. (The only use
> for Start is passing additional parameters to the task) From Finalize
> you call to Finish and then free the task. The constructing function
> *shall* not use pointers.

You ought to wait until the task has terminated before freeing it. I
can't trace it now, but I think that AdaCore recently fixed a feature
where the TCB would be silently not deallocated if the task wasn't
terminated. I had to fix this problem by handing off all tasks to be
deallocated by a low-priority task, which required some interesting
generic/codegen manipulation.

I think that that's a *must* not a *shall*, but it's a little while
since I did requirementese!



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

* Re: Class with task destructor
  2011-11-23  1:50 Class with task destructor Rego, P.
  2011-11-23  2:44 ` Adam Beneschan
  2011-11-23  8:35 ` Dmitry A. Kazakov
@ 2011-11-23 10:26 ` Brian Drummond
  2011-11-25  1:37   ` Rego, P.
  2 siblings, 1 reply; 50+ messages in thread
From: Brian Drummond @ 2011-11-23 10:26 UTC (permalink / raw)


On Tue, 22 Nov 2011 17:50:45 -0800, Rego, P. wrote:

> So now I have a class with a task inside and a Constructor, and I want
> to implement a destructor.

> So I thought that if I unallocate the object, the task inside would be
> dead too, because the object would be its master. It looks that I'm
> wrong, because the execution led me to
> 
> ^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 6295912^ 6295912^ (...) 

Are you by any chance trying something like the RAII pattern in C++?
(which as far as I can see, stands for "automatic destruction is orderly 
shutdown")

If so, I think I'm with Dmitry, in that Controlled (or 
Limited_Controlled) give you the tools to automate the process. 
So your approach (2) is correct; you must stop the task before 
deallocating it. However your class user doesn't need to know that, 
because you can put the detail in Finalize. (which, if Simon is right, 
may need to become a little more complex)

- Brian



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

* Re: Class with task destructor
  2011-11-23  9:05   ` Simon Wright
@ 2011-11-23 10:41     ` Dmitry A. Kazakov
  2011-11-30  1:11     ` Rego, P.
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-11-23 10:41 UTC (permalink / raw)


On Wed, 23 Nov 2011 09:05:51 +0000, Simon Wright wrote:

> You ought to wait until the task has terminated before freeing it. I
> can't trace it now, but I think that AdaCore recently fixed a feature
> where the TCB would be silently not deallocated if the task wasn't
> terminated.

Yes, I think they fixed that. However it would be better to have an
explicit requirement in RM that an instance of Unchecked_Deallocation
blocks until task termination.

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



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

* Re: Class with task destructor
  2011-11-23  6:14     ` Adam Beneschan
@ 2011-11-24  0:15       ` Randy Brukardt
  2011-11-24  2:48         ` Adam Beneschan
  0 siblings, 1 reply; 50+ messages in thread
From: Randy Brukardt @ 2011-11-24  0:15 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 2581 bytes --]

"Adam Beneschan" <adam@irvine.com> wrote in message 
news:bf5f741b-8ced-4530-8090-df6d4e730a5e@e2g2000vbb.googlegroups.com...
>On Nov 22, 9:04 pm, Yannick Duch�ne (Hibou57)
<yannick_duch...@yahoo.fr> wrote:
>> Le Wed, 23 Nov 2011 03:44:39 +0100, Adam Beneschan <a...@irvine.com> a
>> �crit:> The language rules say that Unchecked_Deallocation doesn't force 
>> tasks
>> > to terminate.
>>
>> But it should, because unless I missed something, it seems in this 
>> example
>> case at least, this lead to a dangling reference.
>
>*Any* use of Unchecked_Deallocation can lead to a dangling reference,
>which is why it's called Unchecked.  But also note that the language
>explicitly says that if you use Unchecked_Deallocation on an object
>that contains tasks, the object might not actually disappear
>(13.11.2(9)).  I'm not sure if there are language rules that say that
>the object *must* not be deallocated immediately in a case like this,
>where the task has a discriminant that refers to the object being
>freed.  I don't have time to look into it at the moment.  Maybe
>someone else knows?

The task continues to run (always) through a UC. The compiler has to ensure 
that works, and if that means not deallocating the object, that would work. 
Janus/Ada doesn't work this way, all of the task information is in the TCB 
and there is no connection to the enclosing object. So we can deallocate it 
immediately - the task will still continue to work. TCBs are reused when the 
tasks terminate, and never before.

The requirement that tasks continue to run means that putting a task 
directly in an object will typically lead to a language-required storage 
leak. I always suggest avoiding that. (All of my programs that use tasks use 
fixed pools of tasks that reset themselves after use, in large part because 
tasks can't be managed like other objects.)

One could argue that this behavior is a bug in the Ada Standard (I've 
certainly said that in the past), but there are a number of technical 
reasons that doing something else would be problematical. And changing it 
now would definitely be incompatible - any program that depends on the task 
continuing to run would fail (and in the worst possible way - without any 
indication of the change). We tried to do something else for subpools, but 
the implementation costs were out of hand, and essentially we decided to 
punt (the behavior of tasks in subpools is unspecified) -- hoping to fix 
this somewhere down the line.

                                              Randy.


                           -- Adam





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

* Re: Class with task destructor
  2011-11-24  0:15       ` Randy Brukardt
@ 2011-11-24  2:48         ` Adam Beneschan
  2011-11-29  3:36           ` Randy Brukardt
  0 siblings, 1 reply; 50+ messages in thread
From: Adam Beneschan @ 2011-11-24  2:48 UTC (permalink / raw)


On Nov 23, 4:15 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
>
> >*Any* use of Unchecked_Deallocation can lead to a dangling reference,
> >which is why it's called Unchecked.  But also note that the language
> >explicitly says that if you use Unchecked_Deallocation on an object
> >that contains tasks, the object might not actually disappear
> >(13.11.2(9)).  I'm not sure if there are language rules that say that
> >the object *must* not be deallocated immediately in a case like this,
> >where the task has a discriminant that refers to the object being
> >freed.  I don't have time to look into it at the moment.  Maybe
> >someone else knows?
>
> The task continues to run (always) through a UC. The compiler has to ensure
> that works, and if that means not deallocating the object, that would work.
> Janus/Ada doesn't work this way, all of the task information is in the TCB
> and there is no connection to the enclosing object.

Except that in the OP's case, there *is* a connection: the task has an
access discriminant that will refer to the enclosing object, and if
the task keeps running, it could use that discriminant.  That's what I
wanted to know--in a case like that, are there language rules that say
the object can't be deallocated until the task has completed; or does
the access discriminant just become a dangling reference?  Or does
Janus/Ada (or any other compiler) treat cases like this specially so
that the access discriminant is still valid?  Since
Unchecked_Deallocation is always capable of creating dangling
references, maybe this case isn't so special; I was just wondering
whether this is a special case at all, since off the top of my head it
seems that objects that contain self-references through access
discriminants can't lead to dangling references (through those self-
references) when the objects are deallocated, *unless* they involve a
task that keeps running as in this case.

                        -- Adam



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

* Re: Class with task destructor
  2011-11-23 10:26 ` Brian Drummond
@ 2011-11-25  1:37   ` Rego, P.
  2011-11-25 13:40     ` Brian Drummond
  0 siblings, 1 reply; 50+ messages in thread
From: Rego, P. @ 2011-11-25  1:37 UTC (permalink / raw)


> Are you by any chance trying something like the RAII pattern in C++?
> (which as far as I can see, stands for "automatic destruction is orderly 
> shutdown")
Yes, something like this.
 
> If so, I think I'm with Dmitry, in that Controlled (or 
> Limited_Controlled) give you the tools to automate the process. 
> So your approach (2) is correct; you must stop the task before 
> deallocating it. However your class user doesn't need to know that, 
> because you can put the detail in Finalize. (which, if Simon is right, 
> may need to become a little more complex)
At this point it's not a big issue if the task knows the details. But the finalization timing concerns me a little. No problem if a task gets stuck when other is running, but I intend to run thousands of them in parallel, so I need to ensure this.



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

* Re: Class with task destructor
  2011-11-23  8:35 ` Dmitry A. Kazakov
  2011-11-23  9:05   ` Simon Wright
@ 2011-11-25  2:44   ` Rego, P.
       [not found]   ` <28489797.1088.1322188495508.JavaMail.geo-discussion-forums@yqf20>
  2 siblings, 0 replies; 50+ messages in thread
From: Rego, P. @ 2011-11-25  2:44 UTC (permalink / raw)
  Cc: mailbox

> If you have Start and Finish entries, you don't need terminate alternative.
> Use Ada.Finalization.Limited_Controlled as the base. Make task an access to
> task component. Initialize should allocate the task. You don't need Start
> entry at all. (The only use for Start is passing additional parameters to
> the task) From Finalize you call to Finish and then free the task.

1) Why should I need to use Finalize (instead of direct T.Primary.Finish in Destruct)? Wouldn't be simpler if I used

   procedure Destruct (T : access Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
   begin
      T.Primary.Finish;
      Free (T_Ptr);
   end Destruct;

instead of
 
   overriding procedure Finalize is
   begin 
      T.Primary.Finish;
   end if;

   procedure Destruct (T : access Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
   begin
      T.Finalize;
      Free (T_Ptr);
   end Destruct;
?

2) Anyway, you're suggesting 

   task type Primary_Task (This : not null access Test_Class) is
      entry Pause;
      entry Release;
      entry Finish;
   end Primary_Task;

   type Test_Class is new Limited_Controlled with
      record
         Some_Info : Integer;
         Primary   : Primary_Task (Test_Class'Access);
      end record;
   
   (...)
   task body Primary_Task is
   begin
      Main_Loop : loop
         select
            accept Pause;
            select
               accept Release;
            or
               accept Finish;
               exit Main_Loop;
            end select;
         or
            accept Finish;
            exit Main_Loop;
         else
            Put ("^"&Integer'Image (This.Some_Info));
            delay 0.5;
         end select;
      end loop Main_Loop;
   end Primary_Task;

   (...)
   function Construct return Test_Class_Ptr is
      T_Ptr : constant Test_Class_Ptr := new Test_Class;
   begin
      T_Ptr.Some_Info := 1;
      T_Ptr.Initialize;
      return T_Ptr;
   end Construct;
Right?   
   
3) I didn't override the Initialize. And I have taken out the Start entry, but this leads to 
^ 5242971^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1^ 1

because in the first cycle the Some_Info was not initialized. Maybe I misunderstand when you said to take out Start entry?

 
> The constructing function *shall* not use pointers.
I will use them in a list, that's why I used a pointer.



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

* Re: Class with task destructor
       [not found]   ` <28489797.1088.1322188495508.JavaMail.geo-discussion-forums@yqf20>
@ 2011-11-25  9:19     ` Dmitry A. Kazakov
  2011-11-29  3:40       ` Randy Brukardt
  0 siblings, 1 reply; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-11-25  9:19 UTC (permalink / raw)


On Thu, 24 Nov 2011 18:34:55 -0800 (PST), Rego, P. wrote:

>> If you have Start and Finish entries, you don't need terminate alternative.
>> Use Ada.Finalization.Limited_Controlled as the base. Make task an access to
>> task component. Initialize should allocate the task. You don't need Start
>> entry at all. (The only use for Start is passing additional parameters to
>> the task) From Finalize you call to Finish and then free the task. The
>> constructing function *shall* not use pointers.
> 
> 1) Why should I need to use Finalize (instead of direct T.Primary.Finish in Destruct)?

Because Finalize is always called when the object is being finalized.

> because in the first cycle the Some_Info was not initialized.

Because you have to fix the constructing function to return the object
rather than a pointer. Then you have to ensure that objects cannot be
created otherwise than initialized by that function.

> Maybe I misunderstand when you said to take out Start entry?

The task should be paused initially and first released by the constructing
function.

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



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

* Re: Class with task destructor
  2011-11-25  1:37   ` Rego, P.
@ 2011-11-25 13:40     ` Brian Drummond
  0 siblings, 0 replies; 50+ messages in thread
From: Brian Drummond @ 2011-11-25 13:40 UTC (permalink / raw)


On Thu, 24 Nov 2011 17:37:59 -0800, Rego, P. wrote:

>> Are you by any chance trying something like the RAII pattern in C++?
>> (which as far as I can see, stands for "automatic destruction is
>> orderly shutdown")
> Yes, something like this.
>  
>> If so, I think I'm with Dmitry, in that Controlled (or
>> Limited_Controlled) give you the tools to automate the process. 

> At this point it's not a big issue if the task knows the details. But
> the finalization timing concerns me a little. No problem if a task gets
> stuck when other is running, but I intend to run thousands of them in
> parallel, so I need to ensure this.

Well your user will simply free a controlled object; either by it going 
out of scope (if it's on the stack) or an explicit delete.

Since it's a controlled object, your "Finalize" is automatically called 
before the actual memory is released; it is up to you to write "Finalize" 
to shut the task down properly and only return when this is done. Then 
the actual deallocation will proceed safely. 
What is your concern about that sequence?

- Brian






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

* Re: Class with task destructor
  2011-11-24  2:48         ` Adam Beneschan
@ 2011-11-29  3:36           ` Randy Brukardt
  2011-11-29  9:31             ` Simon Wright
  2011-11-29 15:37             ` Adam Beneschan
  0 siblings, 2 replies; 50+ messages in thread
From: Randy Brukardt @ 2011-11-29  3:36 UTC (permalink / raw)


"Adam Beneschan" <adam@irvine.com> wrote in message 
news:40710291-64ed-46b8-9106-40b7d481effd@b32g2000yqn.googlegroups.com...
On Nov 23, 4:15 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
...
>> The task continues to run (always) through a UC. The compiler has to 
>> ensure
>> that works, and if that means not deallocating the object, that would 
>> work.
>> Janus/Ada doesn't work this way, all of the task information is in the 
>> TCB
>> and there is no connection to the enclosing object.
>
>Except that in the OP's case, there *is* a connection: the task has an
>access discriminant that will refer to the enclosing object, and if
>the task keeps running, it could use that discriminant.

13.11.2(11-15) covers this. Essentially, either no deallocation is done or 
an exception is raised somewhere, sometime. I think Janus/Ada uses the third 
choice, but I'm not sure anymore.

In any case, as I said, you can't sensibly call Unchecked_Deallocation until 
the task is known to have stopped (if it has discriminants). And in any 
case, the storage for the task probably won't be reclaimed for a long time.

                                      Randy.


                                       Randy.





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

* Re: Class with task destructor
  2011-11-25  9:19     ` Dmitry A. Kazakov
@ 2011-11-29  3:40       ` Randy Brukardt
  0 siblings, 0 replies; 50+ messages in thread
From: Randy Brukardt @ 2011-11-29  3:40 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1hi4mzlr17z6m.1t1rj0maa8vmt.dlg@40tude.net...
> On Thu, 24 Nov 2011 18:34:55 -0800 (PST), Rego, P. wrote:
...
>> 1) Why should I need to use Finalize (instead of direct T.Primary.Finish 
>> in Destruct)?
>
> Because Finalize is always called when the object is being finalized.

Which includes when the object goes away because of an exception being 
raised somewhere, a task being aborted, or some containing object being 
deallocated. Using Finalize makes your object far less fragile than trying 
to destroy it manually (and also allows it to be used anywhere Ada allows an 
object, rather than just as a stand-alone entity).

Claw provides a Destroy routine so that windows can be closed early, but 
there is never a requirement to call it.

                            Randy.





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

* Re: Class with task destructor
  2011-11-29  3:36           ` Randy Brukardt
@ 2011-11-29  9:31             ` Simon Wright
  2011-11-29 15:37             ` Adam Beneschan
  1 sibling, 0 replies; 50+ messages in thread
From: Simon Wright @ 2011-11-29  9:31 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> In any case, as I said, you can't sensibly call Unchecked_Deallocation
> until the task is known to have stopped (if it has discriminants).

From experience with GNAT I'd say that it's not sensible to do this
ever. The language explicitly makes it an error if there are
discriminants, but there are all sorts of other possibilities for things
to go wrong in the underlying RTS. In our case, it meant we leaked a
VxWorks TCB.



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

* Re: Class with task destructor
  2011-11-29  3:36           ` Randy Brukardt
  2011-11-29  9:31             ` Simon Wright
@ 2011-11-29 15:37             ` Adam Beneschan
  1 sibling, 0 replies; 50+ messages in thread
From: Adam Beneschan @ 2011-11-29 15:37 UTC (permalink / raw)


On Nov 28, 7:36 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
>
> >Except that in the OP's case, there *is* a connection: the task has an
> >access discriminant that will refer to the enclosing object, and if
> >the task keeps running, it could use that discriminant.
>
> 13.11.2(11-15) covers this. Essentially, either no deallocation is done or
> an exception is raised somewhere, sometime. I think Janus/Ada uses the third
> choice, but I'm not sure anymore.

Thank you for the reference.  I feel a bit silly that I quoted
something two paragraphs above this but missed this important section.

So, essentially, the OP's original attempt is prohibited by the
language.  That's useful information.

                       -- Adam



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

* Re: Class with task destructor
  2011-11-23  9:05   ` Simon Wright
  2011-11-23 10:41     ` Dmitry A. Kazakov
@ 2011-11-30  1:11     ` Rego, P.
  2011-11-30  2:21       ` Adam Beneschan
  2011-11-30  8:35       ` Simon Wright
  2011-11-30  1:47     ` Rego, P.
       [not found]     ` <15090042.1880.1322617401962.JavaMail.geo-discussion-forums@yqkn8>
  3 siblings, 2 replies; 50+ messages in thread
From: Rego, P. @ 2011-11-30  1:11 UTC (permalink / raw)


> You ought to wait until the task has terminated before freeing it.

How could I wait for the task termination?
Could be something like

   procedure Destruct (T : access Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
   begin
      T.Primary.Finish;
      DelayUntilTaskTermination (T_Ptr.Primary);
      Free (T_Ptr);
   end Destruct;

? But is there some package with something like it?



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

* Re: Class with task destructor
  2011-11-23  9:05   ` Simon Wright
  2011-11-23 10:41     ` Dmitry A. Kazakov
  2011-11-30  1:11     ` Rego, P.
@ 2011-11-30  1:47     ` Rego, P.
       [not found]     ` <15090042.1880.1322617401962.JavaMail.geo-discussion-forums@yqkn8>
  3 siblings, 0 replies; 50+ messages in thread
From: Rego, P. @ 2011-11-30  1:47 UTC (permalink / raw)


> You ought to wait until the task has terminated before freeing it. I
> can't trace it now, but I think that AdaCore recently fixed a feature
> where the TCB would be silently not deallocated if the task wasn't
> terminated. I had to fix this problem by handing off all tasks to be
> deallocated by a low-priority task, which required some interesting
> generic/codegen manipulation.

Maybe could I use
   procedure Destruct (T : access Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
   begin
      T.Primary.Finish;
   end Destruct;

   procedure Finalize (Object : in out Test_Class) is
      T_Ptr : Test_Class_Ptr := Test_Class_Ptr (Object.Primary.This);
   begin
      Free (T_Ptr);
   end Finalize;

but this leads to the message "cannot convert access discriminant to non-local access type". So how can I fix this approach?



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

* Re: Class with task destructor
  2011-11-30  1:11     ` Rego, P.
@ 2011-11-30  2:21       ` Adam Beneschan
  2011-11-30  8:41         ` Dmitry A. Kazakov
  2011-12-01  1:58         ` Rego, P.
  2011-11-30  8:35       ` Simon Wright
  1 sibling, 2 replies; 50+ messages in thread
From: Adam Beneschan @ 2011-11-30  2:21 UTC (permalink / raw)


On Nov 29, 5:11 pm, "Rego, P." <pvr...@gmail.com> wrote:
> > You ought to wait until the task has terminated before freeing it.
>
> How could I wait for the task termination?
> Could be something like
>
>    procedure Destruct (T : access Test_Class) is
>       T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
>    begin
>       T.Primary.Finish;
>       DelayUntilTaskTermination (T_Ptr.Primary);
>       Free (T_Ptr);
>    end Destruct;
>
> ? But is there some package with something like it?

Ada.Task_Termination (see C.7.3) may be able to help.  You could
define a protected object with a handler that sets a toggle and an
entry that waits on the toggle, use Set_Specific_Handler to cause the
handler to be executed when the task terminates, then call the
protected entry to wait for the toggle.  (Maybe someone's already
written a publicly available package that defines a
Delay_Until_Task_Termination routine that could be used on
T_Ptr.Primary'Identity, and with underscores in the name so it doesn't
look like a *&#@^#$ Windows API routine...  :)  I haven't tried this,
by the way.

The problem with waiting on the Finish entry of the task, as you
attempted to do in your next post, is that it may create a race
condition.  After the rendezvous is completed, there still may be some
delay between the time the task finishes the ACCEPT and the time it
actually terminates, and that still makes it possible that the caller
could try to free the task before it has actually terminated (which is
a bounded error according to the RM).  I don't know of a good way
around this (besides Ada.Task_Termination).  Maybe there are some
missing features in the language, such as (for instance) a TERMINATE
statement that can be used inside an ACCEPT statement that causes the
task to terminate, completes the rendezvous, and guarantees that when
the calling task is unblocked, the called task will be terminated.

                           -- Adam



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

* Re: Class with task destructor
  2011-11-30  1:11     ` Rego, P.
  2011-11-30  2:21       ` Adam Beneschan
@ 2011-11-30  8:35       ` Simon Wright
  2011-11-30 15:36         ` Adam Beneschan
  2011-12-01  1:59         ` Rego, P.
  1 sibling, 2 replies; 50+ messages in thread
From: Simon Wright @ 2011-11-30  8:35 UTC (permalink / raw)


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

>> You ought to wait until the task has terminated before freeing it.
>
> How could I wait for the task termination?
> Could be something like
>
>    procedure Destruct (T : access Test_Class) is
>       T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
>    begin
>       T.Primary.Finish;
>       DelayUntilTaskTermination (T_Ptr.Primary);
>       Free (T_Ptr);
>    end Destruct;
>
> ? But is there some package with something like it?

   while not T_Ptr.Primary'Terminated loop
      delay 0.001;
   end loop;



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

* Re: Class with task destructor
  2011-11-30  2:21       ` Adam Beneschan
@ 2011-11-30  8:41         ` Dmitry A. Kazakov
  2011-12-01  0:35           ` Randy Brukardt
  2011-12-01  1:58         ` Rego, P.
  1 sibling, 1 reply; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-11-30  8:41 UTC (permalink / raw)


On Tue, 29 Nov 2011 18:21:51 -0800 (PST), Adam Beneschan wrote:

> The problem with waiting on the Finish entry of the task, as you
> attempted to do in your next post, is that it may create a race
> condition.  After the rendezvous is completed, there still may be some
> delay between the time the task finishes the ACCEPT and the time it
> actually terminates, and that still makes it possible that the caller
> could try to free the task before it has actually terminated (which is
> a bounded error according to the RM).  I don't know of a good way
> around this (besides Ada.Task_Termination).

I am using polling for T'Terminated after the rendezvous.

However I have an impression that it should be safe to call
Unchecked_Deallocation in GNAT prematurely.

> Maybe there are some
> missing features in the language,

Not a feature, rather a plain language design bug. Unchecked_Deallocation
shall wait for the object's finalization. Finalization of a task evidently
includes its termination. So Unchecked_Deallocation must block until
termination before it frees anything.

> such as (for instance) a TERMINATE
> statement that can be used inside an ACCEPT statement that causes the
> task to terminate, completes the rendezvous, and guarantees that when
> the calling task is unblocked, the called task will be terminated.

As for missing features, rather than the Task_Termination hack, there
should be some way for the task to communicate to its master upon
completion, e.g. a rendezvous. A handler has a disadvantage of being a
protected procedure.

Furthermore, if the master does not accept such a notification from a
failed slave, the exceptional state should somehow propagate into the
master. I didn't think about the details, but the language design is unsafe
here.

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



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

* Re: Class with task destructor
       [not found]     ` <15090042.1880.1322617401962.JavaMail.geo-discussion-forums@yqkn8>
@ 2011-11-30  8:43       ` Dmitry A. Kazakov
  2011-12-01  1:53         ` Rego, P.
  0 siblings, 1 reply; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-11-30  8:43 UTC (permalink / raw)


On Tue, 29 Nov 2011 17:43:21 -0800 (PST), Rego, P. wrote:

> but this leads to the message "cannot convert access discriminant to non-local access type"

It is a bad idea to free access discriminant, so the message. It can be
circumvented, but you better make it a component.

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



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

* Re: Class with task destructor
  2011-11-30  8:35       ` Simon Wright
@ 2011-11-30 15:36         ` Adam Beneschan
  2011-11-30 16:32           ` Robert A Duff
  2011-12-01 10:51           ` Simon Wright
  2011-12-01  1:59         ` Rego, P.
  1 sibling, 2 replies; 50+ messages in thread
From: Adam Beneschan @ 2011-11-30 15:36 UTC (permalink / raw)


On Nov 30, 12:35 am, Simon Wright <si...@pushface.org> wrote:
> "Rego, P." <pvr...@gmail.com> writes:
> >> You ought to wait until the task has terminated before freeing it.
>
> > How could I wait for the task termination?
> > Could be something like
>
> >    procedure Destruct (T : access Test_Class) is
> >       T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
> >    begin
> >       T.Primary.Finish;
> >       DelayUntilTaskTermination (T_Ptr.Primary);
> >       Free (T_Ptr);
> >    end Destruct;
>
> > ? But is there some package with something like it?
>
>    while not T_Ptr.Primary'Terminated loop
>       delay 0.001;
>    end loop;

Is it just me, or are there others who think that resorting to code
like this is ... well, icky?

I mean, if we were waiting on some external device that didn't have a
mechanism for communicating back, we might have no choice other than
to poll.  But here we're waiting on a task that's part of the same
program, and written in the same language, and we have to resort to
polling to get things to work.  This seems to be a clear sign that
some synchronization feature is missing from the language---either
having Unchecked_Deallocation block until designated tasks terminate,
and/or some other synchronization mechanism.

                            -- Adam

                           -- Adam



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

* Re: Class with task destructor
  2011-11-30 15:36         ` Adam Beneschan
@ 2011-11-30 16:32           ` Robert A Duff
  2011-12-01  0:40             ` Randy Brukardt
  2011-12-01 10:51           ` Simon Wright
  1 sibling, 1 reply; 50+ messages in thread
From: Robert A Duff @ 2011-11-30 16:32 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> On Nov 30, 12:35�am, Simon Wright <si...@pushface.org> wrote:
>> "Rego, P." <pvr...@gmail.com> writes:
>> � �while not T_Ptr.Primary'Terminated loop
>> � � � delay 0.001;
>> � �end loop;
>
> Is it just me, or are there others who think that resorting to code
> like this is ... well, icky?

It's not just you.  ;-)

Ada should provide a way to wait for an arbitrary task, or a group of tasks,
to terminate.  Without polling.  It's quite tricky to implement, though.

Part of the problem with polling is that the delay is almost certainly
too long, or too short -- probably both!

I recently fixed an efficiency bug in a program that did something like
the above polling.  There were about 2000 tasks.  The program did its
job in a few seconds, and then at the end started waiting for all those
tasks to terminate, and that took HALF AN HOUR.

- Bob



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

* Re: Class with task destructor
  2011-11-30  8:41         ` Dmitry A. Kazakov
@ 2011-12-01  0:35           ` Randy Brukardt
  2011-12-01  6:28             ` J-P. Rosen
  2011-12-01  9:25             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 50+ messages in thread
From: Randy Brukardt @ 2011-12-01  0:35 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:ey516bovprzb$.1tjszfc528chj$.dlg@40tude.net...
> On Tue, 29 Nov 2011 18:21:51 -0800 (PST), Adam Beneschan wrote:
...
>> I don't know of a good way
>> around this (besides Ada.Task_Termination).
>
> I am using polling for T'Terminated after the rendezvous.

That's the Ada 83 solution, and there really isn't anything better in the 
language. Not sure if there even could be (I'm not a top-level expert on 
real-time issues, beyond what the Janus/Ada runtime does).

...
> Not a feature, rather a plain language design bug. Unchecked_Deallocation
> shall wait for the object's finalization. Finalization of a task evidently
> includes its termination. So Unchecked_Deallocation must block until
> termination before it frees anything.

The problem here is that finalization and task termination are different 
operations according to the language, and task termination generally has to 
be done first. This was done, I believe, so that any running task does not 
have to worry about having the objects it accesses finalized.

I usually agree that this is wrong, but actually it doesn't matter what 
choice is made -- any choice will be wrong a large part of the time. The 
current choice, for instance, makes it possible for finalize routines to 
access objects that have already been finalized (and allocate objects of 
access types that already have been finalized) - a finalize routine often 
needs to protect against this if it needs to access anything outside of the 
object being finalized.

We had a lot of trouble with this in Claw, particularly because we wanted to 
use a global finalizable object to tell the library tasks when to terminate. 
But that doesn't work in Ada, because tasks are awaited before any 
library-level finalization is done -- and thus the tasks never get their 
shutdown entries called. We eventually found a tricky way to use 
Ada.Task_Identification to determine when the main subprogram has exited, 
and used that to terminate the tasks. (And then we had to get all of the Ada 
95 compilers to implement it properly -- that took a couple of years and an 
ACATS test.)

Switching the order of task waiting and finalization would have worked in 
this case, but it wouldn't work in general as the library tasks would then 
be accessing global objects that have been finalized. Which seems worse than 
the original problem.

Point is that all of these things are interelated, and it isn't always 
possible to make all of them perfect. (Tucker Taft calls this "moving the 
bump under the carpet"; you can move it around to different locations, but 
you can't get rid of it without tearing out the carpet. That happens a lot 
more often in language design than most people think.)

                                           Randy.





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

* Re: Class with task destructor
  2011-11-30 16:32           ` Robert A Duff
@ 2011-12-01  0:40             ` Randy Brukardt
  2011-12-01  8:50               ` Yannick Duchêne (Hibou57)
  0 siblings, 1 reply; 50+ messages in thread
From: Randy Brukardt @ 2011-12-01  0:40 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message 
news:wcc39d5in9z.fsf@shell01.TheWorld.com...
> Adam Beneschan <adam@irvine.com> writes:
...
>> Is it just me, or are there others who think that resorting to code
>> like this is ... well, icky?
>
> It's not just you.  ;-)
>
> Ada should provide a way to wait for an arbitrary task, or a group of 
> tasks,
> to terminate.  Without polling.  It's quite tricky to implement, though.

Of course, when we tried to do that for subpools, AdaCore complained loudly, 
and we ended up taking that feature out of the subpool proposal.

The problem is that waiting on multiple events is not something that is 
easily done, and it is especially hard to insert into existing task 
supervisors (designed without needing to do that).

I thought (and still think) that some sort of sub-master would do the trick 
without too much disruption, but the feedback we got on that idea was not 
too positive.

Anyway, it would make sense to have a much more general feature rather than 
worrying about this problem only in the context of Unchecked_Deallocation 
and Unchecked_Deallocate_Subpool. But that will be even a harder sell, I 
fear.

                          Randy.





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

* Re: Class with task destructor
  2011-11-30  8:43       ` Dmitry A. Kazakov
@ 2011-12-01  1:53         ` Rego, P.
  2011-12-01  9:28           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 50+ messages in thread
From: Rego, P. @ 2011-12-01  1:53 UTC (permalink / raw)
  Cc: mailbox

> It is a bad idea to free access discriminant, so the message.
Got it.
 
>  It can be circumvented, but you better make it a component.
Simon and Adam suggestions fit pretty well what I need, but would be good to know this idea too. So how could I do (circumvent) it?



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

* Re: Class with task destructor
  2011-11-30  2:21       ` Adam Beneschan
  2011-11-30  8:41         ` Dmitry A. Kazakov
@ 2011-12-01  1:58         ` Rego, P.
  1 sibling, 0 replies; 50+ messages in thread
From: Rego, P. @ 2011-12-01  1:58 UTC (permalink / raw)


> Ada.Task_Termination (see C.7.3) may be able to help.  You could
> define a protected object with a handler that sets a toggle and an
> entry that waits on the toggle, use Set_Specific_Handler to cause the
> handler to be executed when the task terminates, then call the
> protected entry to wait for the toggle.  (Maybe someone's already
> written a publicly available package that defines a
> Delay_Until_Task_Termination routine that could be used on
> T_Ptr.Primary'Identity, 
Ok. Great! Thanks.

> and with underscores in the name so it doesn't look like a *&#@^#$ Windows API routine...  :)
ok :)



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

* Re: Class with task destructor
  2011-11-30  8:35       ` Simon Wright
  2011-11-30 15:36         ` Adam Beneschan
@ 2011-12-01  1:59         ` Rego, P.
  1 sibling, 0 replies; 50+ messages in thread
From: Rego, P. @ 2011-12-01  1:59 UTC (permalink / raw)


>    while not T_Ptr.Primary'Terminated loop
>       delay 0.001;
>    end loop;

Great! Quite simple :) 



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

* Re: Class with task destructor
  2011-12-01  0:35           ` Randy Brukardt
@ 2011-12-01  6:28             ` J-P. Rosen
  2011-12-01 10:55               ` Simon Wright
  2011-12-01 21:48               ` Robert A Duff
  2011-12-01  9:25             ` Dmitry A. Kazakov
  1 sibling, 2 replies; 50+ messages in thread
From: J-P. Rosen @ 2011-12-01  6:28 UTC (permalink / raw)


Le 01/12/2011 01:35, Randy Brukardt a �crit :
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
>> I am using polling for T'Terminated after the rendezvous.
> 
> That's the Ada 83 solution, and there really isn't anything better in the 
> language. Not sure if there even could be (I'm not a top-level expert on 
> real-time issues, beyond what the Janus/Ada runtime does).
> 
There is a simple solution that I suggested a couple of days ago, but it
seems it didn't to make it to the NG. Sorry if you see it twice...

Put an entry (say "Termination_Wait") in the waited task, and never
accept it. Call Termination_Wait from the waiting task. When the waiting
task receives Tasking_Error, the waited task is terminated (well,
completed, but that should be close enough).

Benefit: works in all circumstances, even if the waited task is aborted
or terminates due to exception. No race condition.
Drawback: requires cooperation from the waited task (extra entry),
therefore not applicable to tasks that you didn't write yourself.

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Adalog a d�m�nag� / Adalog has moved:
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00



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

* Re: Class with task destructor
  2011-12-01  0:40             ` Randy Brukardt
@ 2011-12-01  8:50               ` Yannick Duchêne (Hibou57)
  2011-12-02  0:50                 ` Randy Brukardt
  0 siblings, 1 reply; 50+ messages in thread
From: Yannick Duchêne (Hibou57) @ 2011-12-01  8:50 UTC (permalink / raw)


Le Thu, 01 Dec 2011 01:40:09 +0100, Randy Brukardt <randy@rrsoftware.com>  
a écrit:
> The problem is that waiting on multiple events is not something that is
> easily done
As Janus Ada is a Windows Ada compiler, I guess you know Windows has some  
way to wait for multiple events and it works rather fine. What is  
different here ?

-- 
“Syntactic sugar causes cancer of the semi-colons.” [1]
“Structured Programming supports the law of the excluded muddle.” [1]
[1]: [Epigrams on Programming — Alan J. — P. Yale University]



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

* Re: Class with task destructor
  2011-12-01  0:35           ` Randy Brukardt
  2011-12-01  6:28             ` J-P. Rosen
@ 2011-12-01  9:25             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-12-01  9:25 UTC (permalink / raw)


On Wed, 30 Nov 2011 18:35:13 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:ey516bovprzb$.1tjszfc528chj$.dlg@40tude.net...
> ...
>> Not a feature, rather a plain language design bug. Unchecked_Deallocation
>> shall wait for the object's finalization. Finalization of a task evidently
>> includes its termination. So Unchecked_Deallocation must block until
>> termination before it frees anything.
> 
> The problem here is that finalization and task termination are different 
> operations according to the language, and task termination generally has to 
> be done first. This was done, I believe, so that any running task does not 
> have to worry about having the objects it accesses finalized.

The problem is that task as an object must be destroyed in exactly this
order:

1. terminated
2. finalized (destructed)
3. deallocated

What you meant is how finalization of an object having task as a component
is composed, i.e. at which stages of the enclosing object destruction and
deallocation the positions 1, 2, 3 occur. That is a different issue, but
under any circumstances the order 1,2,3 may not change.

Unchecked_Deallocation violates this order => must be fixed independently
on anything else.

> Switching the order of task waiting and finalization would have worked in 
> this case, but it wouldn't work in general as the library tasks would then 
> be accessing global objects that have been finalized. Which seems worse than 
> the original problem.

If you mean finalization of the enclosing object, then yes. I can only
reiterate that Ada should have proper constructors and destructors.

> Point is that all of these things are interelated, and it isn't always 
> possible to make all of them perfect. (Tucker Taft calls this "moving the 
> bump under the carpet"; you can move it around to different locations, but 
> you can't get rid of it without tearing out the carpet. That happens a lot 
> more often in language design than most people think.)

1. The construction/destruction model must be sanitized.

2. The Rosen's must be restricted. It is inconsistent for a component to
refer to an enclosing object upon construction/destruction.

There are two alternatives: either to forbid such access discriminants
altogether, or else make them inaccessible on the contexts of the
constructor/destructor. [Initialize/Finalize are not proper
constructor/destructor anyway, so they could be left as obsolete]

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



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

* Re: Class with task destructor
  2011-12-01  1:53         ` Rego, P.
@ 2011-12-01  9:28           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-12-01  9:28 UTC (permalink / raw)


On Wed, 30 Nov 2011 17:53:33 -0800 (PST), Rego, P. wrote:

>> It is a bad idea to free access discriminant, so the message.
> Got it.
>  
>>  It can be circumvented, but you better make it a component.
> Simon and Adam suggestions fit pretty well what I need, but would be good to know this idea too. So how could I do (circumvent) it?

.all'Unchecked_Access [+ access conversion]
.all'Address + Address_To_Access

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



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

* Re: Class with task destructor
  2011-11-30 15:36         ` Adam Beneschan
  2011-11-30 16:32           ` Robert A Duff
@ 2011-12-01 10:51           ` Simon Wright
  2011-12-01 22:59             ` Simon Wright
  1 sibling, 1 reply; 50+ messages in thread
From: Simon Wright @ 2011-12-01 10:51 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> On Nov 30, 12:35 am, Simon Wright <si...@pushface.org> wrote:
>> "Rego, P." <pvr...@gmail.com> writes:
>> >> You ought to wait until the task has terminated before freeing it.
>>
>> > How could I wait for the task termination?
>> > Could be something like
>>
>> >    procedure Destruct (T : access Test_Class) is
>> >       T_Ptr : Test_Class_Ptr := Test_Class_Ptr (T);
>> >    begin
>> >       T.Primary.Finish;
>> >       DelayUntilTaskTermination (T_Ptr.Primary);
>> >       Free (T_Ptr);
>> >    end Destruct;
>>
>> > ? But is there some package with something like it?
>>
>>    while not T_Ptr.Primary'Terminated loop
>>       delay 0.001;
>>    end loop;
>
> Is it just me, or are there others who think that resorting to code
> like this is ... well, icky?

This was an answer to the specific question.

In the context where I used this scheme, it would have been completely
inappropriate to have an unbounded loop like this in the main context;
so the actual delay and Unchecked_Deallocation was handed over to a
low-priority housekeeping task. To do this required cooperation from the
code generator; altogether too complex to go into here! (and I'm by no
means sure that the design is the best possible).

I think I'd be concerned if an implementation arranged to do this sort
of thing 'under the hood'. How would it know what would be an
appropriate 'lower priority', for example?

I'm not sure that the code above is actually icky. You might think that
the aspects of the language that force you to do this are icky; but I
think it's quite reasonable. I'd be even happier if a program that tried
to deallocate an unterminated task was *required* to receive
Tasking_Error or Program_Error; that way we'd have to do something about
it.



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

* Re: Class with task destructor
  2011-12-01  6:28             ` J-P. Rosen
@ 2011-12-01 10:55               ` Simon Wright
  2011-12-01 21:48               ` Robert A Duff
  1 sibling, 0 replies; 50+ messages in thread
From: Simon Wright @ 2011-12-01 10:55 UTC (permalink / raw)


"J-P. Rosen" <rosen@adalog.fr> writes:

> When the waiting task receives Tasking_Error, the waited task is
> terminated (well, completed, but that should be close enough).

I think whether it's 'close enough' is going to depend on the fine
detail of the interaction between the Ada RTS and the underlying OS.



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

* Re: Class with task destructor
  2011-12-01  6:28             ` J-P. Rosen
  2011-12-01 10:55               ` Simon Wright
@ 2011-12-01 21:48               ` Robert A Duff
  2011-12-01 22:44                 ` Adam Beneschan
                                   ` (2 more replies)
  1 sibling, 3 replies; 50+ messages in thread
From: Robert A Duff @ 2011-12-01 21:48 UTC (permalink / raw)


"J-P. Rosen" <rosen@adalog.fr> writes:

> Put an entry (say "Termination_Wait") in the waited task, and never
> accept it. Call Termination_Wait from the waiting task. When the waiting
> task receives Tasking_Error, the waited task is terminated (well,
> completed, but that should be close enough).

I don't think it's close enough.  It is impossible to actually
free things before the task is really terminated.  The task is
doing finalization between completion and termination, and that
could refer to discriminants.  And even if there's no finalization
present, the task is still using its stack, which had better not
be freed.

So there's still a race condition.

Luckily, in the latest version of GNAT, if you call U_D on an
object containing tasks, it will get freed.  If the task happens
to be already terminated, it will get freed immediately.  Otherwise,
it will get freed when the task does terminate.  But this is not
required by the RM.

- Bob



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

* Re: Class with task destructor
  2011-12-01 21:48               ` Robert A Duff
@ 2011-12-01 22:44                 ` Adam Beneschan
  2011-12-02  0:57                 ` Randy Brukardt
  2011-12-02  5:57                 ` J-P. Rosen
  2 siblings, 0 replies; 50+ messages in thread
From: Adam Beneschan @ 2011-12-01 22:44 UTC (permalink / raw)


On Dec 1, 1:48 pm, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:
> "J-P. Rosen" <ro...@adalog.fr> writes:
> > Put an entry (say "Termination_Wait") in the waited task, and never
> > accept it. Call Termination_Wait from the waiting task. When the waiting
> > task receives Tasking_Error, the waited task is terminated (well,
> > completed, but that should be close enough).
>
> I don't think it's close enough.  It is impossible to actually
> free things before the task is really terminated.  The task is
> doing finalization between completion and termination, and that
> could refer to discriminants.  And even if there's no finalization
> present, the task is still using its stack, which had better not
> be freed.

And part of that finalization (the "first step" according to the RM)
is to wait for dependent tasks.  If the waited task has nested tasks,
those tasks could still be running for an indefinitely long period
after the waited task completes.  And those tasks could refer to the
parent task's local variables or discriminants.

                            -- Adam



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

* Re: Class with task destructor
  2011-12-01 10:51           ` Simon Wright
@ 2011-12-01 22:59             ` Simon Wright
  0 siblings, 0 replies; 50+ messages in thread
From: Simon Wright @ 2011-12-01 22:59 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> I think I'd be concerned if an implementation arranged to do this sort
> of thing 'under the hood'. How would it know what would be an
> appropriate 'lower priority', for example?

AdaCore's new solution, as described by Bob Duff, seems to do away with
this concern, because any hanging about is going to be done by the task
we're trying to dispose of.



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

* Re: Class with task destructor
  2011-12-01  8:50               ` Yannick Duchêne (Hibou57)
@ 2011-12-02  0:50                 ` Randy Brukardt
  2011-12-02  5:30                   ` Jeffrey Carter
  0 siblings, 1 reply; 50+ messages in thread
From: Randy Brukardt @ 2011-12-02  0:50 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1584 bytes --]

"Yannick Duch�ne (Hibou57)" <yannick_duchene@yahoo.fr> wrote in message 
news:op.v5syuzm9ule2fv@douda-yannick...
Le Thu, 01 Dec 2011 01:40:09 +0100, Randy Brukardt <randy@rrsoftware.com>
a �crit:
>> The problem is that waiting on multiple events is not something that is
>> easily done
>As Janus Ada is a Windows Ada compiler, I guess you know Windows has some 
>way to wait for multiple events and it works rather fine. What is 
>different here ?

Janus/Ada's task supervisor predates Windows and doesn't (to date) use any 
Windows facilities at all. So what Windows can or cannot do isn't terribly 
relevant. [Humm, that's not 100% true, it does use Sleep and the clock 
routines. But that't it, and Sleep was the only thing added specifically for 
Windows.]

In any case, what a particular target can do is not that relevant to what 
the language design can do. Ada 95 tried to add a multi-way entry call, and 
every implementer who studied it ended up reporting that the implementation 
would essentially end up being some form of polling. Which is not what 
anyone was hoping for. It got dropped from Ada 95.

Clearly, a termination feature can always be implemented by polling, but we 
don't need any feature like that -- you can write that yourself. We have to 
have a feature that actually can be implemented by waiting, and that is not 
as easy as it seems on the surface. (I'm not going to comment on the 
problems that AdaCore found; someone there will have to explain those if 
they want.)

                                                               Randy.








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

* Re: Class with task destructor
  2011-12-01 21:48               ` Robert A Duff
  2011-12-01 22:44                 ` Adam Beneschan
@ 2011-12-02  0:57                 ` Randy Brukardt
  2011-12-02  5:57                 ` J-P. Rosen
  2 siblings, 0 replies; 50+ messages in thread
From: Randy Brukardt @ 2011-12-02  0:57 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message 
news:wccliqwdku1.fsf@shell01.TheWorld.com...
> "J-P. Rosen" <rosen@adalog.fr> writes:
>
>> Put an entry (say "Termination_Wait") in the waited task, and never
>> accept it. Call Termination_Wait from the waiting task. When the waiting
>> task receives Tasking_Error, the waited task is terminated (well,
>> completed, but that should be close enough).
>
> I don't think it's close enough.  It is impossible to actually
> free things before the task is really terminated.  The task is
> doing finalization between completion and termination, and that
> could refer to discriminants.  And even if there's no finalization
> present, the task is still using its stack, which had better not
> be freed.

I agree, but I note that J-P's suggestion at least provides a way to delay 
polling until the task is completed. Most tasks don't have complex 
finalization, so they don't have to stay for a long time in the completed 
state. (Although I'd have to go look up the exact details as to when a 
completed task becomes terminated.

I'll note that I became aware of this need to poll for 'Terminated because 
of various bug reports on ACATS tests involving tasks. Several of them had 
to be fixed by adding such polling before checking the results of the test. 
(And a lot of them already had such polling.) It's hard to avoid in Ada as 
it stands.

                                      Randy.






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

* Re: Class with task destructor
  2011-12-02  0:50                 ` Randy Brukardt
@ 2011-12-02  5:30                   ` Jeffrey Carter
  2011-12-02 16:20                     ` Adam Beneschan
  0 siblings, 1 reply; 50+ messages in thread
From: Jeffrey Carter @ 2011-12-02  5:30 UTC (permalink / raw)


On 12/01/2011 05:50 PM, Randy Brukardt wrote:
>
> In any case, what a particular target can do is not that relevant to what
> the language design can do. Ada 95 tried to add a multi-way entry call, and
> every implementer who studied it ended up reporting that the implementation
> would essentially end up being some form of polling. Which is not what
> anyone was hoping for. It got dropped from Ada 95.

Ada 95 did add asynchronous transfer of control, which does allow an entry call 
as a trigger, and anything in the "then abort" part, including an entry call:

select
    Entry_Call_1;
then abort
    Entry_Call_2;
end select;

These can be nested as deeply as desired, so it seems that Ada 95 did 
effectively add a multi-way entry call.

-- 
Jeff Carter
"I wave my private parts at your aunties."
Monty Python & the Holy Grail
13



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

* Re: Class with task destructor
  2011-12-01 21:48               ` Robert A Duff
  2011-12-01 22:44                 ` Adam Beneschan
  2011-12-02  0:57                 ` Randy Brukardt
@ 2011-12-02  5:57                 ` J-P. Rosen
  2011-12-02 15:07                   ` Robert A Duff
  2011-12-02 18:41                   ` Jeffrey Carter
  2 siblings, 2 replies; 50+ messages in thread
From: J-P. Rosen @ 2011-12-02  5:57 UTC (permalink / raw)


Le 01/12/2011 22:48, Robert A Duff a �crit :
> "J-P. Rosen" <rosen@adalog.fr> writes:
> 
>> Put an entry (say "Termination_Wait") in the waited task, and never
>> accept it. Call Termination_Wait from the waiting task. When the waiting
>> task receives Tasking_Error, the waited task is terminated (well,
>> completed, but that should be close enough).
For the special case of the OP (freeing the task's space), you are
right, but this trick is quite useful in the general case. Even in the
OP case, you can add a busy loop once the task is completed; this one is
likely to be executed at most once (on an uni-processor, there is less
concern about busy loops on multi-processors).

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Adalog a d�m�nag� / Adalog has moved:
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00



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

* Re: Class with task destructor
  2011-12-02  5:57                 ` J-P. Rosen
@ 2011-12-02 15:07                   ` Robert A Duff
  2011-12-02 18:41                   ` Jeffrey Carter
  1 sibling, 0 replies; 50+ messages in thread
From: Robert A Duff @ 2011-12-02 15:07 UTC (permalink / raw)


"J-P. Rosen" <rosen@adalog.fr> writes:

> Le 01/12/2011 22:48, Robert A Duff a �crit :
>> "J-P. Rosen" <rosen@adalog.fr> writes:
>> 
>>> Put an entry (say "Termination_Wait") in the waited task, and never
>>> accept it. Call Termination_Wait from the waiting task. When the waiting
>>> task receives Tasking_Error, the waited task is terminated (well,
>>> completed, but that should be close enough).
> For the special case of the OP (freeing the task's space), you are
> right, but this trick is quite useful in the general case.

Yes, it is useful to know that the task is completed.

>...Even in the
> OP case, you can add a busy loop once the task is completed; this one is
> likely to be executed at most once (on an uni-processor, there is less
> concern about busy loops on multi-processors).

True.  But it's frustrating that the "delay" is likely to be both
too short, and too long, if you know what I mean.

- Bob



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

* Re: Class with task destructor
  2011-12-02  5:30                   ` Jeffrey Carter
@ 2011-12-02 16:20                     ` Adam Beneschan
  2011-12-02 18:01                       ` Dmitry A. Kazakov
  2011-12-02 18:50                       ` Jeffrey Carter
  0 siblings, 2 replies; 50+ messages in thread
From: Adam Beneschan @ 2011-12-02 16:20 UTC (permalink / raw)


On Dec 1, 9:30 pm, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org>
wrote:
> On 12/01/2011 05:50 PM, Randy Brukardt wrote:
>
>
>
> > In any case, what a particular target can do is not that relevant to what
> > the language design can do. Ada 95 tried to add a multi-way entry call, and
> > every implementer who studied it ended up reporting that the implementation
> > would essentially end up being some form of polling. Which is not what
> > anyone was hoping for. It got dropped from Ada 95.
>
> Ada 95 did add asynchronous transfer of control, which does allow an entry call
> as a trigger, and anything in the "then abort" part, including an entry call:
>
> select
>     Entry_Call_1;
> then abort
>     Entry_Call_2;
> end select;
>
> These can be nested as deeply as desired, so it seems that Ada 95 did
> effectively add a multi-way entry call.

It's not entirely the same, though.  In a multi-way entry, if entry
Entry_Call_2 becomes available first, then that entry is accepted and
Entry_Call_1 can no longer be accepted.  In the code you've written
above, if Entry_Call_2 is accepted first, but Entry_Call_1 becomes
available before the Entry_Call_2 entry is completed, I believe that
Entry_Call_1 is accepted and an attempt is made to cancel the call to
Entry_Call_2--which probably doesn't succeed unless a requeue is
involved, so that the Entry_Call_2 rendezvous still completes, but the
Entry_Call_1 rendezvous also takes place.  I'm not 100% sure I have
the semantics right, but I'm pretty sure the behavior would be
different from a true multi-way entry.  Also, I have no problem
believing that since the behavior of a multi-way entry would be
different, the implementation could well be very different from the
implementation necessary to implement asynchronous transfer of
control.

                         -- Adam



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

* Re: Class with task destructor
  2011-12-02 16:20                     ` Adam Beneschan
@ 2011-12-02 18:01                       ` Dmitry A. Kazakov
  2011-12-02 18:50                       ` Jeffrey Carter
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry A. Kazakov @ 2011-12-02 18:01 UTC (permalink / raw)


On Fri, 2 Dec 2011 08:20:43 -0800 (PST), Adam Beneschan wrote:

> On Dec 1, 9:30�pm, Jeffrey Carter <spam.jrcarter....@spam.not.acm.org>
> wrote:
>> On 12/01/2011 05:50 PM, Randy Brukardt wrote:
>>
>>> In any case, what a particular target can do is not that relevant to what
>>> the language design can do. Ada 95 tried to add a multi-way entry call, and
>>> every implementer who studied it ended up reporting that the implementation
>>> would essentially end up being some form of polling. Which is not what
>>> anyone was hoping for. It got dropped from Ada 95.
>>
>> Ada 95 did add asynchronous transfer of control, which does allow an entry call
>> as a trigger, and anything in the "then abort" part, including an entry call:
>>
>> select
>> � � Entry_Call_1;
>> then abort
>> � � Entry_Call_2;
>> end select;
>>
>> These can be nested as deeply as desired, so it seems that Ada 95 did
>> effectively add a multi-way entry call.
> 
> It's not entirely the same, though.  In a multi-way entry, if entry
> Entry_Call_2 becomes available first, then that entry is accepted and
> Entry_Call_1 can no longer be accepted.
> above, if Entry_Call_2 is accepted first, but Entry_Call_1 becomes
> available before the Entry_Call_2 entry is completed, I believe that
> Entry_Call_1 is accepted and an attempt is made to cancel the call to
> Entry_Call_2--which probably doesn't succeed unless a requeue is
> involved, so that the Entry_Call_2 rendezvous still completes, but the
> Entry_Call_1 rendezvous also takes place.  I'm not 100% sure I have
> the semantics right, but I'm pretty sure the behavior would be
> different from a true multi-way entry.

I am uncomfortable with the semantics that allows aborting a rendezvous. It
is also unclear what happens when Entry_Call_1 re-queues without about. I
guess that should not be abortable. 

That was the "ANY" entry call. There also exists "ALL" entries call. That
is when the task engages a rendezvous with multiple tasks and/or executes
protected actions on multiple objects. E.g.

1. it awaits entries of all specified tasks and/or barriers of the
protected objects' entries;

2. the tasks are blocked and/or protected actions are started;

3. entries are executed in an unspecified order;

4. tasks are released and/or protected actions are completed.

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



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

* Re: Class with task destructor
  2011-12-02  5:57                 ` J-P. Rosen
  2011-12-02 15:07                   ` Robert A Duff
@ 2011-12-02 18:41                   ` Jeffrey Carter
  1 sibling, 0 replies; 50+ messages in thread
From: Jeffrey Carter @ 2011-12-02 18:41 UTC (permalink / raw)


On 12/01/2011 10:57 PM, J-P. Rosen wrote:
>>
> For the special case of the OP (freeing the task's space), you are
> right, but this trick is quite useful in the general case.

Another Rosen trick! How many will there be?

-- 
Jeff Carter
"Hello! Smelly English K...niggets."
Monty Python & the Holy Grail
08



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

* Re: Class with task destructor
  2011-12-02 16:20                     ` Adam Beneschan
  2011-12-02 18:01                       ` Dmitry A. Kazakov
@ 2011-12-02 18:50                       ` Jeffrey Carter
  2011-12-02 19:03                         ` Adam Beneschan
  1 sibling, 1 reply; 50+ messages in thread
From: Jeffrey Carter @ 2011-12-02 18:50 UTC (permalink / raw)


On 12/02/2011 09:20 AM, Adam Beneschan wrote:
>
> It's not entirely the same, though.  In a multi-way entry, if entry
> Entry_Call_2 becomes available first, then that entry is accepted and
> Entry_Call_1 can no longer be accepted.  In the code you've written
> above, if Entry_Call_2 is accepted first, but Entry_Call_1 becomes
> available before the Entry_Call_2 entry is completed, I believe that
> Entry_Call_1 is accepted and an attempt is made to cancel the call to
> Entry_Call_2--which probably doesn't succeed unless a requeue is
> involved, so that the Entry_Call_2 rendezvous still completes, but the
> Entry_Call_1 rendezvous also takes place.  I'm not 100% sure I have
> the semantics right, but I'm pretty sure the behavior would be
> different from a true multi-way entry.  Also, I have no problem
> believing that since the behavior of a multi-way entry would be
> different, the implementation could well be very different from the
> implementation necessary to implement asynchronous transfer of
> control.

I didn't recall the specifics of the Ada-95 proposal, nor am I entirely clear on 
the semantics of ATC. Will the "then abort" part be aborted when the trigger 
entry is accepted, or when it completes? I had thought it was the latter, but if 
you say otherwise then I'm probably wrong.

Anyway, the ATC multiple entry call semantics might be useful in some cases.

-- 
Jeff Carter
"Hello! Smelly English K...niggets."
Monty Python & the Holy Grail
08



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

* Re: Class with task destructor
  2011-12-02 18:50                       ` Jeffrey Carter
@ 2011-12-02 19:03                         ` Adam Beneschan
  0 siblings, 0 replies; 50+ messages in thread
From: Adam Beneschan @ 2011-12-02 19:03 UTC (permalink / raw)


On Dec 2, 10:50 am, Jeffrey Carter
<spam.jrcarter....@spam.not.acm.org> wrote:
> On 12/02/2011 09:20 AM, Adam Beneschan wrote:
>
>
>
>
>
>
>
> > It's not entirely the same, though.  In a multi-way entry, if entry
> > Entry_Call_2 becomes available first, then that entry is accepted and
> > Entry_Call_1 can no longer be accepted.  In the code you've written
> > above, if Entry_Call_2 is accepted first, but Entry_Call_1 becomes
> > available before the Entry_Call_2 entry is completed, I believe that
> > Entry_Call_1 is accepted and an attempt is made to cancel the call to
> > Entry_Call_2--which probably doesn't succeed unless a requeue is
> > involved, so that the Entry_Call_2 rendezvous still completes, but the
> > Entry_Call_1 rendezvous also takes place.  I'm not 100% sure I have
> > the semantics right, but I'm pretty sure the behavior would be
> > different from a true multi-way entry.  Also, I have no problem
> > believing that since the behavior of a multi-way entry would be
> > different, the implementation could well be very different from the
> > implementation necessary to implement asynchronous transfer of
> > control.
>
> I didn't recall the specifics of the Ada-95 proposal, nor am I entirely clear on
> the semantics of ATC. Will the "then abort" part be aborted when the trigger
> entry is accepted, or when it completes? I had thought it was the latter, but if
> you say otherwise then I'm probably wrong.

When it completes--I just checked.  That doesn't change the fact that
both entry calls could complete, which is probably not what you'd
expect from a multi-way entry.  But it may be more symmetrical than I
thought when I first posted.  If either entry call is accepted and
*completes*, the other one is cancelled, which succeeds if the other
entry call hasn't yet been accepted (or has been requeued with abort).

                       -- Adam



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

end of thread, other threads:[~2011-12-02 20:01 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-23  1:50 Class with task destructor Rego, P.
2011-11-23  2:44 ` Adam Beneschan
2011-11-23  5:04   ` Yannick Duchêne (Hibou57)
2011-11-23  6:14     ` Adam Beneschan
2011-11-24  0:15       ` Randy Brukardt
2011-11-24  2:48         ` Adam Beneschan
2011-11-29  3:36           ` Randy Brukardt
2011-11-29  9:31             ` Simon Wright
2011-11-29 15:37             ` Adam Beneschan
2011-11-23  8:35 ` Dmitry A. Kazakov
2011-11-23  9:05   ` Simon Wright
2011-11-23 10:41     ` Dmitry A. Kazakov
2011-11-30  1:11     ` Rego, P.
2011-11-30  2:21       ` Adam Beneschan
2011-11-30  8:41         ` Dmitry A. Kazakov
2011-12-01  0:35           ` Randy Brukardt
2011-12-01  6:28             ` J-P. Rosen
2011-12-01 10:55               ` Simon Wright
2011-12-01 21:48               ` Robert A Duff
2011-12-01 22:44                 ` Adam Beneschan
2011-12-02  0:57                 ` Randy Brukardt
2011-12-02  5:57                 ` J-P. Rosen
2011-12-02 15:07                   ` Robert A Duff
2011-12-02 18:41                   ` Jeffrey Carter
2011-12-01  9:25             ` Dmitry A. Kazakov
2011-12-01  1:58         ` Rego, P.
2011-11-30  8:35       ` Simon Wright
2011-11-30 15:36         ` Adam Beneschan
2011-11-30 16:32           ` Robert A Duff
2011-12-01  0:40             ` Randy Brukardt
2011-12-01  8:50               ` Yannick Duchêne (Hibou57)
2011-12-02  0:50                 ` Randy Brukardt
2011-12-02  5:30                   ` Jeffrey Carter
2011-12-02 16:20                     ` Adam Beneschan
2011-12-02 18:01                       ` Dmitry A. Kazakov
2011-12-02 18:50                       ` Jeffrey Carter
2011-12-02 19:03                         ` Adam Beneschan
2011-12-01 10:51           ` Simon Wright
2011-12-01 22:59             ` Simon Wright
2011-12-01  1:59         ` Rego, P.
2011-11-30  1:47     ` Rego, P.
     [not found]     ` <15090042.1880.1322617401962.JavaMail.geo-discussion-forums@yqkn8>
2011-11-30  8:43       ` Dmitry A. Kazakov
2011-12-01  1:53         ` Rego, P.
2011-12-01  9:28           ` Dmitry A. Kazakov
2011-11-25  2:44   ` Rego, P.
     [not found]   ` <28489797.1088.1322188495508.JavaMail.geo-discussion-forums@yqf20>
2011-11-25  9:19     ` Dmitry A. Kazakov
2011-11-29  3:40       ` Randy Brukardt
2011-11-23 10:26 ` Brian Drummond
2011-11-25  1:37   ` Rego, P.
2011-11-25 13:40     ` Brian Drummond

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