开发者

Ada Shutdown Hook

There are some ‘cleanup’ calls that I want called when an Ada appli开发者_如何学编程cation is shutdown/killed.

For instance if I was in java, I would do something like this to achieve the effect of having something called at shutdown:

Runtime.getRuntime().addShutdownHook(new Thread(){
       public void run(){
            method();
       }
});

Is there anything similar in Ada or another way to achieve this?


Since an Ada main program is treated as a task, you can use the Ada.Task_Termination package to manage post-execution cleanup. There's a writeup on this in the Ada 2005 Rationale, and what follows is a quick demo I put together that builds on the example.

You have to provide a library level protected termination procedure, so here's a package for that:

with Ada.Task_Termination;
with Ada.Task_Identification;
with Ada.Exceptions;

package Main_Program_Finalization is

   protected Shutdown_Handler is

      procedure Termination_Finalizer 
        (Cause : in Ada.Task_Termination.Cause_Of_Termination;
         T     : in Ada.Task_Identification.Task_Id;
         X     : in Ada.Exceptions.Exception_Occurrence);
   end Shutdown_Handler;

end Main_Program_Finalization;

Body:

with Text_IO; use Text_IO;

package body Main_Program_Finalization is

   protected body Shutdown_Handler is

      procedure Termination_Finalizer
        (Cause : in Ada.Task_Termination.Cause_Of_Termination;
         T     : in Ada.Task_Identification.Task_Id;
         X     : in Ada.Exceptions.Exception_Occurrence)
      is
         use Ada.Task_Termination;
         use Ada.Task_Identification;
         use Ada.Exceptions;
      begin
         New_Line;
         Put_Line("Shutdown information:");
         New_Line;
         case Cause is
         when Normal =>
            Put_Line("Normal, boring termination");
         when Abnormal =>
            Put_Line("Something nasty happened to task ");
            Put_Line(Image(T));
         when Unhandled_Exception =>
            Put_Line("Unhandled exception occurred in task ");
            Put_Line(Image(T));
            Put_Line(Exception_Information(X));
         end case;
      end Termination_Finalizer;

   end Shutdown_Handler;

end Main_Program_Finalization;

Main program (it's set up for a normal termination as posted, uncomment the last two lines and run it to see the effect of an unhandled-exception triggered termination):

with Main_Program_Finalization;
with Ada.Task_Identification;
with Ada.Task_Termination;
with Text_IO; use Text_IO;

procedure task_term is

   use Ada;

   Task_ID : Task_Identification.Task_Id
     := Task_Identification.Current_Task;

begin
   Put_Line("Main Task ID: " & Task_Identification.Image(Task_ID));

   Put_Line("Setting termination finalizer");
   Task_Termination.Set_Specific_Handler
     (Task_ID, 
      Main_Program_Finalization.Shutdown_Handler.Termination_Finalizer'Access);
   Put_Line("Go off and do things now...");
   delay 1.0;
   Put_Line("Done with mainline processing, the shutdown handler should now execute");

--     Put_Line("Raise an unhandled exception and see what the shutdown handler does");
--     raise Constraint_Error;
end Task_Term;


You could create a Controlled (or Limited_Controlled) object to the main procedure, which calls the necessary stuff in its Finalization method.

Be aware that you can't access any local variables of the main procedure, so put anything necessary into the controlled object.

example:

with Ada.Text_IO;
with Ada.Finalization;
procedure Main is
   type Cleaner is new Ada.Finalization.Limited_Controlled with record
      Some_Interesting_Data : Integer;
   end record;
   overriding procedure Finalize (X : in out Cleaner) is
   begin
      Ada.Text_IO.Put_Line ("Cleaning..." & Integer'Image (X.Some_Interesting_Data));
   end Finalize;
   The_Cleaner : Cleaner;
begin
   Ada.Text_IO.Put_Line ("Main Procedure.");
   The_Cleaner.Some_Interesting_Data := 42;
   Ada.Text_IO.Put_Line ("Finished.");
end Main;


If it's a controlled shutdown initiated by the user or because the program is simply done doing what it does, then you can simply add a final call to a cleanup procedure.

If the program is terminated due to an interrupt signal, such as a user sending a SIGINT signal, or the system shutting down, then you can catch those signals and put your cleanup procedure in the registered callback.

I wrote a short example on how to catch interrupts using Ada. It's available at github and as a wiki article.

Another option is using the Florist POSIX package from libre.adacore.com. Perhaps there's something of use in the posix-signals package.


You can raise an exception, which can be one defined by the language or one defined in your program. Your exception handler would then execute.

You can also use Ada.Command_Line.Set_Exit_Status to return a code to the invoking environment.

Addendum: You can also handle external interrupts, as shown here.


Seems like there should be a way to do this in pure Ada, but I couldn't find one.

One idea would be to use Interfaces.C and call atexit() with a callback function that does the cleanup. I haven't tried it, but I can't think of any reason it wouldn't work.

More info on Ada callbacks from C


If the program is allowed to shut down nicely, then you can use standard language facilities like controlled types to provide your "on shutdown" behavior.

If the program isn't allowed to shut down nicely by the OS, then there is no language-defined way to do it in any language. You will have to use some kind of OS call to do it.

Note that the example you showed was not a Java call, but a JVM call. JVM = Java Virtual Machine...essentially the Java OS. You could make the exact same call from Ada, assuming your Ada code is running on the JVM. If you are running under Windows instead you'd have to do it with Win32 system calls. You can make those from Ada, but obviously the exact calls aren't portably defined in the language.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜