ActiveState
여러 시스템 서비스를 표시하는 GUI가 있습니다 .
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
CPU의 약 50%를 소비한다는 것입니다. 코드를 분석해 보면 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 속성을 알려줍니다.문제 변경 사항.
파일 설명자를 어떻게 얻거나 해당 변경 사항을 수신하기 위해 이벤트 루프에 들어가나요?
이것D-버스 사양org.freedesktop.DBus.Properties.PropertiesChanged
속성이 변경되면 systemd가 신호를 생성함을 나타냅니다 . 신호를 구독하는 방법을 알아내야 할 것 같아요.
답변1
댓글을 추가할 수 없으므로 @Stewart의 답변을 확장하고 있습니다. 신호를 활성화하려면 다음을 수행해야 합니다.신청그들에게:
Subscribe()는 대부분의 버스 신호를 보낼 수 있습니다. 신호에 관심이 있는 클라이언트는 이 메서드를 호출해야 합니다. 신호는 하나 이상의 클라이언트가 이 메서드를 호출할 때만 방출됩니다.
sd_bus_wait
왜 다시 돌아오지 않았는지 궁금하다면 다음과 같은 내용을 놓치고 있는 것입니다.
sd_bus_call_method(bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Subscribe",
&error,
NULL,
NULL);
답변2
대답은 사용하는 것입니다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
몇 가지 메시지를 받을 수 있습니다.