3

У меня есть команда, которую я звоню из кода:

execvp('generate', ...)

которая является исполняемой программой, с которой мой код связывается через stdin, stdout и stderr. Это отлично работает, ни одной проблемы.

Я хочу изменить это, чтобы я мог установить ограничения на ресурсы при generate . Итак, я попытался позвонить:

ulimit -t 1 && generate

Но я получаю сломанную трубу, когда пытаюсь с ней общаться.

Поэтому я поместил строку выше в сценарий оболочки generate_wrapper:

#!/bin/bash
ulimit -t 1 && generate

И я получаю сломанную трубу, когда пытаюсь с ней общаться.

Но

$ echo "foo" | generate_wrapper
$ echo "foo" | generate

оба дают мне правильный, идентичный вывод. Я подумал, что это может быть &&, поэтому я попробовал только голую команду:

#!/bin/bash
generate

Но он все еще работает с CL, и я все еще получаю прерванный канал, когда пытаюсь связаться с ним из кода.

Я попытался явно маршрутизировать FDS, и получил:

#!/bin/bash
generate >&1 2>&2 <&0

Но нет, я все еще получаю сломанный канал, когда пытаюсь связаться с ним из кода.

Поэтому, очевидно, я понятия не имею, что я делаю. Вы можете помочь? Как мне написать оболочку, чтобы я мог ulimit порожденный подпроцесс (rlimit недоступен для pids на моем языке хоста) и по-прежнему общаться с ним?

3 ответа3

1

По какой причине вы не хотите вызывать ulimit (2) в генерирующем коде перед execvp?

Со страницы руководства:

СИНТАКСИС
#include <ulimit.h>
long ulimit (int cmd, ...);

ОПИСАНИЕ
Функция ulimit () получит и установит пределы процесса.

1

EPIPE с его сообщением об ошибке "сломанная труба" возникает, когда сигнал SIGPIPE установлен так, что он игнорируется, и процесс записи пытается записать дальнейшие выходные данные в уже закрытый конец чтения канала, где, в вашем случае, generate имеет все файловые дескрипторы, ссылающиеся на к его стандартному закрытому.

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

Итак, в вашем случае программа, которая вызывает ваш generate исполняемый файл, установила игнорирование сигнала SIGPIPE . Затем, когда ваша generate программа в вашем generate_wrapper обработала ввод в течение одной секунды (ulimit -t 1), generate завершит работу и закроет свой стандартный ввод. Если ваш процесс записи с игнорированным SIGPIPE затем попытается записать дополнительные данные в теперь закрытый stdin generate системного вызова write произойдет сбой, и вы увидите EPIPE с его сообщением об ошибке "сломанный канал" (см. man 2 write).

Что касается оболочки для уменьшения потребления ресурсов процессора, используйте такие инструменты, как cstream или mbuffer.

# test: ulimit -t
#help ulimit
{
time -p bash -c 'yes | head -100000000 | wc -c'
echo
time -p bash -c 'ulimit -t 1; yes | head -100000000 | wc -c'
}

# cstream test
#top -u
yes | cstream -b 100000 -t 100000 -o -
yes | cstream -b 100000 -t 100000 | cat -n

# generate_wrapper
#!/bin/bash
cstream -b 100000 -t 100000 | generate
0

execvp не обрабатывает системные команды, а только прямые двоичные файлы. Также файлы сценариев являются только замаскированными системными командами таким образом.

Я думаю, что вам нужно использовать system(), если вы хотите запускать команды вместо двоичных файлов.

Идея dmckee о вызове ulimit() перед execvp() также является обоснованной. Это, однако, повлияет на все, что процесс делает с этого момента.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .