OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Пятница, 20 Июнь, 2025 11:06

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 7 ] 
Автор Сообщение
 Заголовок сообщения: Снятие задачи по таймауту
СообщениеДобавлено: Воскресенье, 06 Январь, 2008 19:21 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2461
Откуда: Россия, Томск
Есть подсистема для локального тестирования олимпиадных (и прочих учебных) задач для школ. Пишешь решение, тыкаешь коммандер, решение прогоняется на наборе тестовых входных-выходных файлов. Это работает.

Задача такая. Если программа думает более 5 секунд, надо вежливо попросить её на выход и сообщить, что вышло время ожидания на тесте таком-то.
Как сделать таймер и зарядить его на 5 секунд я подсмотрел в DevProfiler. Это работает. Как снять задачу? HALT или ASSERT в обработчике таймера не прокатят, поскольку обработчик выполняется (насколько я понял) в контексте другого потока.

Я подумал сделать по аналогии с Ctrl+Break. Там основной поток ставится на паузу, после чего в его контексте устанавливается флаг трэпа:
Код:
      res := KERNEL32.SuspendThread(main);
      context.flags := {0, 16};
      res := KERNEL32.GetThreadContext(main, context);
      INCL(SYSTEM.VAL(SET, context.pf), 8);   (* set trap flag *)
      res := KERNEL32.SetThreadContext(main, context);
      res := KERNEL32.ResumeThread(main)

Если бы это удалось, то достаточно было бы проигнорировать последующий трэп (обработка трэпов при работе тестируемой задачи тоже уже реализована). Проблема в том, что Kernel.TryHandler игнорирует создаваемый таким образом трэп EXCEPTION_SINGLE_STEP, если переменная Kernel.interrupted = FALSE (устанавливается в TRUE только в обработчике Ctrl+Break). Эта переменная не экспортирована.

Как бы нам в такой ситуации поступить? Экспортировать Kernel.interrupted не хочется. Ещё более не хочется видеть сообщение "keyboard interrupt". Возможно ли возбудить исключение с кодом 128, которое отработает без шума и пыли? Может быть кто-то может порекомендовать какое-нибудь шаманство с Context.ip (instruction pointer)? Например, прыжок в процедуру/на инструкцию HALT(128), но это я корректно сделать не умею.

Какие мысли есть по этому поводу?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Снятие задачи по таймауту
СообщениеДобавлено: Воскресенье, 06 Январь, 2008 20:19 
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Александр Ильин писал(а):
Экспортировать Kernel.interrupted не хочется.

Я бы выставил interrupted с помощью метапрограммирования (Kernel-средствами).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Снятие задачи по таймауту
СообщениеДобавлено: Воскресенье, 06 Январь, 2008 21:03 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2461
Откуда: Россия, Томск
Илья Ермаков писал(а):
Я бы выставил interrupted с помощью метапрограммирования (Kernel-средствами).

Интересная идея, спасибо : )

Это всё же не решает проблему "тихого" прерывания: открывается окно трэпа "прерывание с клавиатуры", а причём здесь клавиатура? Видимо, придётся немного доработать Kernel.TryHandler и ввести дополнительные возможности. Сделал вот как: добавил опубликованную процедуру Kernel.TrapMainThread, перенёс в неё код из обработчика Ctrl-Break (эта процедура теперь оттуда вызывается). Получается законный способ прервать работу.
Код:
PROCEDURE TrapMainThread* (silent: BOOLEAN; timeOut: INTEGER): BOOLEAN;
(* Interrupt the current activity of the main thread with a trap. If silent, don't show any trap window, otherwise "keyboard interrupt" will be reported. The main thread will not be interrupted if it is currently running in the Kernel module. If timeOut > 0, it specifies the time in msec during which to try to interrupt the main thread. If timeOut < 0 then try until success. If timeOut = 0, then try exactly once. The procedure returns TRUE on success or FALSE on timeout. *)

PS: Знаю, что в ядре копаться не хорошо, что это потом всё труднее и труднее поддерживать и портировать между версиями Блэкбокса. Удалось в данном случае отделаться минимальным вмешательством и исключительно расширением интерфейса. С другой стороны, как иначе реализовать необходимый функционал, если изначально требуемая гибкость не заложена? Теперь получится, что доработанная мной подсистема Info21olimp не со всяким ядром будет работать.
Вот здесь-то мне и пригодится метапрограммирование. Буду искать в Kernel процедуру TrapMainThread. Если есть - вызывать, если нет - пользователь увидит клавиатурный трэп. Но это я буду завтра дорабатывать, сейчас отдыхать пора.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Снятие задачи по таймауту
СообщениеДобавлено: Воскресенье, 06 Январь, 2008 21:13 
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Ладно, будет окончательное многопоточное решение - будет гораздо проще.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Снятие задачи по таймауту
СообщениеДобавлено: Понедельник, 07 Январь, 2008 15:48 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2461
Откуда: Россия, Томск
Илья Ермаков писал(а):
Я бы выставил interrupted с помощью метапрограммирования (Kernel-средствами).

Илья, подскажите, как это сделать. Kernel.ThisObject проходит только по экспортированным сущностям.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Снятие задачи по таймауту
СообщениеДобавлено: Понедельник, 07 Январь, 2008 16:07 
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Это не через метаинформацию, а через символьную информацию (Kernel.GetRefXX). Тонкости уже подзабыл, но как пример можно взять DevDebug.ShowGlobals, ну и по GetRefProc/GetRefVar посмотрите их описание в документации Kernel в Wiki.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Снятие задачи по таймауту
СообщениеДобавлено: Понедельник, 07 Январь, 2008 17:47 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2461
Откуда: Россия, Томск
Илья Ермаков писал(а):
Это не через метаинформацию, а через символьную информацию (Kernel.GetRefXX). Тонкости уже подзабыл, но как пример можно взять DevDebug.ShowGlobals, ну и по GetRefProc/GetRefVar посмотрите их описание в документации Kernel в Wiki.

Спасибо, получилось! Теперь подсистема Info21olimp может работать как с доработанной версией ядра, так и с оригинальной. Во втором случае при превышении допустимого времени работы пользователь увидит трэп, словно он сам нажал Ctrl+Break, а система тестирования занесёт в журнал запись о принудительном прерывании. Правда, для этого пришлось скопировать код выставления трэпа из Kernel.KeyboardWathcer в Info21olimpTest.

Задно подправил в wiki описание GetRefVar. По прежнему описанию не работало, реализовал по образцу DevDebug.ShowGlobals и поправил документ.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 7 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2025, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB