
我編寫了一個腳本來根據事件監視器通知的輸入事件運行特定操作,它看起來像
$ 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
程式在循環,耗盡了所有的 CPU,而不是你的 bash 腳本。
當在 systemd 下運行時,STDIN 附加了 /dev/null(甚至可能是關閉的)。當 main 中的事件監視器循環執行 a 時read(2)
,它會獲得 EOF,並再次循環。
以互動方式運作時,event_monitor 的終端連接到 stdin,因此read(2)
會阻塞,直到有輸入。
event_monitor 應該只在開啟的情況下循環讀取標準輸入。如果它收到 EOF,它應該退出(在這種情況下可能不合需要),或者只是休眠很長時間。
如果您無法更改event_monitor
,則可能會成功地將 FIFO(命名管道)附加到服務的 stdin。 systemd 有一個StandardInput
選項(記錄在 systemd.exec(5) 手冊頁中),您可以在其中指定StandardInput=file:/run/event_monitor_ctl
.然後你只需要建立/run/event_monitor_ctl
命名管道。為此,您可以透過建立設定檔(請參閱 tmpfiles.d(5))來使用 systemd-tmpfiles 來建立該命名管道。