Подтвердить что ты не робот

Ada Shutdown Hook

Есть некоторые "вызовы очистки", которые я хочу вызывать, когда приложение Ada отключается/убивается.

Например, если бы я был в java, я бы сделал что-то подобное, чтобы добиться эффекта, вызванного тем, что вызывается при завершении работы:

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

Есть ли что-то подобное в Аде или другим способом достичь этого?

4b9b3361

Ответ 1

Вы можете создать объект Controlled (или Limited_Controlled) для основной процедуры, которая вызывает необходимый материал в методе Finalization.

Помните, что вы не можете получить доступ к каким-либо локальным переменным основной процедуры, поэтому поместите в контролируемый объект что-то необходимое.

Пример:

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;

Ответ 2

Поскольку основная программа Ada рассматривается как задача, вы можете использовать пакет Ada.Task_Termination для управления очисткой после выполнения. Там написано об этом в Ada 2005 Обоснование, а следующее - это быстрая демонстрация, которую я собрал, основываясь на этом примере.

Вы должны предоставить защищенную процедуру на уровне библиотеки, так что вот пакет для этого:

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;

Тело

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;

Основная программа (она настроена для обычного завершения как отправлено, раскомментирует последние две строки и запустит ее, чтобы увидеть эффект прерывания с необработанным исключением):

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;

Ответ 3

Если это контролируемое выключение, инициированное пользователем, или потому, что программа просто выполняется, что она делает, вы можете просто добавить окончательный вызов процедуры очистки.

Если программа завершается из-за сигнала прерывания, например, пользователь, отправляющий сигнал SIGINT, или выключение системы, вы можете поймать эти сигналы и поместить свою процедуру очистки в зарегистрированный обратный вызов.

Я написал короткий пример о том, как поймать прерывания с помощью Ada. Он доступен в github и как wiki article.

Другой вариант - использовать пакет Florist POSIX от libre.adacore.com. Возможно, в пакете posix-сигналов есть что-то полезное.

Ответ 4

Вы можете создать исключение, которое может быть определяемое язык или один определенный в вашей программе. Затем выполнится ваш обработчик исключений.

Вы также можете использовать Ada.Command_Line.Set_Exit_Status, чтобы вернуть код в вызывающую среду.

Добавление: вы также можете обрабатывать внешние прерывания, как показано здесь.

Ответ 5

Кажется, должен быть способ сделать это в чистой Аде, но я не смог найти его.

Одной из идей было бы использование Interfaces.C и вызов atexit() с функцией обратного вызова, которая выполняет очистку. Я не пробовал, но я не могу придумать никаких причин, чтобы это не сработало.

Дополнительная информация о обратных вызовах Ada с C

Ответ 6

Если программе разрешено закрывать красиво, вы можете использовать стандартные языковые средства, такие как контролируемые типы, чтобы обеспечить поведение "при выключении".

Если программе не разрешено нормально закрывать ОС, тогда не существует языка, способного сделать это на любом языке. Для этого вам придется использовать какой-то вызов ОС.

Обратите внимание, что приведенный вами пример не был вызовом Java, а вызовом JVM. JVM = виртуальная машина Java... в основном ОС Java. Вы можете сделать тот же самый вызов от Ada, предполагая, что ваш код Ada запущен на JVM. Если вы работаете под Windows, вам придется делать это с помощью системных вызовов Win32. Вы можете сделать это из Ada, но, очевидно, точные вызовы не определенно определенно на языке.