
이벤트 모니터가 알려주는 입력 이벤트에 대해 조건부로 특정 작업을 실행하는 스크립트를 작성했는데, 이는 다음과 같습니다.
$ cat script.sh
-----------------------------------------------------------
#!/usr/bin/bash
stdbuf -oL /usr/bin/event_monitor | while IFS= read LINE
do
something with $LINE
done
터미널 에서 스크립트로 실행하면 bash
스크립트는 정상적인 양의 CPU를 소비하고 새 줄이 인쇄될 때만 작업을 실행합니다. 그러나 다음 설정으로 서비스로 실행하는 경우
$ 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 스크립트가 아닌 모든 CPU를 사용하여 반복되는 것은 프로그램 입니다 .
systemd에서 실행될 때 STDIN에는 /dev/null이 연결되어 있습니다(또는 닫혀 있을 수도 있습니다). 메인의 이벤트 모니터 루프가 read(2)
EOF를 받고 다시 루프를 돌게 됩니다.
대화형으로 실행될 때 event_monitor에는 stdin에 연결된 터미널이 있으므로 read(2)
입력이 있을 때까지 차단됩니다.
event_monitor는 열려 있는 경우 stdin을 읽을 때만 반복해야 합니다. EOF를 받으면 종료되거나(이 경우에는 바람직하지 않음) 오랫동안 잠자기 상태로 있어야 합니다.
을 변경할 수 없는 경우 event_monitor
서비스의 stdin에 FIFO(명명된 파이프)를 연결하면 어느 정도 성공할 수 있습니다. systemd StandardInput
에는 StandardInput=file:/run/event_monitor_ctl
. 그런 다음 명명된 파이프를 생성하기만 하면 됩니다 /run/event_monitor_ctl
. 이를 위해 구성 파일(tmpfiles.d(5) 참조)을 생성하여 systemd-tmpfiles를 사용하여 명명된 파이프를 생성할 수 있습니다.