HansG
HansG

Reputation: 55

Ada - Asynchronous Transfer of Control with delay statement does not abort (using GNAT)

Introduction

I came across the nice Ada Feature of the Asynchronous Transfer of Control, but somehow the Reference Manual and an example application do not fit together.

The following example is written in the Reference Manual 9.7.4:

select
  delay 5.0;
  Put_Line("Calculation does not converge");
then abort
  -- This calculation should finish in 5.0 seconds;
  --  if not, it is assumed to diverge.
  Horribly_Complicated_Recursive_Function(X, Y);
end select;

I now rebuilt and run it in the following way (complete file):

with Ada.Text_IO; use Ada.Text_IO;
procedure asynch_transf_ex is
begin
  Put_Line("Before Select");
  select
    delay 1.0;
    -- will never be printed
    Put_Line("1 Second is over");
  then abort
    loop
      null;
    end loop;
  end select;
  -- again, not printed
  Put_Line("After Select");
end asynch_transf_ex;

(Compiled with: gnatmake -gnat2012 -gnata -ggdb -O0 asynch_transf_ex.adb)

The Problem

As noticed in the comments, the loop runs forever and is not interrupted. In contrast the Reference Manual states, that it should be interrupted after (roughly) 1 second.

Now, there are situations, when the statements in the abort-area would be safe from being aborted, as stated in Section 9.8 of the RM:

But the loop should be none of them - indeed, if I replace the null; with an delay 0.0; then the execution runs as expected.

As in the example a recursive function was mentioned, I also thought about function calls being somehow a trigger to abort the exection after the time is over. But replacing the null; with a call to a procedure procedure do_null is begin null; end; did not change anything. (I looked at the objdump - the call was not optmized away.)

Reading this explanation about GNAT's implementation of these constructs did not help me.

Question

So, do I miss a point in the Reference Manual, or is this just an issue with GNAT? If so, is the delay 0.0; a suitable "Hotfix", or is there a better solution?

Thanks for any help.

Edit

I'm running Linux (uname -r = 3.16.3-1-ARCH - standard kernel from Arch Linux-repos, not modified), and (as Signals have been mentioned, maybe the processor type is interesting, too) tried it on an Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz and an Intel Pentium 987.

Upvotes: 2

Views: 1000

Answers (1)

ajb
ajb

Reputation: 31699

While the section you cite lists the places where aborts may not occur, i.e. the abort-deferred operations, it does not follow that an abort must occur immediately if not in an abort-deferred operation. In fact, further down in RM 9.8, there is a list of abort completion points:

Other than for these immediate cases, the execution of a construct that is aborted does not necessarily complete before the abort_statement completes. However, the execution of the aborted construct completes no later than its next abort completion point (if any) that occurs outside of an abort-deferred operation; the following are abort completion points for an execution:

  • the point where the execution initiates the activation of another task;

  • the end of the activation of a task;

  • the start or end of the execution of an entry call, accept_statement, delay_statement, or abort_statement;

  • the start of the execution of a select_statement, or of the sequence_of_statements of an exception_handler.

Thus, if a sequence of statements is aborted, the abort does not have to happen until the next one of these occurs. The loop in your example does not do anything that would cause an abort completion point; therefore, using just the rule in 9.8, the abort never has to occur. Adding delay 0.0; would provide abort completion points.

If the Real-Time Annex is supported, then RM D.6 ("Preemptive Abort") says that an abort does have to occur immediately, on a single-processor system, if not in an abort-deferred operation. However, Annex D is optional, and not all implementations support it.

If you are running on Windows, then I believe Annex D is not supported, and I don't think it's possible to support preemptive abort, since Windows does not provide a safe way to terminate a thread immediately without the thread's cooperation.

GNAT supports a Polling pragma for use on Windows; this generates code that checks to see if another thread has tried to abort the current thread.

Upvotes: 3

Related Questions