Eu tenho uma GUI onde ActiveState
mostro vários serviços do systemd.
Em 10Hz, uso a API sd-bus para consultar cada serviço assim:
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);
Meu problema é que quando executo esse código, /sbin/init
ou /lib/systemd/systemd-logind
consome cerca de 50% da CPU. A criação de perfil do código mostra uma enorme quantidade de tempo consumido pelo sd_bus_get_property_string
. Preciso reduzir o número de vezes que chamo essa função.
A introspecção da interface d-bus é interessante:
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
...
Isso me diz que a propriedade ActiveState emite uma alteração .
Como posso obter um descritor de arquivo ou tocar no loop de eventos para receber essa alteração?
A especificação D-Bus sugere que o systemd emitirá um org.freedesktop.DBus.Properties.PropertiesChanged
sinal quando as propriedades mudarem. Acho que preciso descobrir como assinar esse sinal.
Não tenho permissão para adicionar comentários, portanto, estendo a resposta de @Stewart. Para habilitar os sinais, é preciso assiná -los:
Se você está se perguntando por que
sd_bus_wait
nunca retorna, então está perdendo algo comoA resposta é usar
sd_bus_match_signal(3)
para configurar um filtro para eventos.Você ouve eventos fazendo um dos seguintes:
sd_bus_wait(3)
bloquear até que os eventos aconteçam esd_bus_process(3)
tratá-los.sd-bus
-se aosd-event
loop comsd_bus_attach_event(3)
(talvez seja necessário configurar o loop sd-event também).sd_bus_get_fd(3)
esd_bus_get_events(3)
parasd_bus_get_timeout(3)
conectar o sd-bus ao seu próprio loop de eventos.Aqui está um pequeno exemplo em C de como fazer isso:
Eu comentei os mecanismos de retorno de chamada.
Observe que você recebe uma mensagem para uma alteração em qualquer uma das propriedades da unidade. Portanto, se você fizer algo como
systemctl stop
, poderá esperar várias mensagens.