comp.lang.ada
 help / color / mirror / Atom feed
* Finalization of library level tasks
@ 2018-04-15 13:40 Dmitry A. Kazakov
  2018-04-15 14:02 ` Jeffrey R. Carter
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-15 13:40 UTC (permalink / raw)


I vaguely remember a discussion regarding this issue but cannot find it. 
The question is finalization of a task declared at the library level:

    task type Worker_Type is
       entry Quit;
    end Worker_Type;
    type Worker_Type_Ptr is access  Worker_Type;

    type T is new Ada.Finalization.Limited_Controlled with record
       Worker : Worker_Type_Ptr;
    end record;

    procedure Finalize (X : in out T) is
    begin
       X.Worker.Quit;
    end Finalize;

When an instance of T is declared in a library level package, then 
Finalize is never called, I guess because the task must terminate first 
due to some rules about its masters.

Is there a way to work this around?

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


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

* Re: Finalization of library level tasks
  2018-04-15 13:40 Finalization of library level tasks Dmitry A. Kazakov
@ 2018-04-15 14:02 ` Jeffrey R. Carter
  2018-04-15 14:12   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-04-15 14:02 UTC (permalink / raw)


On 04/15/2018 03:40 PM, Dmitry A. Kazakov wrote:
> 
> When an instance of T is declared in a library level package, then Finalize is 
> never called, I guess because the task must terminate first due to some rules 
> about its masters.

The rule is that finalization occurs after all dependent tasks have terminated, 
presumably so a task cannot access a finalized object.

> Is there a way to work this around?

That depends on the problem, but usually a design can be reworked to provide for 
termination of tasks.

-- 
Jeff Carter
"Well, a gala day is enough for me. I don't think
I can handle any more."
Duck Soup
93


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

* Re: Finalization of library level tasks
  2018-04-15 14:02 ` Jeffrey R. Carter
@ 2018-04-15 14:12   ` Dmitry A. Kazakov
  2018-04-15 14:54     ` Jeffrey R. Carter
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-15 14:12 UTC (permalink / raw)


On 2018-04-15 16:02, Jeffrey R. Carter wrote:
> On 04/15/2018 03:40 PM, Dmitry A. Kazakov wrote:
>>
>> When an instance of T is declared in a library level package, then 
>> Finalize is never called, I guess because the task must terminate 
>> first due to some rules about its masters.
> 
> The rule is that finalization occurs after all dependent tasks have 
> terminated, presumably so a task cannot access a finalized object.

There is only environment task.

>> Is there a way to work this around?
> 
> That depends on the problem, but usually a design can be reworked to 
> provide for termination of tasks.

The problem is that Finalize is called when the object is declared in a 
nested scope:

   procedure Main is
      Data : X;
   begin
      Data.Worker := new Worker_Type;
   end Main; -- Finalize is called (and terminates the task)

This does not work:

   package Library_Level is
      Data : X;
   end Library_Level;

   with Library_Level;
   procedure Main is
   begin
      Library_Level.Data.Worker := new Worker_Type;
   end Main; -- Finalize is not called (presumably waiting for the task)

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


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

* Re: Finalization of library level tasks
  2018-04-15 14:12   ` Dmitry A. Kazakov
@ 2018-04-15 14:54     ` Jeffrey R. Carter
  2018-04-15 15:15       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-04-15 14:54 UTC (permalink / raw)


On 04/15/2018 04:12 PM, Dmitry A. Kazakov wrote:
> 
> The problem is that Finalize is called when the object is declared in a nested 
> scope:
> 
>    procedure Main is
>       Data : X;
>    begin
>       Data.Worker := new Worker_Type;
>    end Main; -- Finalize is called (and terminates the task)
> 
> This does not work:
> 
>    package Library_Level is
>       Data : X;
>    end Library_Level;
> 
>    with Library_Level;
>    procedure Main is
>    begin
>       Library_Level.Data.Worker := new Worker_Type;
>    end Main; -- Finalize is not called (presumably waiting for the task)

A task declared by an allocator (usually) depends on the thing that the access 
type is declared in; here, that's a library-level pkg.

An object declaration such as Data goes out of scope when the thing that it's 
declared in goes away. In a procedure, the procedure can end and Data can be 
finalized, even though Data.Worker.all is still running. You might, for example, 
copy Data.Worker to another variable of the access type that will exist after 
the procedure call ends. Or you may want the task to exist and run with no way 
to refer to it; tasks in worker pools often work this way.

When Data is declared in a library-level pkg, it's finalized when the pkg goes 
out of scope, which doesn't happen until all library-level tasks have 
terminated. Since Data.Worker has a library-level access type, Data.Worker.all 
is a library-level task.

-- 
Jeff Carter
"Well, a gala day is enough for me. I don't think
I can handle any more."
Duck Soup
93

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

* Re: Finalization of library level tasks
  2018-04-15 14:54     ` Jeffrey R. Carter
@ 2018-04-15 15:15       ` Dmitry A. Kazakov
  2018-04-15 15:46         ` AdaMagica
  2018-04-25 23:46         ` Randy Brukardt
  0 siblings, 2 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-15 15:15 UTC (permalink / raw)


On 2018-04-15 16:54, Jeffrey R. Carter wrote:
> On 04/15/2018 04:12 PM, Dmitry A. Kazakov wrote:
>>
>> The problem is that Finalize is called when the object is declared in 
>> a nested scope:
>>
>>    procedure Main is
>>       Data : X;
>>    begin
>>       Data.Worker := new Worker_Type;
>>    end Main; -- Finalize is called (and terminates the task)
>>
>> This does not work:
>>
>>    package Library_Level is
>>       Data : X;
>>    end Library_Level;
>>
>>    with Library_Level;
>>    procedure Main is
>>    begin
>>       Library_Level.Data.Worker := new Worker_Type;
>>    end Main; -- Finalize is not called (presumably waiting for the task)
> 
> A task declared by an allocator (usually) depends on the thing that the 
> access type is declared in; here, that's a library-level pkg.
> 
> An object declaration such as Data goes out of scope when the thing that 
> it's declared in goes away. In a procedure, the procedure can end and 
> Data can be finalized, even though Data.Worker.all is still running. You 
> might, for example, copy Data.Worker to another variable of the access 
> type that will exist after the procedure call ends. Or you may want the 
> task to exist and run with no way to refer to it; tasks in worker pools 
> often work this way.

That would not work because the task actually has an access discriminant 
pointing the container type.

> When Data is declared in a library-level pkg, it's finalized when the 
> pkg goes out of scope, which doesn't happen until all library-level 
> tasks have terminated. Since Data.Worker has a library-level access 
> type, Data.Worker.all is a library-level task.

Yes. The problem is the order of finalization. For some unclear reason 
the task's access type is attempted before the object that contains that 
access type because they are in the same scope. The effect is that task 
termination is requested prematurely. I hoped that there is some trick, 
e.g. fooling the accessibility rules of the access type, some sort of 
Unchecked_Allocation. Ada 83 had pragma Controlled to require the 
compiler to keep its hands off, alas, it was removed.

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


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

* Re: Finalization of library level tasks
  2018-04-15 15:15       ` Dmitry A. Kazakov
@ 2018-04-15 15:46         ` AdaMagica
  2018-04-15 15:53           ` Dmitry A. Kazakov
                             ` (2 more replies)
  2018-04-25 23:46         ` Randy Brukardt
  1 sibling, 3 replies; 89+ messages in thread
From: AdaMagica @ 2018-04-15 15:46 UTC (permalink / raw)


Am Sonntag, 15. April 2018 17:15:22 UTC+2 schrieb Dmitry A. Kazakov:
> e.g. fooling the accessibility rules of the access type, some sort of 
> Unchecked_Allocation. Ada 83 had pragma Controlled to require the 
> compiler to keep its hands off, alas, it was removed.

This pragma was never implemented by any compiler (because there never was a garbage collector implemented and the pragma was intended to tell the GC to keep its hand off).

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

* Re: Finalization of library level tasks
  2018-04-15 15:46         ` AdaMagica
@ 2018-04-15 15:53           ` Dmitry A. Kazakov
  2018-04-15 17:17           ` AdaMagica
  2018-04-19 20:39           ` G. B.
  2 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-15 15:53 UTC (permalink / raw)


On 2018-04-15 17:46, AdaMagica wrote:
> Am Sonntag, 15. April 2018 17:15:22 UTC+2 schrieb Dmitry A. Kazakov:
>> e.g. fooling the accessibility rules of the access type, some sort of
>> Unchecked_Allocation. Ada 83 had pragma Controlled to require the
>> compiler to keep its hands off, alas, it was removed.
> 
> This pragma was never implemented by any compiler (because there never was a garbage collector implemented and the pragma was intended to tell the GC to keep its hand off).

It would be perfectly suitable for the purpose of explicitly forbidding 
any internal bookkeeping.

I hoped that pragma Convention (C, Pointer) would have same effect, but 
it does not.

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


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

* Re: Finalization of library level tasks
  2018-04-15 15:46         ` AdaMagica
  2018-04-15 15:53           ` Dmitry A. Kazakov
@ 2018-04-15 17:17           ` AdaMagica
  2018-04-15 17:40             ` Dmitry A. Kazakov
  2018-04-19 20:39           ` G. B.
  2 siblings, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-15 17:17 UTC (permalink / raw)


task body Worker_Type is
  begin
    loop
      select
        accept Quit;
        exit;
      or
        terminate;
      end select;
    end loop;
  end Worker_Type;

  procedure Finalize (X: in out T) is
  begin
    if X.Worker'Callable then
      X.Worker.Quit;
    end if;
  end Finalize;


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

* Re: Finalization of library level tasks
  2018-04-15 17:17           ` AdaMagica
@ 2018-04-15 17:40             ` Dmitry A. Kazakov
  2018-04-15 19:32               ` Egil H H
                                 ` (2 more replies)
  0 siblings, 3 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-15 17:40 UTC (permalink / raw)


On 2018-04-15 19:17, AdaMagica wrote:
> task body Worker_Type is
>    begin
>      loop
>        select
>          accept Quit;
>          exit;
>        or
>          terminate;
>        end select;
>      end loop;
>    end Worker_Type;
> 
>    procedure Finalize (X: in out T) is
>    begin
>      if X.Worker'Callable then
>        X.Worker.Quit;
>      end if;
>    end Finalize;

This task will hang in the select statement.

Terminate alternative is almost always useless because it cannot be 
mixed with "else" or "delay". If there were a way to check within the 
task if its completion has been requested your solution would work. 
Terminate should have been a normal predefined entry:

    task body T is
    begin
       select
          accept T'Terminate;
          exit;
       or ...

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


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

* Re: Finalization of library level tasks
  2018-04-15 17:40             ` Dmitry A. Kazakov
@ 2018-04-15 19:32               ` Egil H H
  2018-04-15 20:09                 ` Dmitry A. Kazakov
  2018-04-16  5:19               ` J-P. Rosen
  2018-04-16  9:19               ` AdaMagica
  2 siblings, 1 reply; 89+ messages in thread
From: Egil H H @ 2018-04-15 19:32 UTC (permalink / raw)


On Sunday, April 15, 2018 at 7:40:38 PM UTC+2, Dmitry A. Kazakov wrote:
> 
> Terminate alternative is almost always useless because it cannot be 
> mixed with "else" or "delay". If there were a way to check within the 
> task if its completion has been requested 

For library level tasks:

loop
   select
      accept Some_Rendezvous;
   or
      delay Some_Interval;
   end select;
    
   exit when not Ada.Task_Identification.Is_Callable
      (Ada.Task_Identification.Environment_Task);
    	    
end loop;


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

* Re: Finalization of library level tasks
  2018-04-15 19:32               ` Egil H H
@ 2018-04-15 20:09                 ` Dmitry A. Kazakov
  2018-04-25 23:49                   ` Randy Brukardt
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-15 20:09 UTC (permalink / raw)


On 2018-04-15 21:32, Egil H H wrote:
> On Sunday, April 15, 2018 at 7:40:38 PM UTC+2, Dmitry A. Kazakov wrote:
>>
>> Terminate alternative is almost always useless because it cannot be
>> mixed with "else" or "delay". If there were a way to check within the
>> task if its completion has been requested
> 
> For library level tasks:
> 
> loop
>     select
>        accept Some_Rendezvous;
>     or
>        delay Some_Interval;
>     end select;
>      
>     exit when not Ada.Task_Identification.Is_Callable
>        (Ada.Task_Identification.Environment_Task);
>      	
> end loop;

Yes, that is what I was looking for. T'Callable on the task itself does 
the trick. Apparently task being terminated is not callable.

Thanks.

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

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

* Re: Finalization of library level tasks
  2018-04-15 17:40             ` Dmitry A. Kazakov
  2018-04-15 19:32               ` Egil H H
@ 2018-04-16  5:19               ` J-P. Rosen
  2018-04-16  7:30                 ` Dmitry A. Kazakov
  2018-04-16  9:19               ` AdaMagica
  2 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-16  5:19 UTC (permalink / raw)


Le 15/04/2018 à 19:40, Dmitry A. Kazakov a écrit :
> Terminate alternative is almost always useless because it cannot be
> mixed with "else" or "delay".
And make termination undecidable? Come on!

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-16  5:19               ` J-P. Rosen
@ 2018-04-16  7:30                 ` Dmitry A. Kazakov
  2018-04-16  7:55                   ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-16  7:30 UTC (permalink / raw)


On 16/04/2018 07:19, J-P. Rosen wrote:
> Le 15/04/2018 à 19:40, Dmitry A. Kazakov a écrit :
>> Terminate alternative is almost always useless because it cannot be
>> mixed with "else" or "delay".
> And make termination undecidable? Come on!

Why? Terminate should be a predefined entry the task master calls to.

Anyway since T'Callable seems working, there is no need to use the 
terminate alternative ever.

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


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

* Re: Finalization of library level tasks
  2018-04-16  7:30                 ` Dmitry A. Kazakov
@ 2018-04-16  7:55                   ` J-P. Rosen
  2018-04-16  8:13                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-16  7:55 UTC (permalink / raw)


Le 16/04/2018 à 09:30, Dmitry A. Kazakov a écrit :
> On 16/04/2018 07:19, J-P. Rosen wrote:
>> Le 15/04/2018 à 19:40, Dmitry A. Kazakov a écrit :
>>> Terminate alternative is almost always useless because it cannot be
>>> mixed with "else" or "delay".
>> And make termination undecidable? Come on!
> 
> Why? Terminate should be a predefined entry the task master calls to.
If you allowed an else (or delay) alternative together with a terminate,
that alternative would be selected, and the task could in turn wake-up
its descendents...

> Anyway since T'Callable seems working, there is no need to use the
> terminate alternative ever.
> 
No, T'Callable becomes false AFTER the terminate has been selected.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-16  7:55                   ` J-P. Rosen
@ 2018-04-16  8:13                     ` Dmitry A. Kazakov
  2018-04-16  8:32                       ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-16  8:13 UTC (permalink / raw)


On 16/04/2018 09:55, J-P. Rosen wrote:
> Le 16/04/2018 à 09:30, Dmitry A. Kazakov a écrit :
>> On 16/04/2018 07:19, J-P. Rosen wrote:
>>> Le 15/04/2018 à 19:40, Dmitry A. Kazakov a écrit :
>>>> Terminate alternative is almost always useless because it cannot be
>>>> mixed with "else" or "delay".
>>> And make termination undecidable? Come on!
>>
>> Why? Terminate should be a predefined entry the task master calls to.
> If you allowed an else (or delay) alternative together with a terminate,
> that alternative would be selected, and the task could in turn wake-up
> its descendents...

You would terminate descendants (grandchildren) from the rendezvous with 
the child's Terminate:

    select
       ...
    or terminate
       do -- Hidden rendezvous body
         ... terminate all descendants
       end Terminate;
    else
       ... spawn new descendants
    end select;

>> Anyway since T'Callable seems working, there is no need to use the
>> terminate alternative ever.
>>
> No, T'Callable becomes false AFTER the terminate has been selected.

So GNAT implementation is wrong and this one is illegal?

    task body T is
    begin
       loop
          exit when not T'Callable;
          ... -- Do something
       end loop;
    end T;

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

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

* Re: Finalization of library level tasks
  2018-04-16  8:13                     ` Dmitry A. Kazakov
@ 2018-04-16  8:32                       ` J-P. Rosen
  2018-04-16 15:26                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-16  8:32 UTC (permalink / raw)


Le 16/04/2018 à 10:13, Dmitry A. Kazakov a écrit :
> You would terminate descendants (grandchildren) from the rendezvous with
> the child's Terminate:
> 
>    select
>       ...
>    or terminate
>       do -- Hidden rendezvous body
>         ... terminate all descendants
>       end Terminate;
>    else
>       ... spawn new descendants
>    end select;
That's not what I mean. If you have both "terminate" and "select", if
you select "terminate" (and all children are on a select with
terminate), then you can terminate and you were right to select that
branch. But if you select "else", then you can wake up other tasks that
might in turn call your entries, so you were right not to select
"terminate". That's what I call undecidable.

>>> Anyway since T'Callable seems working, there is no need to use the
>>> terminate alternative ever.
>>>
>> No, T'Callable becomes false AFTER the terminate has been selected.
> 
> So GNAT implementation is wrong and this one is illegal?
> 
>    task body T is
>    begin
>       loop
>          exit when not T'Callable;
>          ... -- Do something
>       end loop;
>    end T;
I don't know what Gnat is doing, but while T is normally active,
T'Callable is True. This is clearly an infinite loop.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-15 17:40             ` Dmitry A. Kazakov
  2018-04-15 19:32               ` Egil H H
  2018-04-16  5:19               ` J-P. Rosen
@ 2018-04-16  9:19               ` AdaMagica
  2018-04-16 15:15                 ` Dmitry A. Kazakov
  2 siblings, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-16  9:19 UTC (permalink / raw)


Am Sonntag, 15. April 2018 19:40:38 UTC+2 schrieb Dmitry A. Kazakov:
> On 2018-04-15 19:17, AdaMagica wrote:
> > task body Worker_Type is
> >    begin
> >      loop
> >        select
> >          accept Quit;
> >          exit;
> >        or
> >          terminate;
> >        end select;
> >      end loop;
> >    end Worker_Type;
> > 
> >    procedure Finalize (X: in out T) is
> >    begin
> >      if X.Worker'Callable then
> >        X.Worker.Quit;
> >      end if;
> >    end Finalize;
> 
> This task will hang in the select statement.
> 
> Terminate alternative is almost always useless because it cannot be 
> mixed with "else" or "delay".

The only way to request the completion from outside a task is (if I remember correctly) an abort statement. Then you don't need terminate.

Terminate is designed for passive tasks (let's call them thus), which become active only on request, i.e. via an entry call. Thus terminate, delay and else-statement are mutually exclusive. (I'm sure you know all this well.) Terminate is called by (hm, dunno, a task supervisor) when it is clear that there are no more clients who can call any of the entries, so the task has nothing more to do. A delay or else-statement would be a contradiction.

Thus your design seems wrong if you need something like this.

> If there were a way to check within the 
> task if its completion has been requested your solution would work. 
> Terminate should have been a normal predefined entry:
> 
>     task body T is
>     begin
>        select
>           accept T'Terminate;
>           exit;
>        or ...

This would lead to a very different tasking feature - a completely different Ada you every now and then seem to propose.


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

* Re: Finalization of library level tasks
  2018-04-16  9:19               ` AdaMagica
@ 2018-04-16 15:15                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-16 15:15 UTC (permalink / raw)


On 16/04/2018 11:19, AdaMagica wrote:

> Terminate is called by (hm, dunno, a task supervisor) when it is clear that there are no more clients who can call any of the entries, so the task has nothing more to do. A delay or else-statement would be a contradiction.

When the task goes out of scope you cannot continue without terminating 
the task.

> Thus your design seems wrong if you need something like this.
> 
>> If there were a way to check within the
>> task if its completion has been requested your solution would work.
>> Terminate should have been a normal predefined entry:
>>
>>      task body T is
>>      begin
>>         select
>>            accept T'Terminate;
>>            exit;
>>         or ...
> 
> This would lead to a very different tasking feature - a completely different Ada you every now and then seem to propose.

I don't know how this is that much different. You cannot terminate task 
unconditionally or instantly because local object must be finalized on 
the context of the task.

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

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

* Re: Finalization of library level tasks
  2018-04-16  8:32                       ` J-P. Rosen
@ 2018-04-16 15:26                         ` Dmitry A. Kazakov
  2018-04-17  9:51                           ` AdaMagica
                                             ` (2 more replies)
  0 siblings, 3 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-16 15:26 UTC (permalink / raw)


On 16/04/2018 10:32, J-P. Rosen wrote:
> Le 16/04/2018 à 10:13, Dmitry A. Kazakov a écrit :
>> You would terminate descendants (grandchildren) from the rendezvous with
>> the child's Terminate:
>>
>>     select
>>        ...
>>     or terminate
>>        do -- Hidden rendezvous body
>>          ... terminate all descendants
>>        end Terminate;
>>     else
>>        ... spawn new descendants
>>     end select;
> That's not what I mean. If you have both "terminate" and "select", if
> you select "terminate" (and all children are on a select with
> terminate), then you can terminate and you were right to select that
> branch. But if you select "else", then you can wake up other tasks that
> might in turn call your entries, so you were right not to select
> "terminate". That's what I call undecidable.

OK, but why should I care? Once termination is engaged, the task must 
become not callable (which seems the case by GNAT) and any call from any 
child would fail, which should allow terminating them.

>>>> Anyway since T'Callable seems working, there is no need to use the
>>>> terminate alternative ever.
>>>>
>>> No, T'Callable becomes false AFTER the terminate has been selected.
>>
>> So GNAT implementation is wrong and this one is illegal?
>>
>>     task body T is
>>     begin
>>        loop
>>           exit when not T'Callable;
>>           ... -- Do something
>>        end loop;
>>     end T;
> I don't know what Gnat is doing, but while T is normally active,
> T'Callable is True. This is clearly an infinite loop.

It terminates under GNAT. Thus my question.

The only place RM explains 'Callable is in ARM C.7.1:riddle:

"(10.a.1/1):Ramification: {8652/0115} {AI95-00206-01} These routines can 
be called with an argument identifying the environment task. 
Is_Terminated will always be False for such a call, but Is_Callable 
(usually True) could be False if the environment task is waiting for the 
termination of dependent tasks. Thus, a dependent task can use 
Is_Callable to determine if the main subprogram has completed."

At least for the environment task 'Callable is defined this (reasonable) 
way. It seems that GNAT uses this definition for all task.

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


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

* Re: Finalization of library level tasks
  2018-04-16 15:26                         ` Dmitry A. Kazakov
@ 2018-04-17  9:51                           ` AdaMagica
  2018-04-17 12:31                             ` Dmitry A. Kazakov
  2018-04-17 11:16                           ` J-P. Rosen
  2018-04-25 23:54                           ` Randy Brukardt
  2 siblings, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-17  9:51 UTC (permalink / raw)


Am Montag, 16. April 2018 17:26:42 UTC+2 schrieb Dmitry A. Kazakov:
> >> So GNAT implementation is wrong and this one is illegal?
> >>
> >>     task body T is
> >>     begin
> >>        loop
> >>           exit when not T'Callable;
> >>           ... -- Do something
> >>        end loop;
> >>     end T;
> > I don't know what Gnat is doing, but while T is normally active,
> > T'Callable is True. This is clearly an infinite loop.
> 
> It terminates under GNAT. Thus my question.

As I understand RM 9.3, when this task T is going out of scope, i.e. if it is declared inside for instance in a block, the block can only be left when the task is completed (the block is the master, see 7.6.1), and I cannot see that the conditions on T to be completed can ever be fulfilled for T.

Thus the block cannot be left, the program is blocked. Gnat seems wrong to me.


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

* Re: Finalization of library level tasks
  2018-04-16 15:26                         ` Dmitry A. Kazakov
  2018-04-17  9:51                           ` AdaMagica
@ 2018-04-17 11:16                           ` J-P. Rosen
  2018-04-17 12:47                             ` Dmitry A. Kazakov
  2018-04-25 23:54                           ` Randy Brukardt
  2 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-17 11:16 UTC (permalink / raw)


Le 16/04/2018 à 17:26, Dmitry A. Kazakov a écrit :
> The only place RM explains 'Callable is in ARM C.7.1:riddle:
> 
> "(10.a.1/1):Ramification: {8652/0115} {AI95-00206-01} These routines can
> be called with an argument identifying the environment task.
> Is_Terminated will always be False for such a call, but Is_Callable
> (usually True) could be False if the environment task is waiting for the
> termination of dependent tasks. Thus, a dependent task can use
> Is_Callable to determine if the main subprogram has completed."
> 
> At least for the environment task 'Callable is defined this (reasonable)
> way. It seems that GNAT uses this definition for all task.

The environment task calls the main subprogram. Therefore, after the
main subprogram has returned, the environment task may be waiting for
other tasks to terminate, and is thus no more callable. But I don't see
how this relates to your example.

One thing to keep in mind is the meaning of "or terminate": it means
that no task could possibly call an entry of the task, and therefore
that the task is blocked forever. In this case, it is better to
terminate it. If you had an else part, there is a way to revive it, and
therefore it cannot be terminatable.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-17  9:51                           ` AdaMagica
@ 2018-04-17 12:31                             ` Dmitry A. Kazakov
  2018-04-17 15:37                               ` Jeffrey R. Carter
  2018-04-18  8:06                               ` AdaMagica
  0 siblings, 2 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-17 12:31 UTC (permalink / raw)


On 17/04/2018 11:51, AdaMagica wrote:
> Am Montag, 16. April 2018 17:26:42 UTC+2 schrieb Dmitry A. Kazakov:
>>>> So GNAT implementation is wrong and this one is illegal?
>>>>
>>>>      task body T is
>>>>      begin
>>>>         loop
>>>>            exit when not T'Callable;
>>>>            ... -- Do something
>>>>         end loop;
>>>>      end T;
>>> I don't know what Gnat is doing, but while T is normally active,
>>> T'Callable is True. This is clearly an infinite loop.
>>
>> It terminates under GNAT. Thus my question.
> 
> As I understand RM 9.3, when this task T is going out of scope, i.e. if it is declared inside for instance in a block, the block can only be left when the task is completed (the block is the master, see 7.6.1), and I cannot see that the conditions on T to be completed can ever be fulfilled for T.

Quite naturally, when the master is being finalized it marks the task as 
terminating and waits for its completion. The task marked for 
termination has T'Callable false and so terminates.

> Thus the block cannot be left, the program is blocked. Gnat seems wrong to me.

It would be an insane behavior. But that would not wonder me because 
rules are already insane, e.g. 7.6.1(4):

"For the finalization of a master, dependent tasks are first awaited, as 
explained in 9.3. Then each object whose accessibility level is the same 
as that of the master is finalized if the object was successfully 
initialized and still exists."

which is the reason why library-level task cannot be terminated using 
controlled objects.

------------------------------------------------------------
I thought about a method involving a helper task:

    Exiting : Boolean := False;
    type Exit_Event is
       new Ada.Finaization.Limited_Controlled with null record;
    procedure Finalize (X : in out Exit_Event) is
    begin
       Exiting := True;
    end Finalize;

    task Working_Around is
       entry Never_Entry;
    end Working_Around;

    task body Working_Around is
       X : Exit_Event;
    begin
       select
          accept Never_Entry;
       or terminate;
       end select;
    end Working;

    task body T is
    begin
       loop
          exit when not Exiting;
          ... -- Do something
       end loop;
    end T;

I hoped that T'Callable, if defined meaningfully, could spare me this mess.

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

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

* Re: Finalization of library level tasks
  2018-04-17 11:16                           ` J-P. Rosen
@ 2018-04-17 12:47                             ` Dmitry A. Kazakov
  2018-04-17 14:08                               ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-17 12:47 UTC (permalink / raw)


On 17/04/2018 13:16, J-P. Rosen wrote:
> Le 16/04/2018 à 17:26, Dmitry A. Kazakov a écrit :
>> The only place RM explains 'Callable is in ARM C.7.1:riddle:
>>
>> "(10.a.1/1):Ramification: {8652/0115} {AI95-00206-01} These routines can
>> be called with an argument identifying the environment task.
>> Is_Terminated will always be False for such a call, but Is_Callable
>> (usually True) could be False if the environment task is waiting for the
>> termination of dependent tasks. Thus, a dependent task can use
>> Is_Callable to determine if the main subprogram has completed."
>>
>> At least for the environment task 'Callable is defined this (reasonable)
>> way. It seems that GNAT uses this definition for all task.
> 
> The environment task calls the main subprogram. Therefore, after the
> main subprogram has returned, the environment task may be waiting for
> other tasks to terminate, and is thus no more callable. But I don't see
> how this relates to your example.

It is related directly. Environment_Task'Callable becomes False before 
completion when the task is still running.

If 'Callable is same as 'Terminated why there are two of them?

Anyway there must be a way to know if a task was requested to terminate, 
because the terminate alternative is useless for practical cases.

> One thing to keep in mind is the meaning of "or terminate": it means
> that no task could possibly call an entry of the task, and therefore
> that the task is blocked forever. In this case, it is better to
> terminate it.

It is a circular statement. Yes, if you want to terminate a task you 
terminate it. You don't derive that from the task's state. That would be 
  nonsense. If a task wants to terminate it does so without asking the 
master. If the master want to terminate a task it just orders this and 
waits.

> If you had an else part, there is a way to revive it, and
> therefore it cannot be terminatable.

I don't understand the meaning of "revive". The meaning of

    select
       terminate;
    else
       null;
    end select;

is crystal clear: continue if no master did request termination else 
continue. Again, I thought that T'Callable were there to determine if a 
master wants the task to terminate. RM is silent about that. Even for 
the environment task it is in a side note.

I am puzzled.

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

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

* Re: Finalization of library level tasks
  2018-04-17 12:47                             ` Dmitry A. Kazakov
@ 2018-04-17 14:08                               ` J-P. Rosen
  2018-04-17 14:47                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-17 14:08 UTC (permalink / raw)


Le 17/04/2018 à 14:47, Dmitry A. Kazakov a écrit :
> I don't understand the meaning of "revive". The meaning of
> 
>    select
>       terminate;
>    else
>       null;
>    end select;
> 
> is crystal clear: continue if no master did request termination else
> continue. Again, I thought that T'Callable were there to determine if a
> master wants the task to terminate.
It's just that your mental model of 'Callable and Terminate is not the
one of Ada. A master does not require termination from its dependent
tasks: it checks (recursively) if all the dependent tasks are either
already terminated or similarly waiting on a select-with-terminate. If
yes, the whole family terminates simultaneously.

When a master is waiting for dependent tasks to terminate (at its end,
NOT if on a select-with-terminate), it is not yet Terminated, but it is
no more Callable.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-17 14:08                               ` J-P. Rosen
@ 2018-04-17 14:47                                 ` Dmitry A. Kazakov
  2018-04-17 22:00                                   ` Robert A Duff
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-17 14:47 UTC (permalink / raw)


On 17/04/2018 16:08, J-P. Rosen wrote:
> Le 17/04/2018 à 14:47, Dmitry A. Kazakov a écrit :
>> I don't understand the meaning of "revive". The meaning of
>>
>>     select
>>        terminate;
>>     else
>>        null;
>>     end select;
>>
>> is crystal clear: continue if no master did request termination else
>> continue. Again, I thought that T'Callable were there to determine if a
>> master wants the task to terminate.
> It's just that your mental model of 'Callable and Terminate is not the
> one of Ada. A master does not require termination from its dependent
> tasks: it checks (recursively) if all the dependent tasks are either
> already terminated or similarly waiting on a select-with-terminate. If
> yes, the whole family terminates simultaneously.

That simply cannot work. The task (or task manager) must know if the 
terminate alternative can be selected. That depends on the master's 
state. Master or something on its behalf must tell the task that it must 
start selecting terminate alternatives.

> When a master is waiting for dependent tasks to terminate (at its end,
> NOT if on a select-with-terminate), it is not yet Terminated, but it is
> no more Callable.

In that case

    task body T is
    begin
       while T'Callable loop
          ...
       end loop;
    end T;

must work, GNAT is correct, I am happy.

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

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

* Re: Finalization of library level tasks
  2018-04-17 12:31                             ` Dmitry A. Kazakov
@ 2018-04-17 15:37                               ` Jeffrey R. Carter
  2018-04-17 15:57                                 ` Dmitry A. Kazakov
  2018-04-18  8:06                               ` AdaMagica
  1 sibling, 1 reply; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-04-17 15:37 UTC (permalink / raw)


On 04/17/2018 02:31 PM, Dmitry A. Kazakov wrote:
> 
> Quite naturally, when the master is being finalized it marks the task as 
> terminating and waits for its completion. The task marked for termination has 
> T'Callable false and so terminates.

'Callable returns True if the task is completed or abnormal. I would think that 
a task that can evaluate the condition of an "exit when" would be neither.

> I hoped that T'Callable, if defined meaningfully, could spare me this mess.

I'm pretty sure that Is_Callable (Environment_Task), as defined in the ARM, does 
what you want and spares you that mess.

-- 
Jeff Carter
"I was either in love, or I had smallpox."
Take the Money and Run
137

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

* Re: Finalization of library level tasks
  2018-04-17 15:37                               ` Jeffrey R. Carter
@ 2018-04-17 15:57                                 ` Dmitry A. Kazakov
  2018-04-17 20:16                                   ` Jeffrey R. Carter
  2018-04-17 20:55                                   ` J-P. Rosen
  0 siblings, 2 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-17 15:57 UTC (permalink / raw)


On 2018-04-17 17:37, Jeffrey R. Carter wrote:
> On 04/17/2018 02:31 PM, Dmitry A. Kazakov wrote:
>>
>> Quite naturally, when the master is being finalized it marks the task 
>> as terminating and waits for its completion. The task marked for 
>> termination has T'Callable false and so terminates.
> 
> 'Callable returns True if the task is completed or abnormal. I would 
> think that a task that can evaluate the condition of an "exit when" 
> would be neither.

Yet 'Callable is False when the environment task is neither completed 
not abnormal. The definition leaks.

>> I hoped that T'Callable, if defined meaningfully, could spare me this 
>> mess.
> 
> I'm pretty sure that Is_Callable (Environment_Task), as defined in the 
> ARM, does what you want and spares you that mess.

What about this deduction: if the environment task is not callable then 
any other task is not callable, because it depends on the environment task.

In that case any task allocated for a library level access type could 
use T'Callable (Is_Callable = 'Callable according to RM). Therefore GNAT 
is still correct.

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


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

* Re: Finalization of library level tasks
  2018-04-17 15:57                                 ` Dmitry A. Kazakov
@ 2018-04-17 20:16                                   ` Jeffrey R. Carter
  2018-04-17 20:59                                     ` Dmitry A. Kazakov
  2018-04-17 20:55                                   ` J-P. Rosen
  1 sibling, 1 reply; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-04-17 20:16 UTC (permalink / raw)


On 04/17/2018 05:57 PM, Dmitry A. Kazakov wrote:
> 
> What about this deduction: if the environment task is not callable then any 
> other task is not callable, because it depends on the environment task.

That doesn't follow. There's nothing that prevents the environment task from 
being non-callable while other tasks are callable.

When the environment task returns from calling the main-program subprogram, it 
becomes completed and non-callable.

It then waits until all dependent tasks complete.

Then it does library-level finalization.

Then it terminates.

There can be a period there when the environment task has completed and some 
dependent tasks have not. Indeed, if any library-level tasks never finish, that 
period can be infinite.

-- 
Jeff Carter
"I was either in love, or I had smallpox."
Take the Money and Run
137


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

* Re: Finalization of library level tasks
  2018-04-17 15:57                                 ` Dmitry A. Kazakov
  2018-04-17 20:16                                   ` Jeffrey R. Carter
@ 2018-04-17 20:55                                   ` J-P. Rosen
  2018-04-17 21:23                                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-17 20:55 UTC (permalink / raw)


Le 17/04/2018 à 17:57, Dmitry A. Kazakov a écrit :
> Yet 'Callable is False when the environment task is neither completed
> not abnormal. The definition leaks.
This is wrong. Can you provide a complete example that shows that? Then
I'll file a ticket to AdaCore

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-17 20:16                                   ` Jeffrey R. Carter
@ 2018-04-17 20:59                                     ` Dmitry A. Kazakov
  2018-04-18  5:20                                       ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-17 20:59 UTC (permalink / raw)


On 2018-04-17 22:16, Jeffrey R. Carter wrote:
> On 04/17/2018 05:57 PM, Dmitry A. Kazakov wrote:
>>
>> What about this deduction: if the environment task is not callable 
>> then any other task is not callable, because it depends on the 
>> environment task.
> 
> That doesn't follow. There's nothing that prevents the environment task 
> from being non-callable while other tasks are callable.

OK. If other things are inconsistent this one should be as well...

At least I can hope that AdaCore will never fix this "bug" and the 
nonsense will not make it into the ACATS.

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


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

* Re: Finalization of library level tasks
  2018-04-17 20:55                                   ` J-P. Rosen
@ 2018-04-17 21:23                                     ` Dmitry A. Kazakov
  2018-04-18  5:26                                       ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-17 21:23 UTC (permalink / raw)


On 2018-04-17 22:55, J-P. Rosen wrote:
> Le 17/04/2018 à 17:57, Dmitry A. Kazakov a écrit :
>> Yet 'Callable is False when the environment task is neither completed
>> not abnormal. The definition leaks.

ARM C.7.1(10):

"The functions Is_Terminated and Is_Callable return the value of the 
corresponding attribute of the task identified by T.

Ramification: {8652/0115} {AI95-00206-01} These routines can be called 
with an argument identifying the environment task. Is_Terminated will 
always be False for such a call, but Is_Callable (usually True) could be 
False if the environment task is waiting for the termination of 
dependent tasks. Thus, a dependent task can use Is_Callable to determine 
if the main subprogram has completed."

> This is wrong. Can you provide a complete example that shows that? Then
> I'll file a ticket to AdaCore

No way! I want it working. (:-))

P.S. If "main subprogram complete" should mean "environment task 
complete" that is OK to me. However insane the wording sounds to me only 
the semantics counts. Why could not "task complete" mean "will select 
next terminate"? At least it would make some use out of having T'Callable.

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

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

* Re: Finalization of library level tasks
  2018-04-17 14:47                                 ` Dmitry A. Kazakov
@ 2018-04-17 22:00                                   ` Robert A Duff
  2018-04-18  7:25                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: Robert A Duff @ 2018-04-17 22:00 UTC (permalink / raw)


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

>    task body T is
>    begin
>       while T'Callable loop
>          ...
>       end loop;
>    end T;
>
> must work, GNAT is correct, I am happy.

I'm not sure what you mean by "work".  GNAT correctly
compiles that into an infinite loop, as J-P explained.
Here's a complete example:

with Text_IO; use Text_IO;
package Foo is
   task T;
end Foo;

package body Foo is
   task body T is
   begin
      while T'Callable loop
         Put_Line("Hello");
         delay 2.0;
      end loop;
   end T;
end Foo;

procedure Foo.Main is
begin
   null;
end Foo.Main;

This prints "Hello" every 2 seconds until you get 
bored and kill it.

I think perhaps you wanted to query Callable on the environment
task, not T.  If so, please post a complete example, and say
what GNAT is doing, and why you think that's wrong (or right?).

- Bob


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

* Re: Finalization of library level tasks
  2018-04-17 20:59                                     ` Dmitry A. Kazakov
@ 2018-04-18  5:20                                       ` J-P. Rosen
  0 siblings, 0 replies; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18  5:20 UTC (permalink / raw)


Le 17/04/2018 à 22:59, Dmitry A. Kazakov a écrit :
> 
> At least I can hope that AdaCore will never fix this "bug" and the
> nonsense will not make it into the ACATS.
This is no nonsense, and there are lots of tests about termination in
the ACATS. I can tell you: I wrote them.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-17 21:23                                     ` Dmitry A. Kazakov
@ 2018-04-18  5:26                                       ` J-P. Rosen
  2018-04-26  0:02                                         ` Randy Brukardt
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18  5:26 UTC (permalink / raw)


Le 17/04/2018 à 23:23, Dmitry A. Kazakov a écrit :
> P.S. If "main subprogram complete" should mean "environment task
> complete" that is OK to me. However insane the wording sounds to me only
> the semantics counts.
The paragraph you quote says "has completed", not "complete". Remember,
the main subprogram is called by the environment task. So, the main
subprogram completes and exits, then the environment task waits for
dependents, at which point its 'callable becomes false.

> Why could not "task complete" mean "will select
> next terminate"? At least it would make some use out of having T'Callable.
'Callable is very useful for regular tasks. Your quote suggests that
there might also be some use for it on the environment task, which is
not obvious.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-17 22:00                                   ` Robert A Duff
@ 2018-04-18  7:25                                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18  7:25 UTC (permalink / raw)


On 18/04/2018 00:00, Robert A Duff wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>>     task body T is
>>     begin
>>        while T'Callable loop
>>           ...
>>        end loop;
>>     end T;
>>
>> must work, GNAT is correct, I am happy.
> 
> I'm not sure what you mean by "work".  GNAT correctly
> compiles that into an infinite loop, as J-P explained.
> Here's a complete example:
> 
> with Text_IO; use Text_IO;
> package Foo is
>     task T;
> end Foo;
> 
> package body Foo is
>     task body T is
>     begin
>        while T'Callable loop
>           Put_Line("Hello");
>           delay 2.0;
>        end loop;
>     end T;
> end Foo;
> 
> procedure Foo.Main is
> begin
>     null;
> end Foo.Main;
> 
> This prints "Hello" every 2 seconds until you get
> bored and kill it.

In my case it ends. So it is "fixed", unfortunately. It was not that 
useful anyway because it would not work for nested tasks which have 
exactly same problem in the case when the master is at the same level. 
It is not so notorious because programmers tend to allocate tasks 
dynamically and declare the corresponding pointer at the library level. 
So the finalization deadlock does not happen.

> I think perhaps you wanted to query Callable on the environment
> task, not T.  If so, please post a complete example, and say
> what GNAT is doing, and why you think that's wrong (or right?).

I will post an example to augment encapsulated task pattern in order to 
work around language idiosyncrasies.

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

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

* Re: Finalization of library level tasks
  2018-04-17 12:31                             ` Dmitry A. Kazakov
  2018-04-17 15:37                               ` Jeffrey R. Carter
@ 2018-04-18  8:06                               ` AdaMagica
  2018-04-18  8:25                                 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-18  8:06 UTC (permalink / raw)


Am Dienstag, 17. April 2018 14:31:24 UTC+2 schrieb Dmitry A. Kazakov:
> On 17/04/2018 11:51, AdaMagica wrote:
>>>>      task body T is
>>>>      begin
>>>>         loop
>>>>            exit when not T'Callable;
>>>>            ... -- Do something
>>>>         end loop;
>>>>      end T;
> > As I understand RM 9.3, when this task T is going out of scope, i.e. if it is declared inside for instance in a block, the block can only be left when the task is completed (the block is the master, see 7.6.1), and I cannot see that the conditions on T to be completed can ever be fulfilled for T.
> 
> Quite naturally, when the master is being finalized it marks the task as 
> terminating and waits for its completion. The task marked for 
> termination has T'Callable false and so terminates.

Dmitry, please quote the RM where you can find this rule - I'm certain you will not find it.

Your model of tasking in Ada is not completely in line with the RM.
T'Callable is true as long as the T has not finished its body, and there is an infinite loop, so it cannot stop.

> The meaning of
>
>    select
>       terminate;
>    else
>       null;
>    end select;
>
> is crystal clear: continue if no master did request termination else
> continue. Again, I thought that T'Callable were there to determine if a
> master wants the task to terminate. RM is silent about that. Even for
> the environment task it is in a side note.

May be in your mind, but not in the RM. Your model is wrong.


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

* Re: Finalization of library level tasks
  2018-04-18  8:06                               ` AdaMagica
@ 2018-04-18  8:25                                 ` Dmitry A. Kazakov
  2018-04-18  8:52                                   ` Egil H H
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18  8:25 UTC (permalink / raw)


On 18/04/2018 10:06, AdaMagica wrote:

>> Quite naturally, when the master is being finalized it marks the task as
>> terminating and waits for its completion. The task marked for
>> termination has T'Callable false and so terminates.
> 
> Dmitry, please quote the RM where you can find this rule - I'm certain you will not find it.

It is not a rule, it is a possible implementation of finalization as 
defined in 7.6.1(4).

Regarding the semantics of T'Callable, it is basically undefined except 
for the environment task, which implicitly defines otherwise undefined 
"completed" as "main completed" and that in turn implies Callable = False.

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

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

* Re: Finalization of library level tasks
  2018-04-18  8:25                                 ` Dmitry A. Kazakov
@ 2018-04-18  8:52                                   ` Egil H H
  2018-04-18  9:58                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: Egil H H @ 2018-04-18  8:52 UTC (permalink / raw)


Undefined?

9.9(2), "a task is callable unless it is completed or abnormal"
9.3(5), "A task is said to be completed when the execution of its corresponding task_body is completed"

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

* Re: Finalization of library level tasks
  2018-04-18  8:52                                   ` Egil H H
@ 2018-04-18  9:58                                     ` Dmitry A. Kazakov
  2018-04-18 11:33                                       ` J-P. Rosen
  2018-04-26  0:04                                       ` Randy Brukardt
  0 siblings, 2 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18  9:58 UTC (permalink / raw)


On 18/04/2018 10:52, Egil H H wrote:
> Undefined?
> 
> 9.9(2), "a task is callable unless it is completed or abnormal"
> 9.3(5), "A task is said to be completed when the execution of its corresponding task_body is completed"

OK, it is defined enough to confirm that T'Callable cannot be used to 
break finalization deadlock. If not at the library level then only way 
seems to be a helper task at the same level. After second thought no 
shared variable and a controlled object is needed in the helper task. 
The required construct:

    select
       terminate; -- Terminate if asked
    else
       null;
    end select;

can be emulated using Callable on the helper task:

    task Helper is
       entry Never;
    end Helper;

    task body Helper is
    begin
       select
          accept Never;
       or terminate;
       end select;
    end Helper;

    task body Worker_Task is
    begin
       while Helper'Callable loop
          ... -- Do something
       end loop;
    end Worker_Task;

When Helper and Worker_Task have same master then Worker_Task can break 
finalization deadlock by looking at the Helper.

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

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

* Re: Finalization of library level tasks
  2018-04-18  9:58                                     ` Dmitry A. Kazakov
@ 2018-04-18 11:33                                       ` J-P. Rosen
  2018-04-18 11:58                                         ` Dmitry A. Kazakov
  2018-04-26  0:04                                       ` Randy Brukardt
  1 sibling, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18 11:33 UTC (permalink / raw)


Le 18/04/2018 à 11:58, Dmitry A. Kazakov a écrit :
> can be emulated using Callable on the helper task:
> 
>    task Helper is
>       entry Never;
>    end Helper;
> 
>    task body Helper is
>    begin
>       select
>          accept Never;
>       or terminate;
>       end select;
>    end Helper;
> 
>    task body Worker_Task is
>    begin
>       while Helper'Callable loop
>          ... -- Do something
>       end loop;
>    end Worker_Task;
> 
> When Helper and Worker_Task have same master then Worker_Task can break
> finalization deadlock by looking at the Helper.
Won't work. Please read 9.3(6/1):
 the open terminate_alternative is selected if and only if the following
conditions are satisfied:
- The task depends on some completed master; and
- Each task that depends on the master considered is either already
terminated or similarly blocked at a select_statement with an open
terminate_alternative.

Since Worker_Task and Helper depend on the same master, and Worker_Task
is still busy, Helper won't select the terminate alternative, and will
be still Callable.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-18 11:33                                       ` J-P. Rosen
@ 2018-04-18 11:58                                         ` Dmitry A. Kazakov
  2018-04-18 12:00                                           ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18 11:58 UTC (permalink / raw)


On 18/04/2018 13:33, J-P. Rosen wrote:
> Le 18/04/2018 à 11:58, Dmitry A. Kazakov a écrit :
>> can be emulated using Callable on the helper task:
>>
>>     task Helper is
>>        entry Never;
>>     end Helper;
>>
>>     task body Helper is
>>     begin
>>        select
>>           accept Never;
>>        or terminate;
>>        end select;
>>     end Helper;
>>
>>     task body Worker_Task is
>>     begin
>>        while Helper'Callable loop
>>           ... -- Do something
>>        end loop;
>>     end Worker_Task;
>>
>> When Helper and Worker_Task have same master then Worker_Task can break
>> finalization deadlock by looking at the Helper.
> Won't work. Please read 9.3(6/1):
>   the open terminate_alternative is selected if and only if the following
> conditions are satisfied:
> - The task depends on some completed master; and
> - Each task that depends on the master considered is either already
> terminated or similarly blocked at a select_statement with an open
> terminate_alternative.

(plus a race condition in tow. One could construct a case when a couple 
of tasks will never terminate calling each other to ensure that at a 
time at least two of them do not offer terminate alternative. How nice)

> Since Worker_Task and Helper depend on the same master, and Worker_Task
> is still busy, Helper won't select the terminate alternative, and will
> be still Callable.

Well, it seems broken beyond repair then. Let me guess, there going to 
be no change to fix the mess. Right?

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


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

* Re: Finalization of library level tasks
  2018-04-18 11:58                                         ` Dmitry A. Kazakov
@ 2018-04-18 12:00                                           ` J-P. Rosen
  2018-04-18 12:25                                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18 12:00 UTC (permalink / raw)


Le 18/04/2018 à 13:58, Dmitry A. Kazakov a écrit :
> Well, it seems broken beyond repair then. Let me guess, there going to
> be no change to fix the mess. Right?
No, since there is no mess, except in your expectations about what
terminate means.

It is intended to allow for clean termination of servers when no client
is able to call them, and for that purpose, it works as intended.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-18 12:00                                           ` J-P. Rosen
@ 2018-04-18 12:25                                             ` Dmitry A. Kazakov
  2018-04-18 13:51                                               ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18 12:25 UTC (permalink / raw)


On 18/04/2018 14:00, J-P. Rosen wrote:
> Le 18/04/2018 à 13:58, Dmitry A. Kazakov a écrit :
>> Well, it seems broken beyond repair then. Let me guess, there going to
>> be no change to fix the mess. Right?
> No, since there is no mess, except in your expectations about what
> terminate means.

There is no any expectations, just an elementary requirement not to 
deadlock upon object finalization.

> It is intended to allow for clean termination of servers when no client
> is able to call them, and for that purpose, it works as intended.

Sorry, but it does not work at all, because there is no any way to 
terminate task. If intended task termination has race condition, uses 
arbitrary dependencies between unrelated tasks, ignores stated 
dependencies, e.g. between the packages, deadlocks in finalization, then 
there must be something wrong with the intention.

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


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

* Re: Finalization of library level tasks
  2018-04-18 12:25                                             ` Dmitry A. Kazakov
@ 2018-04-18 13:51                                               ` J-P. Rosen
  2018-04-18 14:12                                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18 13:51 UTC (permalink / raw)


Le 18/04/2018 à 14:25, Dmitry A. Kazakov a écrit :
> Sorry, but it does not work at all, because there is no any way to
> terminate task. If intended task termination has race condition, uses
> arbitrary dependencies between unrelated tasks, ignores stated
> dependencies, e.g. between the packages, deadlocks in finalization, then
> there must be something wrong with the intention.
It has not, or your termination conditions call for a higher protocol.
All your suggestions are undecidable; please provide an example of the
problem.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-18 13:51                                               ` J-P. Rosen
@ 2018-04-18 14:12                                                 ` Dmitry A. Kazakov
  2018-04-18 14:52                                                   ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18 14:12 UTC (permalink / raw)


On 18/04/2018 15:51, J-P. Rosen wrote:
> Le 18/04/2018 à 14:25, Dmitry A. Kazakov a écrit :
>> Sorry, but it does not work at all, because there is no any way to
>> terminate task. If intended task termination has race condition, uses
>> arbitrary dependencies between unrelated tasks, ignores stated
>> dependencies, e.g. between the packages, deadlocks in finalization, then
>> there must be something wrong with the intention.
> It has not, or your termination conditions call for a higher protocol.
> All your suggestions are undecidable; please provide an example of the
> problem.

Problem: A worker task encapsulated into an object. The task does some 
calculations or some I/O in chunks. The task's activity is not induced 
by other tasks. When the object finalizes the task must go with it. 
Nothing more.

In pseudo-code:

    task body Worker is
    begin
       while the object lives loop
          do some chunk of work
       end loop;
    end Worker;

P.S. I posted an example in a separate thread. The posted solution 
should work except the cases when the access type is at the same level 
as the object and both are below the library level.

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


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

* Re: Finalization of library level tasks
  2018-04-18 14:12                                                 ` Dmitry A. Kazakov
@ 2018-04-18 14:52                                                   ` J-P. Rosen
  2018-04-18 15:04                                                     ` Dmitry A. Kazakov
                                                                       ` (2 more replies)
  0 siblings, 3 replies; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18 14:52 UTC (permalink / raw)


Le 18/04/2018 à 16:12, Dmitry A. Kazakov a écrit :
> In pseudo-code:
> 
>    task body Worker is
>    begin
>       while the object lives loop
>          do some chunk of work
>       end loop;
>    end Worker;
> 
> P.S. I posted an example in a separate thread. The posted solution
> should work except the cases when the access type is at the same level
> as the object and both are below the library level.
> 
OK. You were actually quite close... Use a killer task (with the same
master as your worker) like this:

task Killer is
   entry Never_Called;
end Killer;

task body Killer is
begin
   accept Never_Called;
exception
   when Tasking_Error =>
     -- Kill the other task
end Killer;

Hint: when the master completes, Tasking_Error is raised in all tasks
waiting on entries that depend on that master.
-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-18 14:52                                                   ` J-P. Rosen
@ 2018-04-18 15:04                                                     ` Dmitry A. Kazakov
  2018-04-18 20:26                                                       ` AdaMagica
  2018-04-18 20:40                                                     ` AdaMagica
  2018-04-18 21:29                                                     ` J-P. Rosen
  2 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18 15:04 UTC (permalink / raw)


On 18/04/2018 16:52, J-P. Rosen wrote:
> Le 18/04/2018 à 16:12, Dmitry A. Kazakov a écrit :
>> In pseudo-code:
>>
>>     task body Worker is
>>     begin
>>        while the object lives loop
>>           do some chunk of work
>>        end loop;
>>     end Worker;
>>
>> P.S. I posted an example in a separate thread. The posted solution
>> should work except the cases when the access type is at the same level
>> as the object and both are below the library level.
>>
> OK. You were actually quite close... Use a killer task (with the same
> master as your worker) like this:
> 
> task Killer is
>     entry Never_Called;
> end Killer;
> 
> task body Killer is
> begin
>     accept Never_Called;
> exception
>     when Tasking_Error =>
>       -- Kill the other task
> end Killer;
> 
> Hint: when the master completes, Tasking_Error is raised in all tasks
> waiting on entries that depend on that master.

Does it raise for all entries? If it does no killer task is needed:

    task body Worker is
    begin
       loop
          begin
             select
                accept Never;
             else
                null;
             end select;
          exception
             when Tasking_Eror =>
                exit;
          end;
          do some chunk of work
       end loop;
    end Worker;

Should this work?

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

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

* Re: Finalization of library level tasks
  2018-04-18 15:04                                                     ` Dmitry A. Kazakov
@ 2018-04-18 20:26                                                       ` AdaMagica
  2018-04-18 21:00                                                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-18 20:26 UTC (permalink / raw)


Am Mittwoch, 18. April 2018 17:04:58 UTC+2 schrieb Dmitry A. Kazakov:
> On 18/04/2018 16:52, J-P. Rosen wrote:
> > Le 18/04/2018 à 16:12, Dmitry A. Kazakov a écrit :
> >> In pseudo-code:
> >>
> >>     task body Worker is
> >>     begin
> >>        while the object lives loop
> >>           do some chunk of work
> >>        end loop;
> >>     end Worker;
> >>
> >> P.S. I posted an example in a separate thread. The posted solution
> >> should work except the cases when the access type is at the same level
> >> as the object and both are below the library level.
> >>
> > OK. You were actually quite close... Use a killer task (with the same
> > master as your worker) like this:
> > 
> > task Killer is
> >     entry Never_Called;
> > end Killer;
> > 
> > task body Killer is
> > begin
> >     accept Never_Called;
> > exception
> >     when Tasking_Error =>
> >       -- Kill the other task
> > end Killer;
> > 
> > Hint: when the master completes, Tasking_Error is raised in all tasks
> > waiting on entries that depend on that master.
> 
> Does it raise for all entries? If it does no killer task is needed:
> 
>     task body Worker is
>     begin
>        loop
>           begin
>              select
>                 accept Never;
>              else
>                 null;
>              end select;
>           exception
>              when Tasking_Eror =>
>                 exit;
>           end;
>           do some chunk of work
>        end loop;
>     end Worker;
> 
> Should this work?

No, because it's not waiting at the rendezvous.


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

* Re: Finalization of library level tasks
  2018-04-18 14:52                                                   ` J-P. Rosen
  2018-04-18 15:04                                                     ` Dmitry A. Kazakov
@ 2018-04-18 20:40                                                     ` AdaMagica
  2018-04-19  7:34                                                       ` Simon Wright
  2018-04-18 21:29                                                     ` J-P. Rosen
  2 siblings, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-18 20:40 UTC (permalink / raw)


Am Mittwoch, 18. April 2018 16:52:04 UTC+2 schrieb J-P. Rosen:
> Le 18/04/2018 à 16:12, Dmitry A. Kazakov a écrit :
> > In pseudo-code:
> > 
> >    task body Worker is
> >    begin
> >       while the object lives loop
> >          do some chunk of work
> >       end loop;
> >    end Worker;
> > 
> > P.S. I posted an example in a separate thread. The posted solution
> > should work except the cases when the access type is at the same level
> > as the object and both are below the library level.
> > 
> OK. You were actually quite close... Use a killer task (with the same
> master as your worker) like this:
> 
> task Killer is
>    entry Never_Called;
> end Killer;
> 
> task body Killer is
> begin
>    accept Never_Called;
> exception
>    when Tasking_Error =>
>      -- Kill the other task
> end Killer;
> 
> Hint: when the master completes, Tasking_Error is raised in all tasks
> waiting on entries that depend on that master.

I do not understand how this is supposed to work.


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

* Re: Finalization of library level tasks
  2018-04-18 20:26                                                       ` AdaMagica
@ 2018-04-18 21:00                                                         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-18 21:00 UTC (permalink / raw)


On 2018-04-18 22:26, AdaMagica wrote:
> Am Mittwoch, 18. April 2018 17:04:58 UTC+2 schrieb Dmitry A. Kazakov:
>> On 18/04/2018 16:52, J-P. Rosen wrote:
>>> Le 18/04/2018 à 16:12, Dmitry A. Kazakov a écrit :
>>>> In pseudo-code:
>>>>
>>>>      task body Worker is
>>>>      begin
>>>>         while the object lives loop
>>>>            do some chunk of work
>>>>         end loop;
>>>>      end Worker;
>>>>
>>>> P.S. I posted an example in a separate thread. The posted solution
>>>> should work except the cases when the access type is at the same level
>>>> as the object and both are below the library level.
>>>>
>>> OK. You were actually quite close... Use a killer task (with the same
>>> master as your worker) like this:
>>>
>>> task Killer is
>>>      entry Never_Called;
>>> end Killer;
>>>
>>> task body Killer is
>>> begin
>>>      accept Never_Called;
>>> exception
>>>      when Tasking_Error =>
>>>        -- Kill the other task
>>> end Killer;
>>>
>>> Hint: when the master completes, Tasking_Error is raised in all tasks
>>> waiting on entries that depend on that master.
>>
>> Does it raise for all entries? If it does no killer task is needed:
>>
>>      task body Worker is
>>      begin
>>         loop
>>            begin
>>               select
>>                  accept Never;
>>               else
>>                  null;
>>               end select;
>>            exception
>>               when Tasking_Eror =>
>>                  exit;
>>            end;
>>            do some chunk of work
>>         end loop;
>>      end Worker;
>>
>> Should this work?
> 
> No, because it's not waiting at the rendezvous.

Strange semantics, at least. How about this:

    task body Worker is
    begin
       loop
          begin
             select
                accept Never;
             or delay 0.000_001;
             end select;
          exception
             when Tasking_Eror =>
                exit;
          end;
          do some chunk of work
       end loop;
    end Worker;

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

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

* Re: Finalization of library level tasks
  2018-04-18 14:52                                                   ` J-P. Rosen
  2018-04-18 15:04                                                     ` Dmitry A. Kazakov
  2018-04-18 20:40                                                     ` AdaMagica
@ 2018-04-18 21:29                                                     ` J-P. Rosen
  2018-04-19  7:32                                                       ` Dmitry A. Kazakov
  2 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-18 21:29 UTC (permalink / raw)


Le 18/04/2018 à 16:52, J-P. Rosen a écrit :
> OK. You were actually quite close... Use a killer task (with the same
> master as your worker) like this:
> 
> task Killer is
>    entry Never_Called;
> end Killer;
> 
> task body Killer is
> begin
>    accept Never_Called;
> exception
>    when Tasking_Error =>
>      -- Kill the other task
> end Killer;
> 
> Hint: when the master completes, Tasking_Error is raised in all tasks
> waiting on entries that depend on that master.
Sorry, my mistake. Typed too fast from an old trick I used... It's the
other way round. When a task completes, it raises Tasking_Error in the
tasks waiting on its entries.

So, you can wait for the completion of a task without busy waiting by
calling an entry of the task that is never accepted, and handling
tasking_error.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: Finalization of library level tasks
  2018-04-18 21:29                                                     ` J-P. Rosen
@ 2018-04-19  7:32                                                       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-19  7:32 UTC (permalink / raw)


On 18/04/2018 23:29, J-P. Rosen wrote:
> Le 18/04/2018 à 16:52, J-P. Rosen a écrit :
>> OK. You were actually quite close... Use a killer task (with the same
>> master as your worker) like this:
>>
>> task Killer is
>>     entry Never_Called;
>> end Killer;
>>
>> task body Killer is
>> begin
>>     accept Never_Called;
>> exception
>>     when Tasking_Error =>
>>       -- Kill the other task
>> end Killer;
>>
>> Hint: when the master completes, Tasking_Error is raised in all tasks
>> waiting on entries that depend on that master.
> Sorry, my mistake. Typed too fast from an old trick I used... It's the
> other way round. When a task completes, it raises Tasking_Error in the
> tasks waiting on its entries.
> 
> So, you can wait for the completion of a task without busy waiting by
> calling an entry of the task that is never accepted, and handling
> tasking_error.

But how to complete that task in the first place? The scenario of task 
termination you described in this thread before specifically precludes 
any task to complete in the event of master waiting them to complete. It 
is a deadlock built into the language.

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


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

* Re: Finalization of library level tasks
  2018-04-18 20:40                                                     ` AdaMagica
@ 2018-04-19  7:34                                                       ` Simon Wright
  0 siblings, 0 replies; 89+ messages in thread
From: Simon Wright @ 2018-04-19  7:34 UTC (permalink / raw)


AdaMagica <christ-usch.grein@t-online.de> writes:

> Am Mittwoch, 18. April 2018 16:52:04 UTC+2 schrieb J-P. Rosen:

>> OK. You were actually quite close... Use a killer task (with the same
>> master as your worker) like this:
>> 
>> task Killer is
>>    entry Never_Called;
>> end Killer;
>> 
>> task body Killer is
>> begin
>>    accept Never_Called;
>> exception
>>    when Tasking_Error =>
>>      -- Kill the other task
>> end Killer;
>> 
>> Hint: when the master completes, Tasking_Error is raised in all tasks
>> waiting on entries that depend on that master.
>
> I do not understand how this is supposed to work.

I tried this:

   with Killer_Pack;
   procedure Killing is
   begin
      null;
   end Killing;
   
   package Killer_Pack is
      task Killer is
         entry Never_Called;
      end Killer;
   end Killer_Pack;

   with GNAT.IO;
   package body Killer_Pack is
      task body Killer is
      begin
         accept Never_Called;
      exception
         when Tasking_Error =>
            GNAT.IO.Put_Line ("bye.");
      end Killer;
   end Killer_Pack;

with all the GNATs I could lay my hands on (macOS) and they all hang:
under gdb,

   (gdb) info tasks
      ID       TID P-ID Pri State                  Name
   *   1 101000000       31 Child Termination Wait main_task
       2 101000e00    1  31 Accept or Select Term  killer

Of course, I'm quite prepared to believe I've misunderstood the point.


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

* Re: Finalization of library level tasks
  2018-04-15 15:46         ` AdaMagica
  2018-04-15 15:53           ` Dmitry A. Kazakov
  2018-04-15 17:17           ` AdaMagica
@ 2018-04-19 20:39           ` G. B.
  2018-04-20  7:27             ` Dmitry A. Kazakov
  2 siblings, 1 reply; 89+ messages in thread
From: G. B. @ 2018-04-19 20:39 UTC (permalink / raw)


AdaMagica <christ-usch.grein@t-online.de> wrote:
> Am Sonntag, 15. April 2018 17:15:22 UTC+2 schrieb Dmitry A. Kazakov:
>> e.g. fooling the accessibility rules of the access type, some sort of 
>> Unchecked_Allocation. Ada 83 had pragma Controlled to require the 
>> compiler to keep its hands off, alas, it was removed.
> 
> This pragma was never implemented by any compiler (because there never
> was a garbage collector implemented and the pragma was intended to tell
> the GC to keep its hand off).
> 

Both AdaMagic and GNAT can compile for the JVM.
GNAT also targets .NET. These are GC targets.
It’s not big business, seemingly, but then what is.


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

* Re: Finalization of library level tasks
  2018-04-19 20:39           ` G. B.
@ 2018-04-20  7:27             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-20  7:27 UTC (permalink / raw)


On 19/04/2018 22:39, G. B. wrote:
> AdaMagica <christ-usch.grein@t-online.de> wrote:
>> Am Sonntag, 15. April 2018 17:15:22 UTC+2 schrieb Dmitry A. Kazakov:
>>> e.g. fooling the accessibility rules of the access type, some sort of
>>> Unchecked_Allocation. Ada 83 had pragma Controlled to require the
>>> compiler to keep its hands off, alas, it was removed.
>>
>> This pragma was never implemented by any compiler (because there never
>> was a garbage collector implemented and the pragma was intended to tell
>> the GC to keep its hand off).
> 
> Both AdaMagic and GNAT can compile for the JVM.
> GNAT also targets .NET. These are GC targets.
> It’s not big business, seemingly, but then what is.

GC is not the point. The point is to be able to turn off any stuff Ada 
implicitly does for finalization and completion of objects allocated 
using allocator of the specified access type:

1. Remove from the list of objects to be finalized
2. From the list of storage [sub]pool objects
3. From the list of objects allocated using a local access type
4. Ignore any rules about task masters

If you were to build your custom GC you might probably wish this option too.

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

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

* Re: Finalization of library level tasks
  2018-04-15 15:15       ` Dmitry A. Kazakov
  2018-04-15 15:46         ` AdaMagica
@ 2018-04-25 23:46         ` Randy Brukardt
  2018-04-26  9:03           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-04-25 23:46 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pavqa6$1qdj$1@gioia.aioe.org...
...
> Yes. The problem is the order of finalization. For some unclear reason the 
> task's access type is attempted before the object that contains that 
> access type because they are in the same scope.

It's not unclear - tasks have to terminate before objects are finalized so 
that the tasks aren't trying to use finalized objects. If the object is a 
protected object, that could be a really bad deal (remember that finalizing 
a protected object raises tasking error in any queued task and prevents 
future calls).

We ran into this with Claw, and eventually had the Ada.Task_Identification 
solution ingrained into the Standard. (I believe you found it from some 
other messages that I saw previously, so I won't describe it here.)

                Randy.



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

* Re: Finalization of library level tasks
  2018-04-15 20:09                 ` Dmitry A. Kazakov
@ 2018-04-25 23:49                   ` Randy Brukardt
  0 siblings, 0 replies; 89+ messages in thread
From: Randy Brukardt @ 2018-04-25 23:49 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pb0bho$p1e$1@gioia.aioe.org...
> On 2018-04-15 21:32, Egil H H wrote:
>> On Sunday, April 15, 2018 at 7:40:38 PM UTC+2, Dmitry A. Kazakov wrote:
>>>
>>> Terminate alternative is almost always useless because it cannot be
>>> mixed with "else" or "delay". If there were a way to check within the
>>> task if its completion has been requested
>>
>> For library level tasks:
>>
>> loop
>>     select
>>        accept Some_Rendezvous;
>>     or
>>        delay Some_Interval;
>>     end select;
>>      exit when not Ada.Task_Identification.Is_Callable
>>        (Ada.Task_Identification.Environment_Task);
>>      end loop;
>
> Yes, that is what I was looking for. T'Callable on the task itself does 
> the trick. Apparently task being terminated is not callable.

Callable becomes False when a task is completed. That happens before 
finalization and before termination.

The environment task completes when the main subprogram exits, and you can 
test that as above.

            Randy.


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

* Re: Finalization of library level tasks
  2018-04-16 15:26                         ` Dmitry A. Kazakov
  2018-04-17  9:51                           ` AdaMagica
  2018-04-17 11:16                           ` J-P. Rosen
@ 2018-04-25 23:54                           ` Randy Brukardt
  2018-04-26 16:22                             ` Jeffrey R. Carter
  2 siblings, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-04-25 23:54 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pb2fbf$516$1@gioia.aioe.org...
> It terminates under GNAT. Thus my question.
>
> The only place RM explains 'Callable is in ARM C.7.1:riddle:

Interesting. It should be declared somewhere. Anyway, the rule is that 
T'Callable = True unless the task is completed. See 9.3 for the definition 
of completed.

If the task is still running, it can't be completed, so T'Callable has to be 
true. The code you have is an infinite loop. It should be using the parent 
task (whatever that is) as the prefix of the attribute.

                     Randy.


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

* Re: Finalization of library level tasks
  2018-04-18  5:26                                       ` J-P. Rosen
@ 2018-04-26  0:02                                         ` Randy Brukardt
  0 siblings, 0 replies; 89+ messages in thread
From: Randy Brukardt @ 2018-04-26  0:02 UTC (permalink / raw)


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

"J-P. Rosen" <rosen@adalog.fr> wrote in message 
news:pb6kuf$jgl$1@gioia.aioe.org...
> Le 17/04/2018 à 23:23, Dmitry A. Kazakov a écrit :
>> P.S. If "main subprogram complete" should mean "environment task
>> complete" that is OK to me. However insane the wording sounds to me only
>> the semantics counts.
> The paragraph you quote says "has completed", not "complete". Remember,
> the main subprogram is called by the environment task. So, the main
> subprogram completes and exits, then the environment task waits for
> dependents, at which point its 'callable becomes false.
>
>> Why could not "task complete" mean "will select
>> next terminate"? At least it would make some use out of having 
>> T'Callable.
> 'Callable is very useful for regular tasks. Your quote suggests that
> there might also be some use for it on the environment task, which is
> not obvious.

I invented that to get around Dmitry's original problem when I stumbled into 
it building Claw right after Ada 95 was finished. I was able to convince the 
ARG that the environment task ought to be completed once the main subprogram 
exits [that follows from the definition of the environment task], and that 
one should be able to use Ada.Task_Identification to query that. (You could 
do it even before the Environment_Task function, you just had to squirrel 
the environment task id during initial elaboration.) Several compilers 
didn't do this right, but one of the first things I added to the ACATS after 
taking over was a test of this case (once the ARG approved the idea, of 
course). So all modern compilers support the idiom of testing Callable of 
the environment task.

                       Randy.



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

* Re: Finalization of library level tasks
  2018-04-18  9:58                                     ` Dmitry A. Kazakov
  2018-04-18 11:33                                       ` J-P. Rosen
@ 2018-04-26  0:04                                       ` Randy Brukardt
  2018-04-26  8:56                                         ` Dmitry A. Kazakov
  1 sibling, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-04-26  0:04 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pb74sr$1cmf$1@gioia.aioe.org...
> On 18/04/2018 10:52, Egil H H wrote:
>> Undefined?
>>
>> 9.9(2), "a task is callable unless it is completed or abnormal"
>> 9.3(5), "A task is said to be completed when the execution of its 
>> corresponding task_body is completed"
>
> OK, it is defined enough to confirm that T'Callable cannot be used to 
> break finalization deadlock.

Of course it can: you test T'Callable of your parent task, *not* of 
yourself. If that parent is the environment task, use the 
Task_Identification version.

                Randy.



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

* Re: Finalization of library level tasks
  2018-04-26  0:04                                       ` Randy Brukardt
@ 2018-04-26  8:56                                         ` Dmitry A. Kazakov
  2018-04-26 22:10                                           ` Randy Brukardt
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-26  8:56 UTC (permalink / raw)


On 26/04/2018 02:04, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:pb74sr$1cmf$1@gioia.aioe.org...
>> On 18/04/2018 10:52, Egil H H wrote:
>>> Undefined?
>>>
>>> 9.9(2), "a task is callable unless it is completed or abnormal"
>>> 9.3(5), "A task is said to be completed when the execution of its
>>> corresponding task_body is completed"
>>
>> OK, it is defined enough to confirm that T'Callable cannot be used to
>> break finalization deadlock.
> 
> Of course it can: you test T'Callable of your parent task, *not* of
> yourself. If that parent is the environment task, use the
> Task_Identification version.

No, because the parent task is not going to terminate.

The problem is to test if the current task is awaited to terminate in 
order to have an equivalent of:

    loop
       select
          terminate;
       else
          null;
       end select;
       -- Do a portion of work
    end loop;

There is no solution to this below the library level where the 
environment task hack works.

Under the library level an access to the task must be used *and* this 
pointer type must be declared one level up the future master of the 
task. I.e. it cannot be local in the scope where the object creating the 
task lives. This will deadlock as mandated by the RM.

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

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

* Re: Finalization of library level tasks
  2018-04-25 23:46         ` Randy Brukardt
@ 2018-04-26  9:03           ` Dmitry A. Kazakov
  2018-04-26 22:25             ` Randy Brukardt
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-26  9:03 UTC (permalink / raw)


On 26/04/2018 01:46, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:pavqa6$1qdj$1@gioia.aioe.org...
> ...
>> Yes. The problem is the order of finalization. For some unclear reason the
>> task's access type is attempted before the object that contains that
>> access type because they are in the same scope.
> 
> It's not unclear - tasks have to terminate before objects are finalized so
> that the tasks aren't trying to use finalized objects. If the object is a
> protected object, that could be a really bad deal (remember that finalizing
> a protected object raises tasking error in any queued task and prevents
> future calls).

It is all objects, not just ones containing the task. You could have:

    package A is
       task type Foo ...
       X : Foo;
    end A;

    package A.B is
       type Bar is new Ada.Finalization.Controlled ...
       Y : Bar;
    end A.B;

Even so, finalization of Y will await termination of X! The deadlock in 
the RM is constructed to prevent any possible way to break it.

There are dozens ways to fix the mess but there seems no interest at all.

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

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

* Re: Finalization of library level tasks
  2018-04-25 23:54                           ` Randy Brukardt
@ 2018-04-26 16:22                             ` Jeffrey R. Carter
  2018-04-26 16:43                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-04-26 16:22 UTC (permalink / raw)


On 04/26/2018 01:54 AM, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>
>> The only place RM explains 'Callable is in ARM C.7.1:riddle:
> 
> Interesting. It should be declared somewhere. Anyway, the rule is that
> T'Callable = True unless the task is completed. See 9.3 for the definition
> of completed.

'Callable and the concept of "callable" are defined at ARM 9.9(2): "T'Callable 
Yields the value True when the task denoted by T is callable, and False 
otherwise; a task is callable unless it is completed or abnormal."

-- 
Jeff Carter
"Every sperm is sacred."
Monty Python's the Meaning of Life
55

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

* Re: Finalization of library level tasks
  2018-04-26 16:22                             ` Jeffrey R. Carter
@ 2018-04-26 16:43                               ` Dmitry A. Kazakov
  2018-04-26 20:19                                 ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-26 16:43 UTC (permalink / raw)


On 2018-04-26 18:22, Jeffrey R. Carter wrote:
> On 04/26/2018 01:54 AM, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>>
>>> The only place RM explains 'Callable is in ARM C.7.1:riddle:
>>
>> Interesting. It should be declared somewhere. Anyway, the rule is that
>> T'Callable = True unless the task is completed. See 9.3 for the 
>> definition
>> of completed.
> 
> 'Callable and the concept of "callable" are defined at ARM 9.9(2): 
> "T'Callable Yields the value True when the task denoted by T is 
> callable, and False otherwise; a task is callable unless it is completed 
> or abnormal."

Literally it means "can be called". In

task body T is
begin
    select
       accept X;
    or terminate;
    end select;
end T;

X cannot be called when the master awaits termination of T. Thus 
*logically* T is not callable when terminate will be selected.

Surely there could be another attribute with a different name, or a 
predefined entry to be accepted when the master is waiting. Or both.

Among with finalization deadlock another problem of terminate 
alternative is that there is not rendezvous. Surely programmers wish do 
be able to do explicit cleanup on termination without misusing 
controlled objects:

    select
       ...
    or terminate do
       ... -- Complete task
       end terminate;
    end select;

[ Yes, we want to be able to requeue terminate and to make entry calls 
from there. ]

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


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

* Re: Finalization of library level tasks
  2018-04-26 16:43                               ` Dmitry A. Kazakov
@ 2018-04-26 20:19                                 ` J-P. Rosen
  0 siblings, 0 replies; 89+ messages in thread
From: J-P. Rosen @ 2018-04-26 20:19 UTC (permalink / raw)


Le 26/04/2018 à 18:43, Dmitry A. Kazakov a écrit :
> Literally it means "can be called". In
> 
> task body T is
> begin
>    select
>       accept X;
>    or terminate;
>    end select;
> end T;
> 
> X cannot be called when the master awaits termination of T. Thus
> *logically* T is not callable when terminate will be selected.
Wrong. X can be called by other subtasks of the same master that are
still active (that's why the master is completed but not terminated).

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-26  8:56                                         ` Dmitry A. Kazakov
@ 2018-04-26 22:10                                           ` Randy Brukardt
  2018-04-27  4:48                                             ` J-P. Rosen
  0 siblings, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-04-26 22:10 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pbs473$co3$1@gioia.aioe.org...
> On 26/04/2018 02:04, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:pb74sr$1cmf$1@gioia.aioe.org...
>>> On 18/04/2018 10:52, Egil H H wrote:
>>>> Undefined?
>>>>
>>>> 9.9(2), "a task is callable unless it is completed or abnormal"
>>>> 9.3(5), "A task is said to be completed when the execution of its
>>>> corresponding task_body is completed"
>>>
>>> OK, it is defined enough to confirm that T'Callable cannot be used to
>>> break finalization deadlock.
>>
>> Of course it can: you test T'Callable of your parent task, *not* of
>> yourself. If that parent is the environment task, use the
>> Task_Identification version.
>
> No, because the parent task is not going to terminate.

"completion" and "termination" are different concepts in Ada, and always 
have been. A completed task still has to await any tasks nested in it, and 
do finalization of any objects that it owns. So it still can execute code, 
make entry calls, and the like.

> The problem is to test if the current task is awaited to terminate in 
> order to have an equivalent of:
>
>    loop
>       select
>          terminate;
>       else
>          null;
>       end select;
>       -- Do a portion of work
>    end loop;

The case I was considering is when the task is directly declared in another 
task. There is no mechanism to determine whether a task is awaited; I 
believe that would be a race condition and thus it was omitted from Ada.

So if you declare a task in a block there is no practical way to terminate 
it -- ergo, don't do that. :-)

> There is no solution to this below the library level where the environment 
> task hack works.

It works fine if the task's master is another task, and it never works 
otherwise. It doesn't have anything specifically to do with the environment 
task -- you can do the same trick with any parent task.

> Under the library level an access to the task must be used *and* this 
> pointer type must be declared one level up the future master of the task. 
> I.e. it cannot be local in the scope where the object creating the task 
> lives. This will deadlock as mandated by the RM.

There's no problem if the task's master is that of the parent task, as I 
noted. One way to do that indeed is to use an access-to-task (but it doesn't 
have to be at library level). If you are looking for something more general, 
it doesn't exist.

                              Randy.




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

* Re: Finalization of library level tasks
  2018-04-26  9:03           ` Dmitry A. Kazakov
@ 2018-04-26 22:25             ` Randy Brukardt
  2018-04-27  7:37               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-04-26 22:25 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pbs4km$doq$1@gioia.aioe.org...
> On 26/04/2018 01:46, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:pavqa6$1qdj$1@gioia.aioe.org...
>> ...
>>> Yes. The problem is the order of finalization. For some unclear reason 
>>> the
>>> task's access type is attempted before the object that contains that
>>> access type because they are in the same scope.
>>
>> It's not unclear - tasks have to terminate before objects are finalized 
>> so
>> that the tasks aren't trying to use finalized objects. If the object is a
>> protected object, that could be a really bad deal (remember that 
>> finalizing
>> a protected object raises tasking error in any queued task and prevents
>> future calls).
>
> It is all objects, not just ones containing the task. You could have:
>
>    package A is
>       task type Foo ...
>       X : Foo;
>    end A;
>
>    package A.B is
>       type Bar is new Ada.Finalization.Controlled ...
>       Y : Bar;
>    end A.B;
>
> Even so, finalization of Y will await termination of X!

It has to. There is no way for the compiler to know that there is no way for 
X to access Y.

> The deadlock in the RM is constructed to prevent any possible way to break 
> it.

Correct, and that is by design. An unbreakable premise of Ada is that 
finalization of objects will always be done no matter what happens. That's 
why subpools have a finalization mechanism, Unchecked_Deallocation does 
finalization, assignment does finalization, ad nauseum. The designer of an 
Ada library (ADT) can always be assured that their last wishes will be 
executed regardless of what horrors the client tries to invent. This is a 
critical property for reusability.

> There are dozens ways to fix the mess but there seems no interest at all.

Correction: there are dozens of ways to make a worse mess. There is no way 
to "fix" the issue, because any change to the rules just breaks in some 
other case. Or completely destroys the ability of ADTs to assume that 
finalization happens.

When we ran into the problem in the Claw design, I spent a lot of time 
trying to come up with a fix. I couldn't find anything that didn't have 
worse problems in some cases. I believe other ARG members did the same 
thing; the environment task solution seemed to be the best workaround (it 
works great in Claw, presuming of course that the compiler implements it 
correctly).

Claw, for instance, uses a number of locks. We had problems with compilers 
finalizing those locks before awaiting tasks, meaning that the tasks got 
Program_Error for no expected reason. (And one compiler that will remain 
nameless just crashed if you called such a lock; there's an ACATS test for 
that, too, these days.)

The critical thing from an Ada perspective is that the rules are 
well-defined and don't change from implementation-to-implementation. Then it 
is always possible to find a solution (not necessarily an easy one).

Task termination is rarely considered in Ada books, yet it is one of the 
hardest things to accomplish. I don't have any termination technique at all 
in the spam filter, because I couldn't think of anything that would actually 
work. Luckily, you can just kill the process from Windows in the few cases 
where you need to shut the thing down.

One of the advantages of the parallelism model in Ada 2020 is that you don't 
have to write explicit tasks so you don't have to deal with termination of 
them.

                          Randy.



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

* Re: Finalization of library level tasks
  2018-04-26 22:10                                           ` Randy Brukardt
@ 2018-04-27  4:48                                             ` J-P. Rosen
  2018-04-27 20:52                                               ` Randy Brukardt
  0 siblings, 1 reply; 89+ messages in thread
From: J-P. Rosen @ 2018-04-27  4:48 UTC (permalink / raw)


Le 27/04/2018 à 00:10, Randy Brukardt a écrit :
> So if you declare a task in a block there is no practical way to terminate 
> it -- ergo, don't do that. :-)
> 
Huh? Consider

declare
   task Server is
      entry Service;
   end Server;

   task body Server is
   begin
      loop
         select
            accept Service do ... end Service;
         or terminate;
         end select;
      end loop;
   end Server;
begin
   ...
   Server.Service;
   ...
   Server.Service;
end;

The task will terminate nicely when the block is completed. That's what
terminate is for!

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Finalization of library level tasks
  2018-04-26 22:25             ` Randy Brukardt
@ 2018-04-27  7:37               ` Dmitry A. Kazakov
  2018-04-27  8:32                 ` AdaMagica
  2018-04-27 21:08                 ` Randy Brukardt
  0 siblings, 2 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-27  7:37 UTC (permalink / raw)


On 27/04/2018 00:25, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:pbs4km$doq$1@gioia.aioe.org...
>> On 26/04/2018 01:46, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:pavqa6$1qdj$1@gioia.aioe.org...
>>> ...
>>>> Yes. The problem is the order of finalization. For some unclear reason
>>>> the
>>>> task's access type is attempted before the object that contains that
>>>> access type because they are in the same scope.
>>>
>>> It's not unclear - tasks have to terminate before objects are finalized
>>> so
>>> that the tasks aren't trying to use finalized objects. If the object is a
>>> protected object, that could be a really bad deal (remember that
>>> finalizing
>>> a protected object raises tasking error in any queued task and prevents
>>> future calls).
>>
>> It is all objects, not just ones containing the task. You could have:
>>
>>     package A is
>>        task type Foo ...
>>        X : Foo;
>>     end A;
>>
>>     package A.B is
>>        type Bar is new Ada.Finalization.Controlled ...
>>        Y : Bar;
>>     end A.B;
>>
>> Even so, finalization of Y will await termination of X!
> 
> It has to. There is no way for the compiler to know that there is no way for
> X to access Y.
> 
>> The deadlock in the RM is constructed to prevent any possible way to break
>> it.
> 
> Correct, and that is by design. An unbreakable premise of Ada is that
> finalization of objects will always be done no matter what happens. That's
> why subpools have a finalization mechanism, Unchecked_Deallocation does
> finalization, assignment does finalization, ad nauseum. The designer of an
> Ada library (ADT) can always be assured that their last wishes will be
> executed regardless of what horrors the client tries to invent. This is a
> critical property for reusability.

It is not reusable when the code depends on whether the object is 
declared at the library level or not. It is not reusable when pointers 
are unavoidable. It is not reusable when the "standard" task termination 
method is not usable and must be always replaced with some kludge to be 
reinvented each time new.

>> There are dozens ways to fix the mess but there seems no interest at all.
> 
> Correction: there are dozens of ways to make a worse mess. There is no way
> to "fix" the issue, because any change to the rules just breaks in some
> other case. Or completely destroys the ability of ADTs to assume that
> finalization happens.

Nothing will be broken by adding a Boolean attribute T'Completion_Awaited.

Nothing will be broken by fixing the finalization model that does not 
distinguish finalization of the class from finalization of the 
type-specific object.

You *can* finalize the class of the object containing the task with the 
task component still running:

    type Container_Type is .. tagged ...
       T : Task_Type;

The order of finalization must be:

    Finalize Container_Type'Class;
    Stop T;                  -- Existing order
    Finalize Container_Type;
    Finalize T;

Note that Ada 95 type system wisely distinguished Container_Type'Class 
and Container_Type, while finalization inconsistently ignores the 
difference.

Nothing will be broken by adding user-controlled aspect to access type 
to kill any bookkeeping, any hidden lists, any dependencies.

[...]

> One of the advantages of the parallelism model in Ada 2020 is that you don't
> have to write explicit tasks so you don't have to deal with termination of
> them.

I don't see how this will help with designing active objects, writing 
servers for I/O protocols, handling pools of worker tasks.

If ARG wants get rid of explicit tasks it should seriously revise the 
type system. The task type must be an interface to derive from.

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

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

* Re: Finalization of library level tasks
  2018-04-27  7:37               ` Dmitry A. Kazakov
@ 2018-04-27  8:32                 ` AdaMagica
  2018-04-27  8:57                   ` Dmitry A. Kazakov
  2018-04-27 21:08                 ` Randy Brukardt
  1 sibling, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-27  8:32 UTC (permalink / raw)


Am Freitag, 27. April 2018 09:37:46 UTC+2 schrieb Dmitry A. Kazakov:
> You *can* finalize the class of the object containing the task with the 
> task component still running:
> 
>     type Container_Type is .. tagged ...
>        T : Task_Type;
> 
> The order of finalization must be:
> 
>     Finalize Container_Type'Class;
>     Stop T;                  -- Existing order

IIUC, you mean the task T is stopped anywhere in the middle of its work? Ada calls this abort. This means a lot of things may be left in an invalid state.

Normal task completion takes place at defined places, everything is left in a well-defined state. It's your design work to define those places.

>     Finalize Container_Type;
>     Finalize T;
> 
> Note that Ada 95 type system wisely distinguished Container_Type'Class 

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

* Re: Finalization of library level tasks
  2018-04-27  8:32                 ` AdaMagica
@ 2018-04-27  8:57                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-27  8:57 UTC (permalink / raw)


On 27/04/2018 10:32, AdaMagica wrote:
> Am Freitag, 27. April 2018 09:37:46 UTC+2 schrieb Dmitry A. Kazakov:
>> You *can* finalize the class of the object containing the task with the
>> task component still running:
>>
>>      type Container_Type is .. tagged ...
>>         T : Task_Type;
>>
>> The order of finalization must be:
>>
>>      Finalize Container_Type'Class;
>>      Stop T;                  -- Existing order
> 
> IIUC, you mean the task T is stopped anywhere in the middle of its work?

No, I mean that the task is awaited, e.g. to accept terminate.

What I meant is that finalization of a class object does not need to 
wait for the task to end. Therefore from the class' Finalize you could 
ask the task to stop:

    task type Task_Type is
       entry Shutdown;
    end Task_Type;

    type Container_Type is
       new Ada.Finalization.Limited_Controlled with
    record
       T : Task_Type;
    end record;

    procedure Finalize (Object : in out Container_Type'Class);
    for Container_Type'Class'Finalize use Finalize ; -- Whatever syntax

    procedure Finalize (Object : in out Container_Type'Class) is
    begin
       Object.T.Shutdown; -- You cannot do that from normal Finalize,
    end Finalize;         -- it is too late then

Presently class finalization is null. BTW, after class finalization 
dispatching calls on the class must result in an exception. It should 
have been a bounded error to dispatch from Initialize or Finalize.

One of the inconsistencies of controlled types design is that 
dispatching is allowed in Finalization <=> the class considered 
operational, but task components are not running <=> the class 
considered non-operational. Either one or another.

> Ada calls this abort. This means a lot of things may be left in an invalid state.

Yes. Task abort is almost never usable.

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

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

* Re: Finalization of library level tasks
  2018-04-27  4:48                                             ` J-P. Rosen
@ 2018-04-27 20:52                                               ` Randy Brukardt
  0 siblings, 0 replies; 89+ messages in thread
From: Randy Brukardt @ 2018-04-27 20:52 UTC (permalink / raw)


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

We were talking about the 90% of cases where "terminate" doesn't work, of 
course. Not the rare cases where it does. (I've never had one in the tasks 
I've written.)

                   Randy.

"J-P. Rosen" <rosen@adalog.fr> wrote in message 
news:pbua2d$1rt8$1@gioia.aioe.org...
> Le 27/04/2018 à 00:10, Randy Brukardt a écrit :
>> So if you declare a task in a block there is no practical way to 
>> terminate
>> it -- ergo, don't do that. :-)
>>
> Huh? Consider
>
> declare
>   task Server is
>      entry Service;
>   end Server;
>
>   task body Server is
>   begin
>      loop
>         select
>            accept Service do ... end Service;
>         or terminate;
>         end select;
>      end loop;
>   end Server;
> begin
>   ...
>   Server.Service;
>   ...
>   Server.Service;
> end;
>
> The task will terminate nicely when the block is completed. That's what
> terminate is for!
>
> -- 
> J-P. Rosen
> Adalog
> 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
> Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
> http://www.adalog.fr 


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

* Re: Finalization of library level tasks
  2018-04-27  7:37               ` Dmitry A. Kazakov
  2018-04-27  8:32                 ` AdaMagica
@ 2018-04-27 21:08                 ` Randy Brukardt
  2018-04-28  8:35                   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-04-27 21:08 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pbuk07$9mf$1@gioia.aioe.org...
...
> It is not reusable when the code depends on whether the object is declared 
> at the library level or not.

That only happens if you write broken code in the first place: tasks should 
never be embedded in objects. It simply doesn't work (Ichbiah got that 
wrong). When you do so, termination is a problem, but so is avoiding 
deadlocks, race conditions, and the like. The entire nesting model of tasks 
in Ada is huge overkill and should never have happened - it's a huge amount 
of complexity for a value approaching zero. (Note that the first thing 
Ravenscar discards is the nesting model.)

>>> There are dozens ways to fix the mess but there seems no interest at 
>>> all.
>>
>> Correction: there are dozens of ways to make a worse mess. There is no 
>> way
>> to "fix" the issue, because any change to the rules just breaks in some
>> other case. Or completely destroys the ability of ADTs to assume that
>> finalization happens.
>
> Nothing will be broken by adding a Boolean attribute T'Completion_Awaited.

I've been told that would lead people to writing code which depends on race 
conditions. I'm not enough of an expert on tasking to try to disagree with 
people that are.

> Nothing will be broken by fixing the finalization model that does not 
> distinguish finalization of the class from finalization of the 
> type-specific object.

A class is purely a static construct (just like privacy), while finalization 
is a purely dynamic construct. There's nothing to "distinguish" -- at 
runtime, all objects have a specific type. Finalization of a "class" can do 
nothing, as there is nothing dynamically to do with classes.

...
> Nothing will be broken by adding user-controlled aspect to access type to 
> kill any bookkeeping, any hidden lists, any dependencies.

Of course, the invariant that finalization always happens would be broken. 
That's a dead body issue with me, as it would destroy the ability to write 
reusable libraries.

Note that as with memory allocation, a well-designed reusable library needs 
to be agnostic as to how clients use it in tasks. It should work properly 
when used sequentially, with multiple tasks, with parallel blocks/loops, and 
anything yet to be invented. That means nothing active should be in the 
library anymore than that the library should be allocating any memory.

...
> I don't see how this will help with designing active objects, writing 
> servers for I/O protocols, handling pools of worker tasks.

IMHO, active objects are evil. Use something like Parafin for pools for 
worker tasks (or just a parallel loop with the task checking turned off). 
"terminate" works fine for most servers, that's what it was designed for. 
And both pools and servers are always going to be at library level, so the 
workarounds can be used if "terminate" doesn't work.

                      Randy.


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

* Re: Finalization of library level tasks
  2018-04-27 21:08                 ` Randy Brukardt
@ 2018-04-28  8:35                   ` Dmitry A. Kazakov
  2018-04-29 17:41                     ` AdaMagica
  2018-05-01  2:27                     ` Randy Brukardt
  0 siblings, 2 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-28  8:35 UTC (permalink / raw)


On 2018-04-27 23:08, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:pbuk07$9mf$1@gioia.aioe.org...
> ...
>> It is not reusable when the code depends on whether the object is declared
>> at the library level or not.
> 
> That only happens if you write broken code in the first place: tasks should
> never be embedded in objects.

You argued for reusable code and ended up with claiming encapsulation 
broken?

> It simply doesn't work (Ichbiah got that
> wrong). When you do so, termination is a problem, but so is avoiding
> deadlocks, race conditions, and the like.

These are imposed by the language not by the program logic.

> The entire nesting model of tasks
> in Ada is huge overkill and should never have happened - it's a huge amount
> of complexity for a value approaching zero. (Note that the first thing
> Ravenscar discards is the nesting model.)

while Ravescar itself is discarded by most applications.

>>>> There are dozens ways to fix the mess but there seems no interest at
>>>> all.
>>>
>>> Correction: there are dozens of ways to make a worse mess. There is no
>>> way
>>> to "fix" the issue, because any change to the rules just breaks in some
>>> other case. Or completely destroys the ability of ADTs to assume that
>>> finalization happens.
>>
>> Nothing will be broken by adding a Boolean attribute T'Completion_Awaited.
> 
> I've been told that would lead people to writing code which depends on race
> conditions. I'm not enough of an expert on tasking to try to disagree with
> people that are.

Better that code than no code at all. Presently no functional code can 
be written. In order to make an argument people who told you that must 
present a working code without alleged "race conditions". There is none, 
so the argument is void.

>> Nothing will be broken by fixing the finalization model that does not
>> distinguish finalization of the class from finalization of the
>> type-specific object.
> 
> A class is purely a static construct (just like privacy), while finalization
> is a purely dynamic construct. There's nothing to "distinguish" -- at
> runtime, all objects have a specific type.

Yes, but is irrelevant to the lifetime of the said objects. I am talking 
about objects [containing tasks].

> Finalization of a "class" can do
> nothing, as there is nothing dynamically to do with classes.

It is not finalization of the class of types, it is finalization of an 
instance of a class-wide object.

Each object of a tagged type is an instance of this type, and per 
language design that allows views, an instance of *all* ancestor types. 
Per same design, it is also an instance of all class-wide types rooted 
in the said types.

All these instances *must* be finalized: X of T1 <- T2 <- T3 must be 
finalized in the order

    Finalize (T1'Class (X));
    Finalize (T2'Class (X));
    Finalize (T3'Class (X));
    Finalize (T3 (X));  -- Only this is actually done
    Finalize (T2 (X));  -- These are left for the user
    Finalize (T1 (X));

> ...
>> Nothing will be broken by adding user-controlled aspect to access type to
>> kill any bookkeeping, any hidden lists, any dependencies.
> 
> Of course, the invariant that finalization always happens would be broken.
> That's a dead body issue with me, as it would destroy the ability to write
> reusable libraries.

No, it will only allow that. The same effect is customary achieved by 
declaring all access types at the library level. That makes the code 
more re-usable because it eliminates harmful checks. Pointers are too 
hot for any language to handle. Just leave them be and allow the 
programmer to do things right.

> Note that as with memory allocation, a well-designed reusable library needs
> to be agnostic as to how clients use it in tasks. It should work properly
> when used sequentially, with multiple tasks, with parallel blocks/loops, and
> anything yet to be invented. That means nothing active should be in the
> library anymore than that the library should be allocating any memory.

Just my point. If anybody knows how to make it working then the programmer.

> ...
>> I don't see how this will help with designing active objects, writing
>> servers for I/O protocols, handling pools of worker tasks.
> 
> IMHO, active objects are evil. Use something like Parafin for pools for
> worker tasks (or just a parallel loop with the task checking turned off).
> "terminate" works fine for most servers, that's what it was designed for.

Unless you need start and stop servers on demand.

> And both pools and servers are always going to be at library level, so the
> workarounds can be used if "terminate" doesn't work.

No, because servers are parts of the components that come and go. You 
are thinking about some sort of monolithic application which is a use 
case taking less and less percentage.

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


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

* Re: Finalization of library level tasks
  2018-04-28  8:35                   ` Dmitry A. Kazakov
@ 2018-04-29 17:41                     ` AdaMagica
  2018-04-29 19:36                       ` Dmitry A. Kazakov
  2018-05-01  2:27                     ` Randy Brukardt
  1 sibling, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-04-29 17:41 UTC (permalink / raw)


Am Samstag, 28. April 2018 10:35:34 UTC+2 schrieb Dmitry A. Kazakov:

> All these instances *must* be finalized: X of T1 <- T2 <- T3 must be 
> finalized in the order
> 
>     Finalize (T1'Class (X));
>     Finalize (T2'Class (X));
>     Finalize (T3'Class (X));
I don't have the slightest idea what should happen there.

>     Finalize (T3 (X));  -- Only this is actually done
Yes, this might be forgotten:
>     Finalize (T2 (X));  -- These are left for the user
>     Finalize (T1 (X));


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

* Re: Finalization of library level tasks
  2018-04-29 17:41                     ` AdaMagica
@ 2018-04-29 19:36                       ` Dmitry A. Kazakov
  2018-04-30 12:27                         ` AdaMagica
  0 siblings, 1 reply; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-29 19:36 UTC (permalink / raw)


On 2018-04-29 19:41, AdaMagica wrote:
> Am Samstag, 28. April 2018 10:35:34 UTC+2 schrieb Dmitry A. Kazakov:
> 
>> All these instances *must* be finalized: X of T1 <- T2 <- T3 must be
>> finalized in the order
>>
>>      Finalize (T1'Class (X));
>>      Finalize (T2'Class (X));
>>      Finalize (T3'Class (X));
> I don't have the slightest idea what should happen there.

Anything necessary to finalize the class-wide object. E.g. informing a 
task component to complete:

    type T1;
    task type Worker_Type (Parent : not null access T1'Class) is
       entry Shutdown;
    end Worker_Type;
    type T1 is new Ada.Finalization.Limited_Controlled with record
       Worker : Worker_Type;
    end record;

    procedure Finalize (Object : in out T1'Class) is
    begin
       Object.Worker.Shutdown;
    end Finalize;

Differently to type-specific Finalize in a class-wide Finalize it is OK 
to make dispatching calls.

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


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

* Re: Finalization of library level tasks
  2018-04-29 19:36                       ` Dmitry A. Kazakov
@ 2018-04-30 12:27                         ` AdaMagica
  2018-04-30 13:03                           ` Dmitry A. Kazakov
  2018-04-30 16:52                           ` Jeffrey R. Carter
  0 siblings, 2 replies; 89+ messages in thread
From: AdaMagica @ 2018-04-30 12:27 UTC (permalink / raw)


Am Sonntag, 29. April 2018 21:36:37 UTC+2 schrieb Dmitry A. Kazakov:
> On 2018-04-29 19:41, AdaMagica wrote:
> > Am Samstag, 28. April 2018 10:35:34 UTC+2 schrieb Dmitry A. Kazakov:
> > 
> >> All these instances *must* be finalized: X of T1 <- T2 <- T3 must be
> >> finalized in the order
> >>
> >>      Finalize (T1'Class (X));
> >>      Finalize (T2'Class (X));
> >>      Finalize (T3'Class (X));
> > I don't have the slightest idea what should happen there.
> 
> Anything necessary to finalize the class-wide object. E.g. informing a 
> task component to complete:

What is this "anything"? I do not see a connection from class-wide type to its task components. What is the connection of class-wide type to other components? What's the difference between task components and other (perhaps limited) components? What does class-wide finalize do to those other components?

In short: If you look inside a class-wide object, you'll find inside an object of a specific type within this class (as Randy said in a previous post). What's the property of this specific object seen as a class-wide object that's not a property of the specific object?

(I have problems expressing what I want to say.I

>     type T1;
>     task type Worker_Type (Parent : not null access T1'Class) is
>        entry Shutdown;
>     end Worker_Type;
>     type T1 is new Ada.Finalization.Limited_Controlled with record
>        Worker : Worker_Type;
>     end record;
> 
>     procedure Finalize (Object : in out T1'Class) is
>     begin
>        Object.Worker.Shutdown;
>     end Finalize;
> 
> Differently to type-specific Finalize in a class-wide Finalize it is OK 
> to make dispatching calls.


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

* Re: Finalization of library level tasks
  2018-04-30 12:27                         ` AdaMagica
@ 2018-04-30 13:03                           ` Dmitry A. Kazakov
  2018-04-30 16:52                           ` Jeffrey R. Carter
  1 sibling, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-30 13:03 UTC (permalink / raw)


On 2018-04-30 14:27, AdaMagica wrote:
> Am Sonntag, 29. April 2018 21:36:37 UTC+2 schrieb Dmitry A. Kazakov:
>> On 2018-04-29 19:41, AdaMagica wrote:
>>> Am Samstag, 28. April 2018 10:35:34 UTC+2 schrieb Dmitry A. Kazakov:
>>>
>>>> All these instances *must* be finalized: X of T1 <- T2 <- T3 must be
>>>> finalized in the order
>>>>
>>>>       Finalize (T1'Class (X));
>>>>       Finalize (T2'Class (X));
>>>>       Finalize (T3'Class (X));
>>> I don't have the slightest idea what should happen there.
>>
>> Anything necessary to finalize the class-wide object. E.g. informing a
>> task component to complete:
> 
> What is this "anything"?

Anything the program logic requires for a class-wide finalization to be 
done.

> I do not see a connection from class-wide type to its task components. What is the connection of class-wide type to other components? What's the difference between task components and other (perhaps limited) components? What does class-wide finalize do to those other components?

The reason why the object's type-specific finalization waits for all 
component tasks to complete do not apply to class-wide finalization of 
the same object.

When you have a task component with a Rosen's trick access discriminant 
T1'Class in the object of T1, without waiting for the task, you may 
finalize T3 and T2 and have the task running with a T1'Class object 
partially finalized. This is why the task must complete *before* 
finalization of T1, T2, T3 etc.

There is no problem not to wait for the task during finalization of 
T1'Class because at this point T1, T2, T3 views of the object are all 
intact. You can safely dispatch on the task discriminant to any target type.

 From T1'Class finalization will shutdown the task and everything will 
be fine, deadlock broken.

Similarly. Let the design require calling an abstract or overridden 
operation upon finalization via dispatch. You cannot do that in the 
Finalize of T1. The reason is exactly same as with the task completion: 
the object is partially finalized in the type T3 where dispatch may lead 
to. But you can safely dispatch in the Finalize of T1'Class, because T3 
view is still there.

> In short: If you look inside a class-wide object, you'll find inside an object of a specific type within this class (as Randy said in a previous post). What's the property of this specific object seen as a class-wide object that's not a property of the specific object?

Simple. All properties of the class, overridden operations, in 
particular. Primitive operations dispatch on a class-wide object, they 
do not on a type-specific object.
  --
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

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

* Re: Finalization of library level tasks
  2018-04-30 12:27                         ` AdaMagica
  2018-04-30 13:03                           ` Dmitry A. Kazakov
@ 2018-04-30 16:52                           ` Jeffrey R. Carter
  2018-04-30 17:06                             ` Dmitry A. Kazakov
  2018-05-01  9:17                             ` AdaMagica
  1 sibling, 2 replies; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-04-30 16:52 UTC (permalink / raw)


On 04/30/2018 02:27 PM, AdaMagica wrote:
> 
> In short: If you look inside a class-wide object, you'll find inside an object of a specific type within this class (as Randy said in a previous post). What's the property of this specific object seen as a class-wide object that's not a property of the specific object?

About the only difference is that operations dispatch with a class-wide 
parameter and don't with a parameter of a specific type.

Op (Parent'Class (X) );

and

Op (X);

end up executing the same code. That Kazakov says they don't is probably an 
indication that he, as he often does, is not talking about Ada.

-- 
Jeff Carter
"You couldn't catch clap in a brothel, silly English K...niggets."
Monty Python & the Holy Grail
19

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

* Re: Finalization of library level tasks
  2018-04-30 16:52                           ` Jeffrey R. Carter
@ 2018-04-30 17:06                             ` Dmitry A. Kazakov
  2018-05-01  9:17                             ` AdaMagica
  1 sibling, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-04-30 17:06 UTC (permalink / raw)


On 2018-04-30 18:52, Jeffrey R. Carter wrote:
> On 04/30/2018 02:27 PM, AdaMagica wrote:
>>
>> In short: If you look inside a class-wide object, you'll find inside 
>> an object of a specific type within this class (as Randy said in a 
>> previous post). What's the property of this specific object seen as a 
>> class-wide object that's not a property of the specific object?
> 
> About the only difference is that operations dispatch with a class-wide 
> parameter and don't with a parameter of a specific type.
> 
> Op (Parent'Class (X) );
> 
> and
> 
> Op (X);
> 
> end up executing the same code.

Wrong. Consider this:

    type T1 is tagged null record;
    procedure Op (X : in out T1);

    type T2 is new T1 with null record;
    procedure Op (X : in out T2);

    type T3 is new T2 with null record;
    procedure Op (X : in out T3);

Now this procedure:

    procedure Finalize (X : in out T2);

if you pass T3 to it then

    procedure Finalize (X : in out T2) is
    begin
       Op (T1'Class (X)); -- Dispatches to Op (T3 (X))
       Op (X); -- Statically calls to Op (T2 (X))

The code is not same because dispatch can cross the actual type border 
and go a descendant. This is also why dispatching in Finalize should 
have been illegal. All re-dispatch should have been illegal because it 
breaks typing.

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

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

* Re: Finalization of library level tasks
  2018-04-28  8:35                   ` Dmitry A. Kazakov
  2018-04-29 17:41                     ` AdaMagica
@ 2018-05-01  2:27                     ` Randy Brukardt
  2018-05-01  6:59                       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 89+ messages in thread
From: Randy Brukardt @ 2018-05-01  2:27 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pc1bok$iqf$1@gioia.aioe.org...
> On 2018-04-27 23:08, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:pbuk07$9mf$1@gioia.aioe.org...
>> ...
>>> It is not reusable when the code depends on whether the object is 
>>> declared
>>> at the library level or not.
>>
>> That only happens if you write broken code in the first place: tasks 
>> should
>> never be embedded in objects.
>
> You argued for reusable code and ended up with claiming encapsulation 
> broken?

Encapusulation of threads is a nonsense idea. Encapsulation is a 
compile-time concept that completely disappears at runtime. A thread (a task 
or tasklet) is a run-time entity with little compile-time presence. Trying 
to encapsulate that makes about as much sense as trying to hide memory 
allocation (which also doesn't really work).

In today's environment, one has to keep the threads at the highest possible 
level of a program, otherwise you will drown in overhead. Sticking threads 
inside of things is exactly opposed to that. I expect that in a future 
environment, threads will be assigned by the compiler, and again writing 
them explicitly is opposed to that. (And if you're not concerned about 
performance, please don't use them at all - the disadvantages outweight any 
possible advantages.) I don't see a reasonable scenario where hiding threads 
is ever going to be a good idea. It might work on some compilation system, 
but it will never be that portable.

                          Randy.



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

* Re: Finalization of library level tasks
  2018-05-01  2:27                     ` Randy Brukardt
@ 2018-05-01  6:59                       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-01  6:59 UTC (permalink / raw)


On 2018-05-01 04:27, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:pc1bok$iqf$1@gioia.aioe.org...
>> On 2018-04-27 23:08, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:pbuk07$9mf$1@gioia.aioe.org...
>>> ...
>>>> It is not reusable when the code depends on whether the object is
>>>> declared
>>>> at the library level or not.
>>>
>>> That only happens if you write broken code in the first place: tasks
>>> should
>>> never be embedded in objects.
>>
>> You argued for reusable code and ended up with claiming encapsulation
>> broken?
> 
> Encapusulation of threads is a nonsense idea. Encapsulation is a
> compile-time concept that completely disappears at runtime.

So is the data type and many other things. It is called abstraction, 
which you want to throw overboard together with encapsulation.

> A thread (a task
> or tasklet) is a run-time entity with little compile-time presence. Trying
> to encapsulate that makes about as much sense as trying to hide memory
> allocation (which also doesn't really work).

Hiding memory allocation works perfectly well. Ada is a proof of that. I 
can return String from a subprogram.

> In today's environment, one has to keep the threads at the highest possible
> level of a program, otherwise you will drown in overhead.

No. It is a perverse design with exposes implementation. There is no 
reason for the user of a complex communication object to know how many 
OS threads the thing uses.

> Sticking threads
> inside of things is exactly opposed to that. I expect that in a future
> environment, threads will be assigned by the compiler, and again writing
> them explicitly is opposed to that. (And if you're not concerned about
> performance, please don't use them at all - the disadvantages outweight any
> possible advantages.) I don't see a reasonable scenario where hiding threads
> is ever going to be a good idea. It might work on some compilation system,
> but it will never be that portable.

It is 100% portable, our middleware which is 100% Ada runs under 
Windows, Linux, VxWorks and exposes no threads to the user. Why should 
he ever know which threads are used by an EtherCAT master, by CANOpen 
master, by MODBUS client etc?

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


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

* Re: Finalization of library level tasks
  2018-04-30 16:52                           ` Jeffrey R. Carter
  2018-04-30 17:06                             ` Dmitry A. Kazakov
@ 2018-05-01  9:17                             ` AdaMagica
  2018-05-01  9:40                               ` Dmitry A. Kazakov
  2018-05-01 11:18                               ` Jeffrey R. Carter
  1 sibling, 2 replies; 89+ messages in thread
From: AdaMagica @ 2018-05-01  9:17 UTC (permalink / raw)


Am Montag, 30. April 2018 18:52:21 UTC+2 schrieb Jeffrey R. Carter:
> On 04/30/2018 02:27 PM, AdaMagica wrote:
> > 
> > In short: If you look inside a class-wide object, you'll find inside an object of a specific type within this class (as Randy said in a previous post). What's the property of this specific object seen as a class-wide object that's not a property of the specific object?
> 
> About the only difference is that operations dispatch with a class-wide 
> parameter and don't with a parameter of a specific type.
> 
> Op (Parent'Class (X) );
> 
> and
> 
> Op (X);
> 
> end up executing the same code. That Kazakov says they don't is probably an 
> indication that he, as he often does, is not talking about Ada.

Of course he's not talking about current Ada, he's talking about an Ada as he would like her to be as there is no Finalize'Class he would like to have.
But he is correct on this example you gave: With redispatch, OP(X) and OP(Parent'Class(X)) are not the same.

What I do not understand is the model he wants to have for Finalize'Class. The idea is quite complicated because of Rosen's trick, redispatch etc. Dmitry only posts some fragmentary ideas without ever giving a complete elaboration. So we, if we try to understand and argue with him, have to imagine and guess what the hell he has in mind.

As in this (incomplete) post of his:
> Now this procedure:
>    procedure Finalize (X : in out T2);
> if you pass T3 to it then

You cannot directly pass an x of type T3 to this Finalize. You can make his example work if you add quite some more code. His examples like this one, if really current Ada (and not some wishful version), are rarely complete.


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

* Re: Finalization of library level tasks
  2018-05-01  9:17                             ` AdaMagica
@ 2018-05-01  9:40                               ` Dmitry A. Kazakov
  2018-05-01 11:18                               ` Jeffrey R. Carter
  1 sibling, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-01  9:40 UTC (permalink / raw)


On 2018-05-01 11:17, AdaMagica wrote:

> What I do not understand is the model he wants to have for Finalize'Class.

I can elaborate if you explain what you understand under "model".

> The idea is quite complicated because of Rosen's trick, redispatch etc.

No, the idea is simple - objects of any type must allow user-defined 
finalization (and initialization).

Rosen's trick and re-dispatch are not my ideas but existing Ada 
features. The latter has huge issues with type consistency which has 
negative effect on finalization.

> Dmitry only posts some fragmentary ideas without ever giving a complete elaboration. So we, if we try to understand and argue with him, have to imagine and guess what the hell he has in mind.

I am ready to answer any questions.

Normally all discussions deviate straight to "Aber, meine Herren, das 
ist keine Physik", or to denial of any software design concepts from ADT 
to nested tasks and then the problem itself: nobody needs X (substitute 
"finalization", "task component" etc).

> You cannot directly pass an x of type T3 to this Finalize. You can make his example work if you add quite some more code. His examples like this one, if really current Ada (and not some wishful version), are rarely complete.

Yes, it is always pseudo-code I use in such discussions. If I made it 
precise, people would critique syntax issues.

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


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

* Re: Finalization of library level tasks
  2018-05-01  9:17                             ` AdaMagica
  2018-05-01  9:40                               ` Dmitry A. Kazakov
@ 2018-05-01 11:18                               ` Jeffrey R. Carter
  2018-05-01 11:27                                 ` Dmitry A. Kazakov
  2018-05-01 15:54                                 ` Niklas Holsti
  1 sibling, 2 replies; 89+ messages in thread
From: Jeffrey R. Carter @ 2018-05-01 11:18 UTC (permalink / raw)


On 05/01/2018 11:17 AM, AdaMagica wrote:
> 
> But he is correct on this example you gave: With redispatch, OP(X) and OP(Parent'Class(X)) are not the same.

If you use redispatching then you get what you deserve.

-- 
Jeff Carter
"My little plum, I am like Robin Hood. I take from
the rich, and I give to the poor. ... Us poor."
Poppy
96

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

* Re: Finalization of library level tasks
  2018-05-01 11:18                               ` Jeffrey R. Carter
@ 2018-05-01 11:27                                 ` Dmitry A. Kazakov
  2018-05-01 15:54                                 ` Niklas Holsti
  1 sibling, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-01 11:27 UTC (permalink / raw)


On 2018-05-01 13:18, Jeffrey R. Carter wrote:
> On 05/01/2018 11:17 AM, AdaMagica wrote:
>>
>> But he is correct on this example you gave: With redispatch, OP(X) and 
>> OP(Parent'Class(X)) are not the same.
> 
> If you use redispatching then you get what you deserve.

The first step in understanding the importance of having class-wide 
finalization and initialization ...

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


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

* Re: Finalization of library level tasks
  2018-05-01 11:18                               ` Jeffrey R. Carter
  2018-05-01 11:27                                 ` Dmitry A. Kazakov
@ 2018-05-01 15:54                                 ` Niklas Holsti
  2018-05-02 14:34                                   ` AdaMagica
  1 sibling, 1 reply; 89+ messages in thread
From: Niklas Holsti @ 2018-05-01 15:54 UTC (permalink / raw)


On 18-05-01 14:18 , Jeffrey R. Carter wrote:
> On 05/01/2018 11:17 AM, AdaMagica wrote:
>>
>> But he is correct on this example you gave: With redispatch, OP(X) and
>> OP(Parent'Class(X)) are not the same.
>
> If you use redispatching then you get what you deserve.

Which can be exactly what you want to achieve!

(Obligatory dissenting voice in favour of occasional redispatching, to 
avoid the appearance that redispatching is universally abhorred.)

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


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

* Re: Finalization of library level tasks
  2018-05-01 15:54                                 ` Niklas Holsti
@ 2018-05-02 14:34                                   ` AdaMagica
  2018-05-02 14:50                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 89+ messages in thread
From: AdaMagica @ 2018-05-02 14:34 UTC (permalink / raw)


Am Dienstag, 1. Mai 2018 17:54:02 UTC+2 schrieb Niklas Holsti:
> On 18-05-01 14:18 , Jeffrey R. Carter wrote:
> > On 05/01/2018 11:17 AM, AdaMagica wrote:
> >>
> >> But he is correct on this example you gave: With redispatch, OP(X) and
> >> OP(Parent'Class(X)) are not the same.
> >
> > If you use redispatching then you get what you deserve.
> 
> Which can be exactly what you want to achieve!
> 
> (Obligatory dissenting voice in favour of occasional redispatching, to 
> avoid the appearance that redispatching is universally abhorred.)

Yes, there are situations where redispatching is essential. I've once come into this situation.

But I would say, do not use redispatch in Initialize, Adjust, Finalize. This is strong advice. Think thrice if you think you need it.


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

* Re: Finalization of library level tasks
  2018-05-02 14:34                                   ` AdaMagica
@ 2018-05-02 14:50                                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 89+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-02 14:50 UTC (permalink / raw)


On 02/05/2018 16:34, AdaMagica wrote:
> Am Dienstag, 1. Mai 2018 17:54:02 UTC+2 schrieb Niklas Holsti:
>> On 18-05-01 14:18 , Jeffrey R. Carter wrote:
>>> On 05/01/2018 11:17 AM, AdaMagica wrote:
>>>>
>>>> But he is correct on this example you gave: With redispatch, OP(X) and
>>>> OP(Parent'Class(X)) are not the same.
>>>
>>> If you use redispatching then you get what you deserve.
>>
>> Which can be exactly what you want to achieve!
>>
>> (Obligatory dissenting voice in favour of occasional redispatching, to
>> avoid the appearance that redispatching is universally abhorred.)
> 
> Yes, there are situations where redispatching is essential. I've once come into this situation.

They are all wrong, either due to design error or language problem.

In particular in Ada there is no partial override. Usually re-dispatch 
is required because there no way to define a prologue or epilogue of a 
primitive operation. So if you have this:

    procedure Foo (X : in out T) is
    begin
       ... Do this
       Baz (T'Class (X));
       ... Do that
    end Foo;

That is the language problem which does not allow T to define Foo's 
prologue and epilogue not to be overridden:

    procedure Foo'Prologue (X : in out T) is
    begin
       ... Do this
    end Foo'Prologue;

    procedure Foo (X : in out T) is null;

    procedure Foo'Epilogue (X : in out T) is
    begin
       ... Do that
    end Foo'Epilogue;

Then Baz would be a plain overriding of Foo, no re-dispatch.

BTW, Finalize must have been an epilogue, and Initialize a prologue.

> But I would say, do not use redispatch in Initialize, Adjust, Finalize. This is strong advice. Think thrice if you think you need it.

It is always wrong to dispatch from Initialize and Finalize, no need to 
even think about it. As I said before it must be plain dispatch from 
class-wide Finalize/Initialize/Adjust when all type-specific Finalizes 
are complete and Initializes not yet called.

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


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

end of thread, other threads:[~2018-05-02 14:50 UTC | newest]

Thread overview: 89+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-15 13:40 Finalization of library level tasks Dmitry A. Kazakov
2018-04-15 14:02 ` Jeffrey R. Carter
2018-04-15 14:12   ` Dmitry A. Kazakov
2018-04-15 14:54     ` Jeffrey R. Carter
2018-04-15 15:15       ` Dmitry A. Kazakov
2018-04-15 15:46         ` AdaMagica
2018-04-15 15:53           ` Dmitry A. Kazakov
2018-04-15 17:17           ` AdaMagica
2018-04-15 17:40             ` Dmitry A. Kazakov
2018-04-15 19:32               ` Egil H H
2018-04-15 20:09                 ` Dmitry A. Kazakov
2018-04-25 23:49                   ` Randy Brukardt
2018-04-16  5:19               ` J-P. Rosen
2018-04-16  7:30                 ` Dmitry A. Kazakov
2018-04-16  7:55                   ` J-P. Rosen
2018-04-16  8:13                     ` Dmitry A. Kazakov
2018-04-16  8:32                       ` J-P. Rosen
2018-04-16 15:26                         ` Dmitry A. Kazakov
2018-04-17  9:51                           ` AdaMagica
2018-04-17 12:31                             ` Dmitry A. Kazakov
2018-04-17 15:37                               ` Jeffrey R. Carter
2018-04-17 15:57                                 ` Dmitry A. Kazakov
2018-04-17 20:16                                   ` Jeffrey R. Carter
2018-04-17 20:59                                     ` Dmitry A. Kazakov
2018-04-18  5:20                                       ` J-P. Rosen
2018-04-17 20:55                                   ` J-P. Rosen
2018-04-17 21:23                                     ` Dmitry A. Kazakov
2018-04-18  5:26                                       ` J-P. Rosen
2018-04-26  0:02                                         ` Randy Brukardt
2018-04-18  8:06                               ` AdaMagica
2018-04-18  8:25                                 ` Dmitry A. Kazakov
2018-04-18  8:52                                   ` Egil H H
2018-04-18  9:58                                     ` Dmitry A. Kazakov
2018-04-18 11:33                                       ` J-P. Rosen
2018-04-18 11:58                                         ` Dmitry A. Kazakov
2018-04-18 12:00                                           ` J-P. Rosen
2018-04-18 12:25                                             ` Dmitry A. Kazakov
2018-04-18 13:51                                               ` J-P. Rosen
2018-04-18 14:12                                                 ` Dmitry A. Kazakov
2018-04-18 14:52                                                   ` J-P. Rosen
2018-04-18 15:04                                                     ` Dmitry A. Kazakov
2018-04-18 20:26                                                       ` AdaMagica
2018-04-18 21:00                                                         ` Dmitry A. Kazakov
2018-04-18 20:40                                                     ` AdaMagica
2018-04-19  7:34                                                       ` Simon Wright
2018-04-18 21:29                                                     ` J-P. Rosen
2018-04-19  7:32                                                       ` Dmitry A. Kazakov
2018-04-26  0:04                                       ` Randy Brukardt
2018-04-26  8:56                                         ` Dmitry A. Kazakov
2018-04-26 22:10                                           ` Randy Brukardt
2018-04-27  4:48                                             ` J-P. Rosen
2018-04-27 20:52                                               ` Randy Brukardt
2018-04-17 11:16                           ` J-P. Rosen
2018-04-17 12:47                             ` Dmitry A. Kazakov
2018-04-17 14:08                               ` J-P. Rosen
2018-04-17 14:47                                 ` Dmitry A. Kazakov
2018-04-17 22:00                                   ` Robert A Duff
2018-04-18  7:25                                     ` Dmitry A. Kazakov
2018-04-25 23:54                           ` Randy Brukardt
2018-04-26 16:22                             ` Jeffrey R. Carter
2018-04-26 16:43                               ` Dmitry A. Kazakov
2018-04-26 20:19                                 ` J-P. Rosen
2018-04-16  9:19               ` AdaMagica
2018-04-16 15:15                 ` Dmitry A. Kazakov
2018-04-19 20:39           ` G. B.
2018-04-20  7:27             ` Dmitry A. Kazakov
2018-04-25 23:46         ` Randy Brukardt
2018-04-26  9:03           ` Dmitry A. Kazakov
2018-04-26 22:25             ` Randy Brukardt
2018-04-27  7:37               ` Dmitry A. Kazakov
2018-04-27  8:32                 ` AdaMagica
2018-04-27  8:57                   ` Dmitry A. Kazakov
2018-04-27 21:08                 ` Randy Brukardt
2018-04-28  8:35                   ` Dmitry A. Kazakov
2018-04-29 17:41                     ` AdaMagica
2018-04-29 19:36                       ` Dmitry A. Kazakov
2018-04-30 12:27                         ` AdaMagica
2018-04-30 13:03                           ` Dmitry A. Kazakov
2018-04-30 16:52                           ` Jeffrey R. Carter
2018-04-30 17:06                             ` Dmitry A. Kazakov
2018-05-01  9:17                             ` AdaMagica
2018-05-01  9:40                               ` Dmitry A. Kazakov
2018-05-01 11:18                               ` Jeffrey R. Carter
2018-05-01 11:27                                 ` Dmitry A. Kazakov
2018-05-01 15:54                                 ` Niklas Holsti
2018-05-02 14:34                                   ` AdaMagica
2018-05-02 14:50                                     ` Dmitry A. Kazakov
2018-05-01  2:27                     ` Randy Brukardt
2018-05-01  6:59                       ` 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