вторник, 19 марта 2019 г.

Обработка Ctrl+C для хост-программ MiniMono

При запуске программ выполняющих длительные операции иногда возникает необходимость прервать их выполнение. Статья описывает как это выполнить для консольных и GUI программ.

Для прерывания программ в консольном варианте процесса MiniM Database Server поддерживается обработка клавишной комбинации Ctrl+C. При ее нажатии процесс генерирует ошибку INTERRUPT.

Несмотря на то, что процесс выполняет команды, Windows вызывает установленный обработчик нажатия Ctrl+C в отдельном контексте. В этом контексте программа не имеет возможности вызывать многие функции, но может изменить состояние внутренней переменной. Интерпретатор MiniM периодически проверяет взведен ли этот внутренний индикатор, но уже в регулярном контексте выполнения. И, если взведен, то генерирует ошибку INTERRUPT. Кроме того, реагирование на Ctrl+C встроено в процедуру чтения символов с клавиатуры.

Для того, чтобы можно было прервать также и контекст выполнения MiniMono, в программном интерфейсе MiniMono начиная с версии 1.12 предусмотрена функция CtrlBreakVM:
extern "C" __declspec( dllexport) 
  void __stdcall CtrlBreakVM( int set_break);
Если значение set_break равно 0, то индикатор прерывания снимается, иначе взводится. Эта функция предназначена для вызова из контекста обработчика прерывания клавишной комбинации Ctrl+C. Кроме того, ее можно вызывать из любого другого контекста, в том числе GUI-ориентированных приложений.

Для использования обработчика необходимо выполнить следующие действия:
  • Импортировать указатель на функцию CtrlBreakVM.
  • Описать обработчик прерывания.
  • В обработчике при условии прерывания вызвать установку индикатора прерывания.
  • Установить обработчик.
  • При завершении программы снять обработчик прерывания.
На языке С++ эти действия выглядят типовым образом:

Обработчик прерывания:
#include <windows.h>
#include "minimono.h"
#include "zdevice.h"

static ctrlbreakvm_t CtrlBreakVM = NULL;

BOOL WINAPI ConsoleHandler( DWORD dwCtrlType)
{
  switch( dwCtrlType)
  {
    case CTRL_C_EVENT:      // нажали Ctrl+C
    case CTRL_BREAK_EVENT:  // нажали Ctrl+Break
      if( CtrlBreakVM)
      {
        CtrlBreakVM( 1);
      }
      break;
  }
  return TRUE;
};
Импорт функции установки индикатора и установка обработчика прерывания после создания виртуальной машины MiniMono:
  CtrlBreakVM = (ctrlbreakvm_t)GetProcAddress( hModule, "CtrlBreakVM");
  SetConsoleCtrlHandler( ConsoleHandler, TRUE);
Снятие обработчика прерывания перед окончанием программы:
  SetConsoleCtrlHandler( ConsoleHandler, FALSE);
При установке обработчика прерывания таким образом процесс сможет передать виртуальной машине MiniMono сигнал о необходимости прерывания.

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

Комментариев нет:

Отправить комментарий