сценарий к процессу ограничения времени на posix - PullRequest
0 голосов
/ 04 декабря 2010

Мне нужно вызвать system () и popen () для запуска команды cmd, чтобы процесс был ограничен по времени.Код результата должен быть таким же, если процесс завершен, иначе должна быть возможность обнаружить, что истекло время ожидания.Должен работать в системах posix (по крайней мере, в Linux и OSX).

По крайней мере, в OSX sh -c "ulimit -tn; cmd" не работает из интерактивного приглашения (ulimit -tn); cmd) работает, но также ограничивает командный процесс (делая эту оболочку бесполезной).Это может не иметь значения.

Внешний сценарий нежелателен: он затрудняет перемещение программы, используя ее, если бы я хотел с этим смириться, я мог бы просто написать программу на Си.

Моя альтернатива - использовать fork () / exec () внутри моей программы: я могу это сделать, но код довольно уродлив (требует как минимум две вилки, возиться с файловыми дескрипторами) и будет запускать только исполняемый файл.

В Linux есть программа с синхронизацией времени, но она недоступна в OSX (и я не могу найти исходный код).Аналогичный вопрос был задан на SO с немного другими требованиями: мне нужен правильный код возврата, и он должен работать с popen ().

Ответы [ 2 ]

1 голос
/ 05 декабря 2010

Здесь есть Perl-скрипт , здесь , который сохраняет код завершения команды, которая завершает или возвращает 255, если время ожидания истекло. Он работает аналогично timeout, который был написан Wietse Venema (автор Postfix ) и впервые выпущен как часть SATAN .

Вот источник C для другой версии, которая является частью GNU coreutils начиная с версии 7 (2008-10-05) [бета].

0 голосов
/ 05 декабря 2010

В GNU coreutils есть программа 'timeout', которую можно легко скомпилировать для MacOS X (я нашел ее на своем компьютере в поисках собственной одноименной программы).

В качестве альтернативы, у меня есть версия, которую я написал примерно в 1989 году. Для правильной работы на MacOS X потребовалось несколько приемов. ( Свяжитесь со мной, если вам нужен код - см. Мой профиль .)


Вот сценарий оболочки, который приблизительно соответствует тому, что вы хотите.Он не может удовлетворить все ваши требования: в частности, он не может надежно ретранслировать состояние выхода.Он уже достаточно искривлен, чтобы сделать программу на C тривиальной.Оболочка (bash, во всяком случае) не помогает, если не переоценивать «$$» (текущий идентификатор процесса) для подоболочек;он по-прежнему полагает, что идентификатор процесса суб-оболочек совпадает с родительским процессом.

#!/bin/bash
# timeout -t time [-s signal] cmd [arg ...]

usage()
{
    echo "Usage: $(basename $0 .sh) -t time [-s signal] cmd [arg ...]" 1>&2
    exit 1
}

signal=15
while getopts t:s: opt "$@"
do
    case $opt in
    (t) time=$OPTARG;;
    (s) signal=$OPTARG;;
    (*)  usage;;
    esac
done
shift $((OPTIND - 1))
[ $# -ne 0 ]   || usage
[ -n "$time" ] || usage

pid_top=$$
# Run the command
(
    ("$@") &
    pid_sub=$!
    echo $pid_sub > .pid.$pid_top
    trap "kill $signal $pid_sub 2>/dev/null;
          kill 15 $pid_top 2>/dev/null; exit 1" 15
    wait
    kill $signal $pid_top 2>/dev/null
) &
pid_shell=$!
pid_cmd=$(cat .pid.$pid_top; rm -f .pid.$pid_top)
# Watchdog timer
(sleep $time; kill $signal $pid_cmd 2>/dev/null;
 kill -15 $pid_shell $pid_top) &
pid_watch=$!
# Cleanup!
trap "kill $signal $pid_cmd 2>/dev/null;
      kill 15 $pid_shell $pid_watch 2>/dev/null; exit 1" 15
wait

Логика обработки аргументов в основном стандартная - вы должны указать время, вы можете указать сигнал, вынеобходимо указать команду, вы можете указать аргументы для этой команды.

Основной сценарий оболочки отмечает собственный идентификатор процесса в переменной pid_top для удобства вложенных оболочек (хотя '$$', вероятно, будет работать).

Затем основная оболочка запускает фоновую вложенную оболочку для запуска команды, но здесь необходимы махинации.Сначала вспомогательная оболочка выполняет фактическую команду в фоновом режиме, захватывая идентификатор подпроцесса в pid_sub.Затем он передает этот PID в файл '.pid. $ Pid_top', чтобы родительская оболочка могла прочитать его и организовать отправку угроз смерти фактической команде, если время ожидания истекло.Затем он организует захват сигнала 15 (SIGTERM);при получении такого сигнала он убивает фактическую команду с помощью сигнала, запрошенного в командной строке, а также отправляет сигнал завершения родительскому процессу.Тогда это уходит в ожидание.Если команда завершается, она отправляет сигнал завершения родительскому процессу, сообщая родителю, что все в порядке.

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

Итак, теперь в фоновом режиме работают три процесса.(ой - это сбивает с толку);текущая команда, вспомогательная оболочка, ожидающая выполнения команды, и сторожевой таймер.

Основная оболочка захватывает PID сторожевого таймера и организует перехват сигнала 15. При получении сигнала он отправляетсоответствующий сигнал завершения для фактической команды и сигнал завершения для вспомогательной оболочки и сторожевого таймера, даже если хотя бы один из них не существует.

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

Затем он завершится ...

Чтобы получить точный статус от выполненногоКоманда сложная.Проблема в том, что если оболочка запускает процесс в фоновом режиме, вы не можете получить его состояние выхода;но если вы запустите его синхронно (чтобы вы могли получить статус выхода), тогда сторожевой таймер и основной процесс не будут знать свой PID и не смогут гарантировать его завершение, когда закончится таймер.Возможно, я просто упускаю очевидное - я, безусловно, надеюсь, потому что этот сценарий ужасен!Для себя я буду придерживаться C-программы;он использует только два процесса и возвращает актуальный статус команды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...