how to implement a non-blocking server in Ada? - ada

My current design looks like this
task body Agent_Task is
begin
loop
select
accept Request_A do
end Request_A;
or
accept Request_B do
end Request_B;
or
...
else
Do_Other_Stuff;
end select;
end loop;
exception
when Exception_Id : others => Show_Exception (Exception_Id);
end Agent_Task;
But when calling an entry in an agent frequently (e.g. Request_A) it will become non-responsive.
Is there a better structure to make the agent never be blocked? like interrupts?
The most time consuming part is in Do_Other_Stuff, what I want the server to do is roughly:
loop
Do_Other_Stuff;
if interrupted, handle other requests.
end loop;
This a school assn which I can not modify the test program to retry a failed request to an agent. When the test is runing, mutilple agents will talk to each other concurrently.

Note that you have a spurious end; in your code that makes it illegal.
If what's important is that those making requests not block, you could use a protected queue for the inter-task communication:
loop
select
Request_Queue.Get (Item => Request);
Process (Request => Request);
else
Do_Other_Stuff;
end select;
end loop;
Requests will not be processed until Do_Other_Stuff completes, but those making requests will not be blocked by putting a request on the queue.
Using a queue would also allow you to use asynchronous transfer of control to give requests priority over Do_Other_Stuff:
loop
select
Request_Queue.Get (Item => Request);
Process (Request => Request);
then abort
Do_Other_Stuff;
end select;
end loop;
Do_Other_Stuff would then need to be abortable, and able to pick up from where it left off the next time it runs. But it would be better if Do_Other_Stuff could be moved into another task as Holsti suggested.
Finally, if you can't move Do_Other_Stuff to another task, and you can't abort it, you may need to break it into shorter parts:
loop
Do_Some_Stuff;
Handle_Requests;
Do_Some_More_Stuff;
Handle_Requests;
..
end loop;
Again, this is easier with a queue, since accept statements can't go in a subprogram.

Move the Do_Other_Stuff to another task, that is, divide your Agent_Task into two tasks.
How difficult that is depends on how much communication (data flow) there is between Do_Other_Stuff and the actions for Request_A and Request_B. If Do_Other_Stuff is moved to its own task, that task has to communicate with the original Agent_Task is some way, by rendez-vous or protected objects. If Do_Other_Stuff is a long computation that has some inputs and some outputs, you might add two entries to Agent_Task, one to provide the inputs to the Other_Stuff task, and another to receive the outputs from the Other_Stuff task.

Related

Handling long running, blocking functions

In a project I have to use an imported C function that sends a request to a server and receives a response. It is possible to provide a timeout parameter to this function to specify the maximum time before the blocking function returns if the server is not reachable.
Unfortunately this timeout is not always reliable and often the maxium timeout value is exceeded. What is the best Ada approach to handle this kind of problem?
After reading this chapter I am not sure if I could use this kind of programming pattern? The imported C function is not thread safe so only one request at a time is possible. A perfect solution would allow one to send a request (with a valid response or the timeout response normally returned by the imported C function) and a second function could be used to query if the last request timed out. Until the imported C function call has returned further requests should always return the timout response.
I am not sure what happens to the entries (programming statements inside the entries) Password_Server.Set and Process_Data.Output call if the delay alternative is chosen?
If the entry call is queued or waiting for access to a protected object (PO), then the entry call is aborted when the delay expires, the delay branch is executed, and the select finishes. If the entry call has been accepted (task) or is executing (PO) when the delay expires, it continues until it finishes or is requeued. If it finishes, then the entry branch is executed and the select finishes. If it is requeued with abort it behaves just as it does initially. If it is requeued without abort, then the delay branch is ignored. (Note that if it's requeued without abort, it can still be later requeued with abort, so things can be more complicated. It's best to try to avoid such a design.)
IIUC correctly, you want only one task at a time to be able to call the C operation. If one task is calling it and another tries to, the second task should be told the call timed out. Ada should abort the C operation if it takes longer than its timeout.
The only way I can see to abort the call to C is with an Asynchronous Transfer of Control. Whether that will actually do what is wanted is an open question.
This leads me to something like
package Calling_C is
type Data is ...
procedure Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean);
end Calling_C;
package body Calling_C is
task Control is
entry Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean);
end Control;
task body Control is
begin
Forever : loop
select
accept Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean) do
select
delay Timeout;
Timed_Out := True;
then abort
-- Call the C operation
end select;
end Call_C;
or
terminate;
end select;
end loop Forever;
end Control;
procedure Call_C (Info : in Data; Timeout : in Duration; Timed_Out : out Boolean) is
begin
select
Control.Call_C (Info => Info, Timeout => Timeout, Timed_Out => Timed_Out);
else
Timed_Out := True;
end Select;
end Call_C;
end Calling_C;
The first task gets in and calls the C operation. Subsequent tasks are not accepted immediately and return with Timed_Out set to True. If the call to C doesn't return in time, maybe it's aborted.
I don't actually know Ada very good just yet. Posting my idea here so pros can tell me whether it's a bad idea. The server would look something like this:
task Server is
entry Request (in Input : Input_Type);
entry Response (out Output : Output_Type);
end Server;
task body Server is
Local_Input : Input_Type;
Local_Output : Output_Type;
begin
accept Request (Input : in Input_Type) do
Local_Input := Input;
end Request;
Local_Output := My_C_Code(Local_Input);
accept Response(Output : out Output_Type) do
Output := Local_Output;
end Response;
end Server;
How to use it:
Server.Request(Input);
select
Server.Response(Output);
-- got your response
or
delay Timeout;
-- response timeout
end select;
As you may have realized the Server will block on Response until the Request caller (or anyone else) decides to call it. My best guess is either a) adding select ... or terminate, or b) handle the timeout and go back to waiting for Response, sync or async.

Mixed entry call and accept select in Ada?

Is it possible to mix protected entry calls (with barrier) with accepts in one select statement? Without using delays and two different consecutive selects, one for accepts and one for entry calls:
task body Task is
begin
select
accept Get;
or
accept Put;
or
Protected_Object.Alive;
end select;
end Task;
protected body Protected_Object is
begin
entry Alive when Is_Alive is
...
I want Task to get locked waiting for a call to Get, Put or getting the barrier in Alive opened.
Here are a couple of alternatives depending on what you expect to happen more often:
If you expect/want the Get/Put to happen more often than Alive:
task body Test is
begin
loop
select
accept Get;
or
accept Put;
or
-- Pick a value that makes sense
-- This is how long you check Get
-- and Put before trying Alive
delay 0.0001;
-- Asynchronous transfer of control
-- will try Protected_Object.Alive
-- until the second delay is finished
select
-- Pick a value that makes sense
-- Should be much smaller than the above
-- delay
delay 0.0000001;
then abort
Protected_Object.Alive;
end select;
end select;
end loop;
end Test;
if you expect/want Alive checked more often than Get/Put then:
task body Test is
begin
loop
select
accept Get;
or
accept Put;
else
-- Asynchronous transfer of control
-- will try Protected_Object.Alive
-- until the delay is finished
select
-- Pick a value that makes sense
delay 0.0001;
then abort
Protected_Object.Alive;
end select;
end select;
end loop;
end Test;
Either way, you'll need to decide how/when to end that loop if desired.
Note that you can do:
select
Protected_Object.Alive;
then abort
select
accept Get;
or
accept Put;
end select;
end select;
which may give you what you want, though understanding ATC can be tricky.

Ada stop entry execution and execute other entry

I'm new to Ada and I'm trying to write a simple program but I have some issues I couldn't solve. So I have a task with an execute entry and a signalfound entry, the execute entry is being called first and has to do some calculations until the signalfound entry is being called by the main and then it has to stop.
But the problem is that when Signalfound entry is called it doesn't get executed because the task is stuck in the while loop. Is there an obvious solution to this problem in Ada. I tried googling the problem but without succes. Thanks in advance!
task Example body
ResultFound : Boolean := False;
--- other unimportant things
begin
loop
select
accept Execute do
while (ResultFound = False) loop
---do some calculations
end loop;
end Execute;
or
accept SignalFound do
ResultFound := True;
end SignalFound;
or
-- other unimportant accepts
end select;
end loop;
end Example;
Well, when Execute is called, your task enters the loop, which means it never executes the select statement again, so it can never accept the SignalFound call. Also, the entity calling Execute will never continue since your while loop repeats forever inside the accept statement. Usually, you want to make your critical regions for task synchronisation as small as possible, so that both tasks can carry on with their work after necessary data has been exchanged.
Mind that your code reflects a protocol by which your task operates. Currently, your code says „I will accept both Execute and SignalFound at any loop iteration“, which does not seem to match with the protocol you have in mind based on what you write.
I believe what you actually want to do is something like this:
task Example body
begin
loop
-- simply wait for someone to tell me to execute.
accept Execute;
Calculations : loop
-- check at every loop iteration whether there's a SignalFound waiting
select
accept SignalFound;
exit Calculations;
else
-- do some calculations
end select;
end loop Calculations;
-- will go to next iteration and wait for someone to call Execute again.
end loop;
end Example;
This code enforces a sequence of alternating Execute / SignalFound calls which seems to be what you have in mind.

Ada 83(Only) How to end an entire program which has multiple procedures

I am using Ada83 (It's a course requirement to use this version), I am using multiple procedures. I don't know how to come out of the entire program. Some thing like Exit in C program which closes entire procedure. Where is the exit is called from?
If your program does not use tasks, you can define an exception that signifies an "emergency exit"; perhaps in some package:
package Emergency is
Emergency_Exit : exception;
end Emergency;
In your main procedure, catch this exception:
procedure Your_Main_Procedure is
begin
... whatever the main procedure does
exception
when Emergency.Emergency_Exit =>
null;
end Your_Main_Procedure;
So that whenever you raise the exception somewhere in your program:
raise Emergency_Exit;
it will transfer control to the null statement, which will then reach the end of the main procedure and exit the program.
Doing it this way means you can add cleanup code to other procedures:
procedure Something_Else is
...
begin
Direct_IO_Instance.Open (Some_File, Direct_IO_Instance.Out_File, "filename");
begin
... do your work
exception
when Emergency.Emergency_Exit =>
-- cleanup
Finish_Writing (Some_File);
Direct_IO_Instance.Close (Some_File);
-- now reraise, which will eventually reach the end of the program
raise;
end;
end Something_Else;
So when Emergency_Exit is raised, it will eventually transfer control to the end of the main procedure, but it might stop off in other exception handlers along the way to do any needed cleanup.
I don't think this works if there are other tasks running, because the main procedure will wait for those other tasks to complete before the program exits. In that case, in Ada 83, you'll need to coordinate the exit with the other tasks; perhaps you can define a global Boolean that those tasks check periodically to get them to exit, or perhaps you can structure the program in a way so that the Emergency_Exit exception handler knows what tasks to abort, or can call a task entry to get those tasks to terminate. The best solution would depend on the actual program structure.
On this page there is some explanation on how to do it, and what the risks are:
http://rosettacode.org/wiki/Program_termination#Ada

Best practice for implementing in Ada (2005 or 2012) an equivalent of the java finalize block

Java has the finalize block which allows to execute some statements after a block
is left (executed even if an exception is raised). Example:
try {
...
} catch (Exception e) {
...
} finally {
... // any code here
}
Ada has the controlled objects which allows to implement a Finalize operation
but there is no finalize block equivalent as in java. This is useful for logging,
closing files, transactions and so on (without having to create a specific tagged type for each possible block).
How would you implement such finalize block in Ada 2005 (while keeping the code readable)?
Are there plans in Ada 2012 to allow executing any finalization code easily?
I believe this code will do what you ask; it successfully prints out 42 with the present raise or with return. It's an implementation of T.E.D's suggestion.
Tested with GCC 4.5.0 on Mac OS X, Darwin 10.6.0.
with Ada.Finalization;
package Finally is
-- Calls Callee on deletion.
type Caller (Callee : not null access procedure)
is new Ada.Finalization.Limited_Controlled with private;
private
type Caller (Callee : not null access procedure)
is new Ada.Finalization.Limited_Controlled with null record;
procedure Finalize (Object : in out Caller);
end Finally;
package body Finally is
procedure Finalize (Object : in out Caller)
is
begin
Object.Callee.all;
end Finalize;
end Finally;
with Ada.Text_IO; use Ada.Text_IO;
with Finally;
procedure Finally_Demo is
begin
declare
X : Integer := 21;
-- The cleanup procedure, to be executed when this block is left
procedure F
is
begin
Put_Line ("X is " & Integer'Image (X));
end F;
-- The controlled object, whose deletion will execute F
F_Caller : Finally.Caller (F'Access);
begin
X := 42;
raise Constraint_Error;
end;
end Finally_Demo;
As Adrien mentions in the comment, Finalize is more analogous to a destructor.
To get something approximating an exception/final sequence you can do something along these lines (WARNING, not compiled, just typed--we'll work out any errors together :-) See also the Exceptions section of the Ada RM.
with Ada.Exceptions; use Ada.Exceptions;
procedure Do_Something is
-- Variables and what-not...
-- In case you have an exception and want to reraise it after you've done
-- the 'final' processing.
Exception_Caught : Exception_Occurrence := Null_Occurrence;
begin
-- You can have some statements, like initializations, here that will not
-- raise exceptions. But you don't have to, it can all just go in the
-- following block. However you want to do it...
declare
-- If you need to declare some entities local to a block, put those here.
-- If not, just omit this declare section. Be aware, though, that if
-- you initialize something in here and it raises an exception, the
-- block's exception handler will not catch it. Such an exception will
-- propagate out of the whole procedure (unless it has an outermost
-- exception handler) because you're _not_ in the block's scope yet.
begin
-- Main processing that might raise an exception
...
exception
when E : others =>
-- Handle any exception that's raised. If there are specific
-- exceptions that can be raised, they should be explicitly
-- handled prior to this catch-all 'others' one.
-- Save the exception occurrence, i.e. make a copy of it that can
-- be reraised in the 'Final' section if needed. (If you want to
-- reraise for a specific exception, do this in those handlers as
-- well.
Save_Occurrence(Exception_Caught, E);
end;
-- Final processing. Everything from here to the end of the procedure is
-- executed regardless of whether an exception was raised in the above
-- block. By it including an others handler, it ensured that no exception
-- will propagate out of this procedure without hitting this 'Final' code.
-- If an exception was raised and needs to be propagated:
if Exception_Caught /= Null_Occurrence then
Reraise_Exception(Exception_Caught);
end if;
end Do_Something;
Assuming you have understood the difference between ada.finalization and a finalize block in java, i would do something similar to the following, which should have the same effect.
procedure x is
begin
-- some code
begin
-- more code (your try)
exception
-- handle exception if necessary (caught exception)
end;
-- yet more code which is executed regardless of any exception handling.
end x;
Marc C has the right approach for trying to emulate that in straight-line procedural code.
However, IMHO that structure is mostly a way to hack around Java's OO system, for those who want one of the structural benifits of OO in old-fashioned procedural programming. Even in Java you are almost always better off creating a proper class instead.
So I don't think it is too much of a stretch to say that the proper way to get that functionality in Ada would be to make a proper object, and make your object a child of Ada.Finalization.Controlled.
If you don't want to bother with creating an actual object, you could just create a dummy one, put your finalization code in it, and declare it on the stack at the top of the block you want it run for. The drawback to that is that controlled types themselves (as least the last time I used them) have to be declared at package-level scope. When that's the case, you'd be unable to put direct references to lower-declared objects in them. They claimed they were going to fix that in future language revision, but I haven't tried it recently to see if they did.
Just thought of another answer. Its a bit heavy (and perhaps more trouble than it is worth). But it would give you something that looks a bit like your old finalize block
The idea would be to put your "finalizable" code in a task. You cannot leave the scope a task is declared in until the task terminates. So you could put your work code in the task and your "finally" code just outside of the scope the task is defined in. The parent task would sit there and wait for the work task to end (one way or another), and then it would run the "finally" code no matter how it ended. The drawback is that if the task throws an exception, it will stop at the task. So you still don't quite get the behavior that you can throw an exception and it will propagate out automatically while the "finalize" code gets run. You could maybe get that behavior back by adding a rendezvous and a second task (that's the problem with tasks. They are like potato chips...you always need one more).
procedure Finalized is
begin
declare
task Worker is end Worker;
task body Worker is begin
--// Working code in here. Can throw exceptions or whatever.
--// Does not matter.
end Worker;
begin
end;
--// If we get here, we know the task finished somehow (for good or ill)
--// so the finalization code goes here.
end Finalized;
It seems to me there might be a way to do something like this with protected objects too. I'll leave that one for others to figure out.
Lets put this problem into perspective.
In programming theory there exists concepts of an object's create & destroy and a procedure's try & finally. Both ultimately deal with resource management but they pivot on different things.
With objects we pivot on the potentially long-living tree of objects and variables referenced by the object pointer.
With procedures we pivot on the usually temporary objects and variables existing in the scope of the procedure call (the notable exception is main)
Now, depending on the procedure we might need to spawn a series of resources which, if the procedure is interrupted by a fatal error, must rollback all spawned resources in reverse order. Quite often this is easiest achieved by creating objects dedicated to managing their respective resource. Ada.Finalization becomes quite useful here.
But this can be overkill, and there can be arguments made against this technique on a case-by-case basis. So if we are interested in self-containing resource management to a procedure and making use of a C++-style finally keyword, consider the following.
I have often initially been pleased by the promise of convenience using finally only to be disappointed by how complicated the code can turn out after making use of it. Nesting is required for complex rollback operations, and many times the process is not linear, requiring logic to decide exactly how to roll back depending on how far we made it through the initialization. The nested block structure corners you to use linear logic. Thus when you need something more complicated then you are seriously considering making use of goto.
I've gone through this enough times to realize that, as appetizing as OOP-style finalize can be with what I mentioned, a true try & finally can be achieved in Ada without all the headaches as demonstrated in the following example. Note, it's far from perfect, but I think the good outweighs the bad with this strategy. What I especially like about this strategy is how explicit the finalize process becomes, all steps labeled and checked against Ada's type system, well organized and easy to manage. The C++-style try & finally scatters this kind of code, and Ada's Finalize hide's it and makes it harder to control the higher-level order of fail-over logic.
procedure Proc is
type Init_Stages_All is (Do_Null, Do_Place, Do_Pour, Do_Drink);
subtype Init_Stages is Init_Stages_All range Do_Place .. Do_Drink;
Init_Stage : Init_Stages_All := Do_Null;
procedure Initialize_Next is
begin
Init_Stage := Init_Stages_All'Succ(Init_Stage);
case Init_Stage is
when Do_Place => ...
when Do_Pour => ...
when Do_Drink => ...
when Do_Null => null;
end case;
end Initialize_Next;
procedure Finally is
begin
for Deinit_Stage in reverse Init_Stage .. Init_Stages'Last loop
case Deinit_Stage is
when Do_Place => ...
when Do_Pour => ...
when Do_Drink => ...
end case;
end loop;
end Finally;
begin
Initialize_Next; -- Do_Place
...
Initialize_Next; -- Do_Pour
...
Initialize_Next; -- Do_Drink
...
Finally;
exception
when E : others =>
...
Finally;
raise;
end Proc;
On a final note, this strategy also makes it easier to deal with finalization exceptions. I'd suggest creating a procedure in Finally that is called when an exception is raised and recursively call Finally by manipulating the Init_Stage as well as interject any additional fail-over logic there.

Resources