comp.lang.ada
 help / color / mirror / Atom feed
* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-04  5:58 To raise an exception in task and handle/catch it in outer-block Frank
@ 2004-01-03 22:03 ` tmoran
  2004-01-04 20:58   ` Frank
  0 siblings, 1 reply; 8+ messages in thread
From: tmoran @ 2004-01-03 22:03 UTC (permalink / raw)


Personally, I would find it somewhat clearer to enclose the stuff that
may have/handle exceptions in a block of its own, rather than the task's
begin-end block.  That makes it clearer that exception handling has
nothing to do with whether the task finishes up with an "accept Stop" etc.

   task body A_Task is
   begin
     begin
       do stuff
     exception
       when others => do stuff
     end;
     accept Stop...
   end A_Task;



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

* To raise an exception in task and handle/catch it in outer-block.
@ 2004-01-04  5:58 Frank
  2004-01-03 22:03 ` tmoran
  0 siblings, 1 reply; 8+ messages in thread
From: Frank @ 2004-01-04  5:58 UTC (permalink / raw)


Hi!

What is the best practice for handling exceptions (by outer block) that are
raised in tasks?
My question is in particular, if the approach I have chosen in the example
below is recommended or not?

What I have tried, is that a task raises an exception. The outer block is
still waiting to perform "Stop" and "Final".
In this solution I have added two accepts for "Stop" and "Final" in the
exception-block of the task, to catch
the client-code's "Stop" and "Final".

What is the best way of handling this? To start testing "Is_Callable" or
similar clutters the code in my opinion.


Frank


package Test_Task_Exception is


   task type A_Task is
      entry Init( P_Fail : in Boolean) ;
      entry Start;
      entry Stop;
      entry Final;
   end A_Task;

end Test_Task_Exception;



with Ada.Text_IO;

package body Test_Task_Exception is

   test_exception : exception;

   task body A_Task is
     Run : Boolean := False;
     Counter : Integer := 0;
     Fail : Boolean;

   begin
      accept Init ( P_Fail : in Boolean) do
         Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Init - Body");
         Fail := P_Fail;
      end Init;

      accept Start do
         Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Start - Body");
         Run := True;
      end Start;

      while Run loop
         Counter := Counter + 1;

         Ada.Text_IO.Put_Line("Test_Task_Exception.A_Task.Task Working " &
Counter'Img);

         if Counter > 8 and not Fail then
            select
               accept Stop do
                  Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Stop -
Body");
                  Run := False;
               end Stop;

            else
                  null;
            end select;
         end if;

         if Counter > 8 and Fail then
           raise test_exception;
         end if;
      end loop;

      accept Final do
        Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Final - Body");
      end Final;

   exception
      when others =>
        begin
          accept Stop do
            Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Stop -
Exception");
          end Stop;

          accept Final do
            Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Final -
Exception");
            raise test_exception;
          end Final;

        end;

   end A_Task;

end Test_Task_Exception;





with Test_Task_Exception;
use Test_Task_Exception;
with Text_IO;
use Text_IO;

procedure Test_Task_Main is
  type Pointer_To_A_Task is access Test_Task_Exception.A_Task;
  Task1, Task2 : Pointer_To_A_Task;
begin
  Put_Line("Main program");
  Task1 := new Test_Task_Exception.A_Task;
  Task2 := new Test_Task_Exception.A_Task;

  Put_Line("*************** Raise no exception");
  Task1.Init (False);
  Task1.Start;
  Task1.Stop;
  Task1.Final;

  Put_Line("*************** Do raise exception");
  Task2.Init (True);
  Task2.Start;
  Task2.Stop;
  Task2.Final;

end Test_Task_Main;







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

* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-04 20:58   ` Frank
@ 2004-01-04 20:35     ` tmoran
  2004-01-07  3:48       ` Frank
  2004-01-10  2:20     ` Craig Carey
  1 sibling, 1 reply; 8+ messages in thread
From: tmoran @ 2004-01-04 20:35 UTC (permalink / raw)


Your code is right.  Raising an exception in a rendezvous will raise
the exception in both the task and its caller (caller = what you are
calling outer block, right?)
          accept Final do
            ...
            raise test_exception;  -- raise exception in caller
          end Final;
You might instead want to use Ada.Exceptions.Save_Occurrence in the
task, pass the Exception_Occurrence_Access (or null) to the caller at
a rendezvous, then Reraise_Occurrence at a convenient point in the
caller.



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

* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-03 22:03 ` tmoran
@ 2004-01-04 20:58   ` Frank
  2004-01-04 20:35     ` tmoran
  2004-01-10  2:20     ` Craig Carey
  0 siblings, 2 replies; 8+ messages in thread
From: Frank @ 2004-01-04 20:58 UTC (permalink / raw)


Hi!

I agree that the exception has nothing to do with the Stop/Final accept.

What I try to achieve is that the exception is propagated to the outer
block. In this case with outer block, I mean the block that controls the
task- in my example "Test_Task_Main"*.
This issue came up because a exception raised in a task like this is not
propagated automatically by Ada to the outer block, but is resolved within
each task.
Another reason why is that the exception is related to the outer-block or
more precisely the developer of the outer block. I wish to propagate the
exception in the task for the outer-block(*) to
handle it there.

In my real-code, the situation is that a library Im working on, requires an
abstract subprogram to be overridden.

This abstract subprogram is called from within the library itself and it is
in that environment that an exception may be detected.
The business-related exception ("test_exception") will be raised if the
developer of the abstract subprogram behaves bad.
If such a exception is detected, I wish to communicate this to the
outer-block(*).

One question I have, is if this kind of construction is allowed in respect
to Ada standard.

This is a pseudo-code based on the example, here I have included the call to
the abstract subprogram:

package body Test_Task_Exception is

   test_exception : exception;

   task body A_Task is
     Run : Boolean := False;

   begin
      accept Init do -- ... as in example

      accept Start do -- ... as in example

      while Run loop

        -- This is an abstract subprogram, overriden by the developer using
this library.
        -- If the return value is bad, we wish to communicate this to the
outer-block
        Retur_Value := Do_Business_Logic(....);
        if Retur_Value = Bad_Value then
            raise test_exception;
        end if;

        -- Return_Value is ok, we are allowed to stop normally.l
            select
               accept Stop do
                  Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Stop -
Body");
                  Run := False;
               end Stop;

            else
                  null;
            end select;



      end loop;

      accept Final do -- ... as in example

   exception
      when others =>
        begin
          accept Stop do -- ... as in example

          accept Final do -- repeated here for clarity
            Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Final -
Exception");

            -- We wish to communicate exception to the outer-block
            raise test_exception;
          end Final;

        end;

   end A_Task;

end Test_Task_Exception;



Frank


<tmoran@acm.org> wrote in message news:Z_GJb.739626$Fm2.662614@attbi_s04...
> Personally, I would find it somewhat clearer to enclose the stuff that
> may have/handle exceptions in a block of its own, rather than the task's
> begin-end block.  That makes it clearer that exception handling has
> nothing to do with whether the task finishes up with an "accept Stop" etc.
>
>    task body A_Task is
>    begin
>      begin
>        do stuff
>      exception
>        when others => do stuff
>      end;
>      accept Stop...
>    end A_Task;









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

* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-04 20:35     ` tmoran
@ 2004-01-07  3:48       ` Frank
  0 siblings, 0 replies; 8+ messages in thread
From: Frank @ 2004-01-07  3:48 UTC (permalink / raw)


Thank you for help.





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

* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-04 20:58   ` Frank
  2004-01-04 20:35     ` tmoran
@ 2004-01-10  2:20     ` Craig Carey
  2004-01-10  6:24       ` Robert I. Eachus
  2004-01-10 21:05       ` Frank
  1 sibling, 2 replies; 8+ messages in thread
From: Craig Carey @ 2004-01-10  2:20 UTC (permalink / raw)


On Sun, 4 Jan 2004 12:58:52 -0800, "Frank" <franjoe@frisurf.no> wrote:
...
>This issue came up because a exception raised in a task like this is not
>propagated automatically by Ada to the outer block, but is resolved within
>each task.
...
>   task body A_Task is
...
>   exception
>      when others =>
>        begin
>          accept Stop do -- ... as in example
>
>          accept Final do -- repeated here for clarity
>            Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Final...
>               -- We wish to communicate exception to the outer-block

>            raise test_exception;    <<<=== Bad News here. Delete this !!

>          end Final;
>        end;
>   end A_Task;
>end Test_Task_Exception;


Lockups in GNAT running in Linux were observed by me to occur in Linux
 when an exception was raised in a task's outmost exception handler.

The debugger may be unhelpful so it may be best to check all code and
delete any that would allow a task to be exited by the raising of an
exception.

Deleting that "raise" statement still leaves the Put_Line line which 
could also raise an exception.

The lockup problems maybe are absent in Windows. In Linux, a call to
C's exit() [GNAT's OS_Exit] can zombi-ize the program over delay
statements, and any sort of blocking (though I don't recall seeing
barriers of protected objects being implication in the construction of
zombies).

The above call to raise is a way to get a lockup without any blocking.
I never submitted a bug report.


Craig Carey





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

* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-10  2:20     ` Craig Carey
@ 2004-01-10  6:24       ` Robert I. Eachus
  2004-01-10 21:05       ` Frank
  1 sibling, 0 replies; 8+ messages in thread
From: Robert I. Eachus @ 2004-01-10  6:24 UTC (permalink / raw)


Craig Carey wrote:

> The above call to raise is a way to get a lockup without any blocking.
> I never submitted a bug report.

I don't know what GNAT does in this case, it may even have a bug. But 
the code in your example should cause the exception to be propagated to 
the caller, then silently terminate the task.  I can well imagine 
situations where this would cause a program to hang.  (If some tasks in 
a process, but not all tasks are terminated, the program unit the tasks 
depend on will not be left.  I think that is what you mean when talking 
about zombies.

-- 
                                           Robert I. Eachus

"The war on terror is a different kind of war, waged capture by capture, 
cell by cell, and victory by victory. Our security is assured by our 
perseverance and by our sure belief in the success of liberty." -- 
George W. Bush




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

* Re: To raise an exception in task and handle/catch it in outer-block.
  2004-01-10  2:20     ` Craig Carey
  2004-01-10  6:24       ` Robert I. Eachus
@ 2004-01-10 21:05       ` Frank
  1 sibling, 0 replies; 8+ messages in thread
From: Frank @ 2004-01-10 21:05 UTC (permalink / raw)


Hi!

Im dont understand your answer completely. What I get from it is that the
effect
of this kind of construction ..may be... platform-dependent, due to a
GNAT-bug (which is an OK answer).

I have tried (dont read it as "tested") the original example in Windows,
where it appeared to work
the 5-7 times I ran it :-)

It was my feeling that my construction was "agressive" this is why I check
it here.

1) I agree that there is a great chance of  locking tasks doing it in this
way.
2) The Text_IO is there for the moment for debugging purposes.
3) And by "outer-block" I mean the calling main program in my example.
4) Im currently using GNAT 3-15p on Windows XP.

This leaves me with the original "problem", how to I simplify the life of
the outer-block. In this posting a have noted two alternative.....

A)
--------------------------------
Norman H. Cohen's "Ada a Second language"(2nd ed) discusses this issue in
chapter
"18.9.1 Exceptions in Task Bodies", he proposes a solution where the
exception becomes
noticeable (but not "handled" when considering my example):

<Quote Norman H. Cohen>

task body My_Task
...
  use Ada.Text_IO; Ada.Task_Identification; Ada.Exception;
begin
..
exception
  when E: others => Put_Line(Current_Error, "Task " & Image(Current_Task) &
"terminated becuase of exception " &
       Exception_Name(E));
end My_Task;

</Quote Norman H. Cohen>

I have used it, and it works, but I was not quite satisifed because it still
leaves my outer-block in trouble....

B)
--------------------------------
A new theory I have now after reading this feedback, is to do the follwoing
(this is a rework of the example in the original posting):

What I do here is that I remove the "accept"'s in the exception-block of the
task and leaves an exceptions handling like
alternative (A) plus catching then "test_exception" in particular.
The accept is now moved to the if-statement where the
problem is found. Now the outer-block will
call these "alternative" accept-statements if the if-statement found a
problem. I leave the "raise test_exception" in the
"accept Final" as before, which should propagate to the outer-block.
(PS: Example has not been compiled by me)


Now I should be back on safe grounds again - or what?


with Ada.Text_IO;

package body Test_Task_Exception is

   test_exception : exception;

   task body A_Task is
     Run : Boolean := False;
     Counter : Integer := 0;
     Fail : Boolean;

   begin
      accept Init ( P_Fail : in Boolean) do
         Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Init - Body");
         Fail := P_Fail;
      end Init;

      accept Start do
         Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Start - Body");
         Run := True;
      end Start;

      while Run loop
         Counter := Counter + 1;

         Ada.Text_IO.Put_Line("Test_Task_Exception.A_Task.Task Working " &
Counter'Img);

         if Counter > 8 and not Fail then
            select
               accept Stop do
                  Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Stop -
Body");
                  Run := False;
               end Stop;

            else
                  null;
            end select;
         end if;

         if Counter > 8 and Fail then
            -- I wish to raise a exception and propagate it to the
outer-block.
            -- I add an accept here also that the outer-block will visit
now...
            accept Stop do
                Ada.Text_IO.Put_Line
("Test_Task_Exception.A_Task.Stop -Alternative handling");
                Run := False;
            end Stop;

            accept Final do
                Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Final - To
Raise exception");
                raise test_exception;
            end Final;
         end if;
      end loop;

      accept Final do
        Ada.Text_IO.Put_Line ("Test_Task_Exception.A_Task.Final - Body");
      end Final;

    exception
        when test_exception => null; -- short cut this one since it is
handled elsewhere.....

        when others =>
       -- "Norman H. Cohen's tick"

   end A_Task;

end Test_Task_Exception;







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

end of thread, other threads:[~2004-01-10 21:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-01-04  5:58 To raise an exception in task and handle/catch it in outer-block Frank
2004-01-03 22:03 ` tmoran
2004-01-04 20:58   ` Frank
2004-01-04 20:35     ` tmoran
2004-01-07  3:48       ` Frank
2004-01-10  2:20     ` Craig Carey
2004-01-10  6:24       ` Robert I. Eachus
2004-01-10 21:05       ` Frank

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