Aborting a process in Ada that uses a protected object that requeues

220 views Asked by At

I'm experiencing some troubles with my program.

I have a process that calls a function (Take_Job) that is supposed to remain blocked until a time (MINIMUM_WAIT) passes. If it doesn't happen that way, a message informing of this situation will appear.

for Printer_Id in Type_Printer_Id loop
   select
      delay MINIMUM_WAIT
      Pragma_Assert (True, "");
   then abort
      Take_Job (Controller,
                     Printer_Id,
                     Max_Tonner,
                     Job,
                     Change_Tonner);
      Pragma_Assert
        (False,
           "Testing of Take_Job hasn't been successful. It should have remained blocked.");
   end select;
end loop;

The function Take_Job calls to an entry in a protected object:

procedure Take_Job (R                 : in out Controller_Type;
                         Printer      : in     Type_Printer_Id;
                         Siz          : in     Typo_Volume;
                         Job          :    out Typo_Job;
                         Excep_Tonner :    out Boolean) is
begin
   R.Take_Job(Printer, Siz, Job, Excep_Tonner);
end Take_Job;

Where "R" is the protected object.

The following code is the entry of the protected object. Actually, the "when" condition is True because I need to check some stuff with the parameters of the entry. Since Ada doesn't allow me to do that, I copy the parameters inside the protected object and call to a "delayed entry", then in the "delayed entry" I will make sure that the condition is met before proceeding.

entry Take_Job(Printer_Id: in Type_Printer_Id; Remaining: in Type_Volume; Job: out Type_Job; exceptionTonner: out Boolean)
when True is
begin
   Copy_Remaining(Printer_Id) := Remaining;
   requeue Take_Job_Delayed(Printer_Id);
end Take_Job;

Let's see the "delayed entry" code:

entry Take_Job_Delayed(for J in Type_Printer_Id)(Printer_Id: in Type_Printer_Id; Remaining: in Type_Volume; Job: out Type_Job; exceptionTonner: out Boolean)
when False is -- I've done this on purpose
begin
   null; -- Actually, there would be a lot of code here
end Take_Job_Delayed;

Let's say that my goal is to pass the MINIMUM_WAIT and run the "Pragma_Assert(True, "")". If I put the "when" condition of Take_Job to "False", then everything works fine. Take_Job is never accepted and the Pragma_Assert will be executed. If I set it to "True" and the "when" condition of Take_Job_Delayed to "False", I don't get the same effect and the process gets blocked and neither of the Pragma_Asserts will be executed.

Why? It looks like the problem is in the "requeue" or somewhere near that, but why is this happening?

1

There are 1 answers

0
Simon Wright On BEST ANSWER

You need to do the requeue with abort;

entry Take_Job(Printer_Id: in Type_Printer_Id;
               Remaining: in Type_Volume;
               Job: out Type_Job;
               exceptionTonner: out Boolean)
when True is
begin
   Copy_Remaining(Printer_Id) := Remaining;
   requeue Take_Job_Delayed(Printer_Id) with abort;
end Take_Job;

because otherwise the opportunity to abort the entry call has been lost. There are details in ARM 9.5.4, and a more understandable explanation in Burns & Wellings, “Concurrency in Ada”.