Question

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?

Was it helpful?

Solution

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”.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top