comp.lang.ada
 help / color / mirror / Atom feed
* Deallocating records with task type fields.
@ 2005-12-09 22:49 Gene
  2005-12-10  7:16 ` Jeffrey R. Carter
  2005-12-10 14:10 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 11+ messages in thread
From: Gene @ 2005-12-09 22:49 UTC (permalink / raw)


Please consider these declarations for a task with some task local
data:

   type Listener_Type;

   task type Listener_Task_Type(Env : access Listener_Type);

   type Listener_Type is
      record
         Port : Positive;
         Executive : Listener_Task_Type(Listener_Type'Access);
      end record;

With this, the executive task has access to the task local environment
exemplified here by a port number.

Here are the questions:

1.  Is this a good idiom for implementing task local data, or is there
some other preferable method?
2.  As I read the ALRM it is incorrect to deallocate a Listener_Type
object until the Executive task has exited.  What is a good idiomatic
way for the Executive to deallocate its own task local storage just
before it exits and without causing a race condition?  [The only ways I
can come up with seem like excessive machinery.]

Thanks in advance.




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

* Re: Deallocating records with task type fields.
  2005-12-09 22:49 Deallocating records with task type fields Gene
@ 2005-12-10  7:16 ` Jeffrey R. Carter
  2005-12-10 11:45   ` Simon Wright
  2005-12-10 14:10 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 11+ messages in thread
From: Jeffrey R. Carter @ 2005-12-10  7:16 UTC (permalink / raw)


Gene wrote:
> Please consider these declarations for a task with some task local
> data:
> 
>    type Listener_Type;
> 
>    task type Listener_Task_Type(Env : access Listener_Type);
> 
>    type Listener_Type is
>       record
>          Port : Positive;
>          Executive : Listener_Task_Type(Listener_Type'Access);
>       end record;
> 
> With this, the executive task has access to the task local environment
> exemplified here by a port number.
> 
> Here are the questions:
> 
> 1.  Is this a good idiom for implementing task local data, or is there
> some other preferable method?

For a case like this, I'd probably suggest

task type Listener (Port : Positive);

More generally, how do you create an object of Listener_Type and ensure that you 
assign a value to its Port component before its Executive accesses that component?

An alternative is to not embed the task in its data:

task type T (Environment : access Environment_Data);

This requires that you have the data available when you create the task object.

> 2.  As I read the ALRM it is incorrect to deallocate a Listener_Type
> object until the Executive task has exited.  What is a good idiomatic
> way for the Executive to deallocate its own task local storage just
> before it exits and without causing a race condition?  [The only ways I
> can come up with seem like excessive machinery.]

The best way is not to use allocation, and thus not need deallocation.

If you do need to allocate the data, you can use the access type for that 
instead of an anonymous access type:

task type T (Environment : Data_Ptr);

and the task could make a copy of Environment and deallocate that. I would not 
generally advise such an approach.

-- 
Jeff Carter
"I like it when the support group complains that they have
insufficient data on mean time to repair bugs in Ada software."
Robert I. Eachus
91



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

* Re: Deallocating records with task type fields.
  2005-12-10  7:16 ` Jeffrey R. Carter
@ 2005-12-10 11:45   ` Simon Wright
  0 siblings, 0 replies; 11+ messages in thread
From: Simon Wright @ 2005-12-10 11:45 UTC (permalink / raw)


"Jeffrey R. Carter" <spam@spam.com> writes:

> Gene wrote:

>> 2.  As I read the ALRM it is incorrect to deallocate a
>> Listener_Type object until the Executive task has exited.  What is
>> a good idiomatic way for the Executive to deallocate its own task
>> local storage just before it exits and without causing a race
>> condition?  [The only ways I can come up with seem like excessive
>> machinery.]
>
> The best way is not to use allocation, and thus not need
> deallocation.

True, but there's still the problem of freeing the resource abstracted
in Gene's original by the Listener_Type object (that is, the port).



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

* Re: Deallocating records with task type fields.
  2005-12-09 22:49 Deallocating records with task type fields Gene
  2005-12-10  7:16 ` Jeffrey R. Carter
@ 2005-12-10 14:10 ` Dmitry A. Kazakov
  2005-12-11  4:06   ` Gene
  2005-12-11  5:02   ` Gene
  1 sibling, 2 replies; 11+ messages in thread
From: Dmitry A. Kazakov @ 2005-12-10 14:10 UTC (permalink / raw)


On 9 Dec 2005 14:49:14 -0800, Gene wrote:

> Please consider these declarations for a task with some task local
> data:
> 
>    type Listener_Type;
> 
>    task type Listener_Task_Type(Env : access Listener_Type);
> 
>    type Listener_Type is
>       record
>          Port : Positive;
>          Executive : Listener_Task_Type(Listener_Type'Access);
>       end record;
> 
> With this, the executive task has access to the task local environment
> exemplified here by a port number.
> 
> Here are the questions:
> 
> 1.  Is this a good idiom for implementing task local data, or is there
> some other preferable method?
>
> 2.  As I read the ALRM it is incorrect to deallocate a Listener_Type
> object until the Executive task has exited.  What is a good idiomatic
> way for the Executive to deallocate its own task local storage just
> before it exits and without causing a race condition?  [The only ways I
> can come up with seem like excessive machinery.] 

Not really. If data are local then it is task's responsibility to maintain 
them. Your design inverses this: the life span of environment must enclose 
one of the task. I presume that you are trying to bring parameters of a 
task and the local data under one roof. It can work in only simple cases.

Possible alternatives:

1. Local things are on the task's stack. Parameters are passed through 
discriminants.

2. Same as above, but parameters are passed via Start entry point

3. Task is encapsulated into a controlled object which has the parameters 
and data. A pragmatic way to do this is to have a task pointer as a 
component, so that task might be allocated separately from the object. 
Otherwise, there will be problems with initialization and finalization.

4. Smart pointers with reference counting. If you want to create a resource 
(like local data) for a task in one place and collect it in another (upon 
task exit) then smart pointers is a safe way to do it.

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



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

* Re: Deallocating records with task type fields.
  2005-12-10 14:10 ` Dmitry A. Kazakov
@ 2005-12-11  4:06   ` Gene
  2005-12-11 11:50     ` Dmitry A. Kazakov
  2005-12-12 22:03     ` Randy Brukardt
  2005-12-11  5:02   ` Gene
  1 sibling, 2 replies; 11+ messages in thread
From: Gene @ 2005-12-11  4:06 UTC (permalink / raw)


Many thanks.  I certainly could have picked a better of example that
Port for data.

In fact the real environment record also has a protected output queue
with procedures to get data from the queue that the Listener has placed
there.  That's the interesting case because other tasks need to call
functions that can touch the queue.  I couldn't see a good way to
declare the queue on the task stack and yet allow other tasks to get
things from it.

So before the current method I indeed implemented the shared queue by
passing it to the Listener with a discriminant (your 2.). Also tried a
Start entry (your 3.).  In all the method above is by far the cleanest
because the whole Listener is a single type that acts like a functional
closure.  This matter of handling deallocation when the executive task
exits is the only rough edge.

As the name implies, the application is a TCP network listener in a
multi-node graphics application.  Listeners are allocated as needed and
exit when their corresponding connections are terminated, either
normally or due to an error condition.  When this happens, we want the
Listener to arrange for its own deallocation.

Currently I just have the Executive put its enclosing Listener on a
system-wide "dead listener" queue.  There is a procedure that traverses
the queue to deallocate any listeners whose executive tasks have indeed
terminated.  This is called whenever a new Listener is allocated.  This
works fine (although it needs Real Time Extensions).  I wondered if
there was a simpler way.

In fact just for fun I also tried having the Listener call
Unchecked_Deallocation itself just before exiting (i.e. the task was
deallocating its own context!).  And with GNAT running under both
Solaris and Windows it never caused a problem.




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

* Re: Deallocating records with task type fields.
  2005-12-10 14:10 ` Dmitry A. Kazakov
  2005-12-11  4:06   ` Gene
@ 2005-12-11  5:02   ` Gene
  1 sibling, 0 replies; 11+ messages in thread
From: Gene @ 2005-12-11  5:02 UTC (permalink / raw)


Many thanks.  I certainly could have picked a better of example that
Port for data.

In fact the real environment record also has a protected output queue
with procedures to get data from the queue that the Listener has placed
there.  That's the interesting case because other tasks need to call
functions that can touch the queue.  I couldn't see a good way to
declare the queue on the task stack and yet allow other tasks to get
things from it.

So before the current method I indeed implemented the shared queue by
passing it to the Listener with a discriminant (your 2.). Also tried a
Start entry (your 3.).  In all the method above is by far the cleanest
because the whole Listener is a single type that acts like a functional
closure.  This matter of handling deallocation when the executive task
exits is the only rough edge.

As the name implies, the application is a TCP network listener in a
multi-node graphics application.  Listeners are allocated as needed and
exit when their corresponding connections are terminated, either
normally or due to an error condition.  When this happens, we want the
Listener to arrange for its own deallocation.

Currently I just have the Executive put its enclosing Listener on a
system-wide "dead listener" queue.  There is a procedure that traverses
the queue to deallocate any listeners whose executive tasks have indeed
terminated.  This is called whenever a new Listener is allocated.  This
works fine (although it needs Real Time Extensions).  I wondered if
there was a simpler way.

In fact just for fun I also tried having the Listener call
Unchecked_Deallocation itself just before exiting (i.e. the task was
deallocating its own context!).  And with GNAT running under both
Solaris and Windows it never caused a problem.




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

* Re: Deallocating records with task type fields.
  2005-12-11  4:06   ` Gene
@ 2005-12-11 11:50     ` Dmitry A. Kazakov
  2005-12-12 11:32       ` Alex R. Mosteo
  2005-12-12 22:03     ` Randy Brukardt
  1 sibling, 1 reply; 11+ messages in thread
From: Dmitry A. Kazakov @ 2005-12-11 11:50 UTC (permalink / raw)


On 10 Dec 2005 20:06:46 -0800, Gene wrote:

> Many thanks.  I certainly could have picked a better of example that
> Port for data.
> 
> In fact the real environment record also has a protected output queue
> with procedures to get data from the queue that the Listener has placed
> there.  That's the interesting case because other tasks need to call
> functions that can touch the queue.  I couldn't see a good way to
> declare the queue on the task stack and yet allow other tasks to get
> things from it.
> 
> So before the current method I indeed implemented the shared queue by
> passing it to the Listener with a discriminant (your 2.). Also tried a
> Start entry (your 3.).  In all the method above is by far the cleanest
> because the whole Listener is a single type that acts like a functional
> closure.  This matter of handling deallocation when the executive task
> exits is the only rough edge.
> 
> As the name implies, the application is a TCP network listener in a
> multi-node graphics application.  Listeners are allocated as needed and
> exit when their corresponding connections are terminated, either
> normally or due to an error condition.  When this happens, we want the
> Listener to arrange for its own deallocation.
> 
> Currently I just have the Executive put its enclosing Listener on a
> system-wide "dead listener" queue.  There is a procedure that traverses
> the queue to deallocate any listeners whose executive tasks have indeed
> terminated.  This is called whenever a new Listener is allocated.  This
> works fine (although it needs Real Time Extensions).  I wondered if
> there was a simpler way.
> 
> In fact just for fun I also tried having the Listener call
> Unchecked_Deallocation itself just before exiting (i.e. the task was
> deallocating its own context!).  And with GNAT running under both
> Solaris and Windows it never caused a problem.

Yes, AFAIK it works with GNAT.

But the real question is if a listener can be accessed outside the task,
then there is a danger that the task could prematurely deallocate it. Thus
there must be somebody responsible for the life span of listener. Your
variant with "dead listener" queue is nothing but a GC. One could also use
reference counting GC. In any case it is global GC, which is responsible.
The problem with this is what is a listener object worth when the task is
dead? If a task life span is shorter then this state change should be
visible for users of listeners. This devaluates the idea of GC. If users
are aware of state change, they could also take care of deallocation of
listeners.

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



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

* Re: Deallocating records with task type fields.
  2005-12-11 11:50     ` Dmitry A. Kazakov
@ 2005-12-12 11:32       ` Alex R. Mosteo
  2005-12-12 18:30         ` Pascal Obry
  0 siblings, 1 reply; 11+ messages in thread
From: Alex R. Mosteo @ 2005-12-12 11:32 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> On 10 Dec 2005 20:06:46 -0800, Gene wrote:

>>In fact just for fun I also tried having the Listener call
>>Unchecked_Deallocation itself just before exiting (i.e. the task was
>>deallocating its own context!).  And with GNAT running under both
>>Solaris and Windows it never caused a problem.
> 
> 
> Yes, AFAIK it works with GNAT.

Warning here: deallocating a task type in GNAT will silently leak memory 
*unless* the task is already 'Terminated.

You can make a small test for yourself: if the task is terminated, 
there's no memory leak. If it isn't, free won't fail but there's memory 
leak. If you create lots of tasks this will be noticeable sooner or later.

So I don't think it is (or was, I tested this with 3.15p for the last 
time) possible for a task to self-deallocate itself.

You need some kind of task manager who does something like:

loop
    if T'Terminated then -- where T is some task access type
       Free (T); -- Where free is unchecked_deallocation instance
    end if;
    delay 0.1;
end loop;

I would manage this transparently using finalization: on the record 
instantiation the task would be registered with the manager; on 
finalization the manager would be notified that the task needs being 
freed. (For example, the manager could have a list of accesses to tasks 
being terminated).



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

* Re: Deallocating records with task type fields.
  2005-12-12 11:32       ` Alex R. Mosteo
@ 2005-12-12 18:30         ` Pascal Obry
  2005-12-13 10:22           ` Alex R. Mosteo
  0 siblings, 1 reply; 11+ messages in thread
From: Pascal Obry @ 2005-12-12 18:30 UTC (permalink / raw)
  To: Alex R. Mosteo

Alex,

> You need some kind of task manager who does something like:
> 
> loop
>    if T'Terminated then -- where T is some task access type
>       Free (T); -- Where free is unchecked_deallocation instance
>    end if;
>    delay 0.1;
> end loop;

This is an infinite loop :) You probably meant something like:

  while not T'Terminated loop
    delay 0.1;
  end loop;
  Free (T); -- Where free is unchecked_deallocation instance

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|              http://www.obry.net
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



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

* Re: Deallocating records with task type fields.
  2005-12-11  4:06   ` Gene
  2005-12-11 11:50     ` Dmitry A. Kazakov
@ 2005-12-12 22:03     ` Randy Brukardt
  1 sibling, 0 replies; 11+ messages in thread
From: Randy Brukardt @ 2005-12-12 22:03 UTC (permalink / raw)


"Gene" <gene.ressler@gmail.com> wrote in message
news:1134274006.711602.173280@g43g2000cwa.googlegroups.com...
...
> In fact the real environment record also has a protected output queue
> with procedures to get data from the queue that the Listener has placed
> there.  That's the interesting case because other tasks need to call
> functions that can touch the queue.  I couldn't see a good way to
> declare the queue on the task stack and yet allow other tasks to get
> things from it.

An idea for the future (Ada 200Y) - use a protected interface and an access
to it. You'd still need to manage the pointer in some way (so it doesn't
dangle - you'll have to use 'Unchecked_Access to create the pointer), but it
would let you put the primary object inside of the task.

Indeed, you probably can do this with an access-to-protected-type, too
(presuming the objects are all the same type). Tasks that need to use the
protected queue would call an entry to get the access-to-protected-object,
then they could reference the queue normally via the access. If the callers
don't copy the access, you don't even need any real management of the
pointers (they call to the entry ensures that the queue exists).

This is far from my favorite approach, but it at least has good storage
management behavior. And it's probably better than twisting yourself in
knots to get storage management of separate entities tied together.

                               Randy.







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

* Re: Deallocating records with task type fields.
  2005-12-12 18:30         ` Pascal Obry
@ 2005-12-13 10:22           ` Alex R. Mosteo
  0 siblings, 0 replies; 11+ messages in thread
From: Alex R. Mosteo @ 2005-12-13 10:22 UTC (permalink / raw)


Pascal Obry wrote:
> Alex,
> 
> 
>>You need some kind of task manager who does something like:
>>
>>loop
>>   if T'Terminated then -- where T is some task access type
>>      Free (T); -- Where free is unchecked_deallocation instance
>>   end if;
>>   delay 0.1;
>>end loop;
> 
> 
> This is an infinite loop :) You probably meant something like:
> 
>   while not T'Terminated loop
>     delay 0.1;
>   end loop;
>   Free (T); -- Where free is unchecked_deallocation instance

Of course ;) I never find the Exits...



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

end of thread, other threads:[~2005-12-13 10:22 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-09 22:49 Deallocating records with task type fields Gene
2005-12-10  7:16 ` Jeffrey R. Carter
2005-12-10 11:45   ` Simon Wright
2005-12-10 14:10 ` Dmitry A. Kazakov
2005-12-11  4:06   ` Gene
2005-12-11 11:50     ` Dmitry A. Kazakov
2005-12-12 11:32       ` Alex R. Mosteo
2005-12-12 18:30         ` Pascal Obry
2005-12-13 10:22           ` Alex R. Mosteo
2005-12-12 22:03     ` Randy Brukardt
2005-12-11  5:02   ` Gene

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