
Я написал скрипт для запуска определенных действий в зависимости от событий ввода, о которых сообщает монитор событий. Он выглядит примерно так:
$ cat script.sh
-----------------------------------------------------------
#!/usr/bin/bash
stdbuf -oL /usr/bin/event_monitor | while IFS= read LINE
do
something with $LINE
done
При запуске в качестве скрипта из bash
терминала скрипт потребляет обычное количество ресурсов ЦП и выполняет действие только при печати новой строки. Однако при запуске в качестве службы со следующей настройкой
$ cat event.service
-----------------------------------------------------------
[Unit]
Description=Actions upon events
[Service]
Type=simple
ExecStart=/path/to/script.sh
[Install]
WantedBy=default.target
Теперь команда event_monitor
захватывает все логическое ядро и strace
показывает, что ничего не read
делает read()
так часто, как позволяет процессор:
$ strace -p $event_monitor_pid
-----------------------------------------------------------
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
................ad nauseum
в то время как служба все еще регистрирует события и выполняет условные команды, когда происходят реальные события. Что здесь пошло не так?
ps это происходит с , cras_monitor
но не с acpi_listen
. Я пытался убедиться, что while
цикл запускается только после того, как базовая служба успешно запустится, но безуспешно.
Обновление: вот некоторые потенциально важные фрагменты event_monitor
кода:
...
#include <headers.h>
...
# Print to console function:
static void event_occurrence(void *context, int32_t attribute)
{
printf("Some attribute has changed to %d.\n", attribute);
}
...
int main(int argc, char **argv)
{
struct some_service_client *client # defined in headers
int rc
...
# Some routine
...
some_service_client_set_event_occurence_callback(client,event_occurence)
...
rc = some_func(client)
...
while (1) {
int rc;
char c;
rc = read(STDIN_FILENO, &c, 1);
if (rc < 0 || c == 'q')
return 0;
}
...
}
решение1
Это ваша event_monitor
программа зацикливается, используя все ресурсы процессора, а не ваш bash-скрипт.
При запуске под systemd STDIN имеет присоединенный /dev/null (или, возможно, даже закрыт). Когда цикл монитора событий в main делает a read(2)
, он получает EOF и снова проходит по циклу.
При интерактивном запуске event_monitor подключает терминал к stdin, поэтому read(2)
блокируется до тех пор, пока не поступит ввод.
event_monitor должен зацикливаться только на чтении stdin, если он открыт. Если он получает EOF, он должен либо выйти (вероятно, нежелательно в этом случае), либо просто спать долгое время.
Если вы не можете изменить event_monitor
, вы можете добиться некоторого успеха, прикрепив FIFO (именованный канал) к stdin службы. systemd имеет опцию StandardInput
(задокументированную на странице man systemd.exec(5)), где вы можете указать StandardInput=file:/run/event_monitor_ctl
. Затем вам просто нужно создать /run/event_monitor_ctl
именованный канал. Для этого вы можете использовать systemd-tmpfiles, создав файл конфигурации (см. tmpfiles.d(5)) для создания этого именованного канала.