Systemd
觀看 sd-bus 屬性
我有一個 GUI,可以在其中顯示
ActiveState
幾個 systemd 服務。在 10Hz 時,我使用 sd-bus api 來查詢每個服務,如下所示:
sd_bus* bus; sd_bus_error err = SD_BUS_ERROR_NULL; char* msg = 0; sd_bus_default_system(&bus); sd_bus_get_property_string(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1/unit/foo_2eservice", "org.freedesktop.systemd1.Unit", "ActiveState", &err, &msg);
我的問題是,當我執行這段程式碼時,
/sbin/init
還是/lib/systemd/systemd-logind
消耗了大約 50% 的 CPU。分析程式碼顯示sd_bus_get_property_string
. 我需要減少呼叫此函式的次數。d-bus介面的自省很有意思:
busctl introspect \ org.freedesktop.systemd1 \ /org/freedesktop/systemd1/unit/foo_2eservice \ org.freedesktop.system1.Unit NAME TYPE SIGNATURE RESULT/VALUE FLAGS .Kill method si - - .Ref method - - - .Reload method s o - .ReloadOrRestart method s o - .ReloadOrTryRestart method s o - .ResetFailed method - - - .Restart method s o - .SetProperties method ba(sv) - - .Start method s o - .Stop method s o - .TryRestart method s o - .Unref method - - - .ActiveEnterTimestamp property t 0 emits-change .ActiveEnterTimestampMonotonic property t 0 emits-change .ActiveExitTimestamp property t 0 emits-change .ActiveExitTimestampMonotonic property t 0 emits-change .ActiveState property s "inactive" emits-change ...
這告訴我 ActiveState 屬性發出了一個 change。
如何獲取文件描述符,或點擊事件循環以接收該更改?
D-Bus 規范建議 systemd 將在屬性更改時發出信號
org.freedesktop.DBus.Properties.PropertiesChanged
。我想我需要弄清楚如何訂閱該信號。
答案是用來
sd_bus_match_signal(3)
設置事件過濾器。您可以通過執行以下操作之一來監聽事件:
sd_bus_wait(3)
阻塞直到事件發生並sd_bus_process(3)
處理它們。- 連接
sd-bus
到sd-event
循環sd_bus_attach_event(3)
(您可能還需要設置 sd-event 循環)。- 使用
sd_bus_get_fd(3)
,sd_bus_get_events(3)
和sd_bus_get_timeout(3)
將 sd-bus 連接到您自己的事件循環。這是一個簡短的 C 範例,說明如何執行此操作:
/* gcc main.c -lsystemd */ #include <systemd/sd-bus.h> #include <stdio.h> #include <stdlib.h> static inline const char *strna(const char *s) { return s ?: "n/a"; } int message_callback(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) { printf("callback: path=%s interface=%s member=%s\n", strna(sd_bus_message_get_path(m)), strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)) ); return 0; } int main() { sd_bus* bus = NULL; sd_bus_error err = SD_BUS_ERROR_NULL; char* msg = NULL; void* userdata = NULL; sd_bus_default_system(&bus); sd_bus_match_signal( bus, /* bus */ NULL, /* slot */ NULL, /* sender */ "/org/freedesktop/systemd1/unit/foo_2eservice", /* path */ "org.freedesktop.DBus.Properties", /* interface */ "PropertiesChanged", /* member */ NULL /*message_callback*/ , /* callback */ userdata ); while( 1 ) { sd_bus_wait(bus, UINT64_MAX); while ( sd_bus_process(bus, NULL) ) { } sd_bus_get_property_string( bus, /* bus */ "org.freedesktop.systemd1", /* destination */ "/org/freedesktop/systemd1/unit/foo_2eservice", /* path */ "org.freedesktop.systemd1.Unit", /* interface */ "ActiveState", /* member */ &err, &msg); printf("New state: %s\n", msg); free(msg); } sd_bus_error_free(&err); sd_bus_message_unref(ret); sd_bus_unref(bus); return 0; }
我已經註釋掉了回調機制。
請注意,您會收到有關任何單位屬性更改的消息。因此,如果您執行類似的操作
systemctl stop
,您可能會收到幾條消息。