Piotr Walkusz
Piotr Walkusz

Reputation: 15

Nested "then abort" weird behaviour

Are nested "then abort" constructions legal in Ada? If yes, how properly can I use them? I have this code:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

  task TestTask is
  end TestTask;

  task body TestTask is
  begin
    select
      delay 2.0;
      Put_Line("C"); -- never executed
    then abort
      select
        delay 5.0;
      then abort
        Put_Line("A");
        delay 4.0;
      end select;
      loop
        Put_Line("B");
        delay 10.0;
      end loop;
    end select;
  end TestTask;

begin
  null;
end Main;

I expect that this code should exit after 2 seconds. But instead, it prints continuously "B" without even delay (it ignores delay 10.0). It looks that code behaves in this way:

  1. Execute Put_Line("A") and wait 2 seconds
  2. Exit from inner "then abort"
  3. Execute loop ignoring delay 10.0

If instead of delay 4.0 we insert delay 1.0 (then aborting occurs inside the loop), the program works properly. I think it is very dangerous, because "abort then" can be inside library function, for example:

procedure Main is

  ----- It's function from library -----

  procedure Foo is
  begin
    select
      delay 5.0;
    then abort
      Put_Line("A");
      delay 4.0;
    end select;
  end;

  ---------------------------------------

  task TestTask is
  end TestTask;

  task body TestTask is
  begin
    select
      delay 2.0;
      Put_Line("C"); -- never executed
    then abort
      Foo;
      loop
        Put_Line("B");
        delay 10.0;
      end loop;
    end select;
  end TestTask;

begin
  null;
end Main;

Can someone explain why this program behaves in this weird way?

Upvotes: 1

Views: 173

Answers (1)

trashgod
trashgod

Reputation: 205865

As noted in A Comparison of the Asynchronous Transfer of Control Features in Ada and the Real-Time Specification, "The asynchronous select statement deals with nested ATCs correctly. For example, if the delay for an outer triggering statement expires while an inner delay is pending, the inner delay will be canceled and an ATC will be promulgated out of the inner abortable part…"

The variation below prints ABBBBC, as expected. The outer triggering statement specifies a five second timeout; the nested triggering statement specifies a three second timeout. As the latter's abortable part only consumes one second of its thee second budget, the ensuing loop can print four B's before the outer timeout. Change the outer delay to 1.0 in order to reproduce the effect seen in your example.

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

   task TestTask;

   task body TestTask is
   begin
      select
         delay 5.0;
         Put("C");
      then abort
         select
            delay 3.0;
         then abort
            Put("A");
            delay 1.0;
         end select;
         loop
            Put("B");
            delay 1.0;
         end loop;
      end select;
   end TestTask;

begin
   null;
end Main;

Upvotes: 3

Related Questions