openbmc dbus架构简析

守听  金牌会员 | 2024-12-26 06:44:03 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 979|帖子 979|积分 2937

1.说明

openbmc是基于systemd的,dbus的库实现是在systemd。对于用户(app)使用来说,用的是sd-bus相关接口,即lib库,它在systemd中已有提供。系统提供一个总线(dbus daemon),实际是一个进程程序,这个进程程序(dbus的实现dbus-daemon或者dbus-borker的dbus-broker-launcher)会用到systemd实现的库接口,client和server的通讯经过这个进程来转发数据,当然,client和server代码的编写也会依赖systemd的库接口。
总体而言,openbmc做了一个sdbusplus的c++ binding,然后该binding使用的是systemd提供的函数接口等。systemd的源码可以参考https://github.com/systemd/systemd. binding简朴明确就是c++调用c,其他c++应用程序直接调用binding函数,即是c++层的库。
可以在https://en.wikipedia.org/wiki/D-Bus中找到相关描述:

   备注:openbmc 有关dbus的资料:
  

  • 1.https://dbus.freedesktop.org/doc/dbus-specification.html
  • 2.https://dbus.freedesktop.org/doc/dbus-tutorial.html
  • 3.https://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html
  • 4.https://github.com/systemd/systemd
  • 5.接口api:https://github.com/systemd/systemd/blob/main/src/systemd/sd-bus.h
  • 6.openbmc实现的sdbus c++ binding: https://github.com/openbmc/sdbusplus
总体而言,对于开发openbmc,可以先看d-bus的基本概念,然后基于此,知道openbmc用到systemd和c++ binding就差不多了。
别的,补充systemd的中文参考手册:


  • 7.systemd.unit中文手册
  • 8.systemd.service中文手册
  • 9.redhat systemd介绍
2.openbmc使用的systemd与d-bus说明

参考文章: https://opensource.com/article/20/4/systemd可以看到systemd的架构图:

2.1 openbmc使用的dbus

先使用ast2500平台为例,平台信息如下:

检察dbus使用的daemon服务:

同样,可以使用如下下令检察服务:
  1. # cat /etc/systemd/system/dbus.service
复制代码

使用下令,均可检察信息:
  1. # cat /lib/systemd/system/dbus-broker.service
复制代码

别的,也可以观察到系统也包含dbus的实现。

对应,可以检察目录:

谈到这里,可以列出来现在BMC的dbus的实现包含2个:


  • 1.https://www.freedesktop.org/wiki/Software/dbus/
  • 2.https://github.com/bus1/dbus-broker
现在BMC使用的是dbus-borker.
2.2 简朴分析一下dbus-broker流程

分析dbu-broker流程前,首先需要阅读2篇文章:


  • systemd for Developers I
  • systemd for Developers II
  • systemd 默认的输入输出流
  • 1.简朴分析一下dbus-broker-launch代码流程:
  1. src\launch\main.c
  2. int main(int argc, char **argv)
  3. ---> r = parse_argv(argc, argv);
  4. ---> r = inherit_fds();
  5.         ---> n = sd_listen_fds(true);
  6.         ---> s = SD_LISTEN_FDS_START;
  7.         ---> r = sd_is_socket(s, PF_UNIX, SOCK_STREAM, 1);
  8.         ---> r = fcntl(s, F_GETFL);
  9.         ---> r = fcntl(s, F_SETFL, r | O_NONBLOCK);
  10.         ---> main_fd_listen = s;
  11.         ---> r = run();
  12.                 ---> r = launcher_new(&launcher, main_fd_listen, main_arg_audit, main_arg_configfile, main_arg_user_scope);
  13.                         ---> r = launcher_open_log(launcher);
  14.                                 ---> .sun_path = "/run/systemd/journal/socket",
  15.                                 ---> fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
  16.                                 ---> connect(fd,(struct sockaddr *)&address,offsetof(struct sockaddr_un, sun_path) + strlen(address.sun_path));
  17.                                 ---> log_init_journal_consume(&launcher->log, fd);
  18.                         ---> r = sd_event_default(&launcher->event);
  19.                         ---> r = sd_event_add_signal(launcher->event, NULL, SIGTERM, NULL, NULL);
  20.                         ---> r = sd_event_add_signal(launcher->event, NULL, SIGINT, NULL, NULL);
  21.                         ---> r = sd_event_add_signal(launcher->event, NULL, SIGHUP, launcher_on_sighup, launcher);
  22.                         ---> r = sd_bus_new(&launcher->bus_controller);
  23.                 ---> r = launcher_run(launcher);
  24.                         ---> r = launcher_parse_config(launcher, &root, &nss_cache);
  25.                                 ---> configfile = "/usr/share/dbus-1/system.conf";
  26.                                 ---> config_parser_init(&parser); //XML parser
  27.                                 ---> config_parser_read(&parser, rootp, configfile, nss_cache, dirwatch); //解析/usr/share/dbus-1/system.conf
  28.                                 ---> r = sd_event_add_io(..., launcher_on_dirwatch,...) //重新加载文件
  29.                         ---> r = launcher_load_services(launcher, root, &nss_cache);
  30.                         ---> r = sd_notify(false, "READY=1");
  31.                         ---> r = launcher_load_policy(launcher, root, &policy);
  32.                         ---> r = socketpair(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, controller); //创建一对双向通信的client/server. 注意是双向通信
  33.                         ---> r = sd_bus_set_fd(launcher->bus_controller, controller[0], controller[0]);
  34.                                 ---> bus->input_fd = input_fd; //systemd的代码,输入设置为controller[0]
  35.                                 ---> bus->output_fd = output_fd;//systemd的代码,输出均设置为controller[0]
  36.                         ---> r = launcher_fork(launcher, controller[1]); //
  37.                                 ---> launcher_run_child(launcher, log_get_fd(&launcher->log), fd_controller);
  38.                                         ---> const char * const argv[] = {"dbus-broker", ...}
  39.                                         ---> r = sd_id128_get_machine(&machine_id);
  40.                                         ---> sd_id128_to_string(machine_id, str_machine_id);
  41.                                         ---> r = execve(main_arg_broker, (char * const *)argv, environ);
  42.                                 ---> r = sd_event_add_child(launcher->event, NULL, pid, WEXITED, launcher_on_child_exit, launcher); //建立子进程,在子进程中创建dbus-broker 进程。
  43.                         ---> r = sd_bus_add_object_vtable(launcher->bus_controller, NULL, "/org/bus1/DBus/Controller", "org.bus1.DBus.Controller", launcher_vtable, launcher);
  44.                         ---> r = sd_bus_add_filter(launcher->bus_controller, NULL, launcher_on_message, launcher);  //launcher_on_message 是一个很重要的函数
  45.                         ---> r = sd_bus_start(launcher->bus_controller);
  46.                         ---> r = launcher_add_services(launcher);
  47.                         ---> r = launcher_add_listener(launcher, &policy, system_console_users, n_system_console_users);
  48.                         ---> r = launcher_connect(launcher);
  49.                         ---> r = sd_bus_attach_event(launcher->bus_controller, launcher->event, SD_EVENT_PRIORITY_NORMAL);
  50.                         ---> r = sd_bus_attach_event(launcher->bus_regular, launcher->event, SD_EVENT_PRIORITY_NORMAL);
  51.                         ---> r = launcher_subscribe(launcher);
  52.                         ---> r = sd_event_loop(launcher->event);
复制代码
以是回顾一下之前看到的控制台有2个进程,分别为:/usr/bin/dbus-broker-launch和dbus-broker。此中dbus-broker-launch是由systemd以服务启动的。而dbus-broker则是由如下代码启动起来的。
  1. const char * const argv[] = {"dbus-broker", ...}
  2. execve(main_arg_broker, (char * const *)argv, environ);
复制代码
检察文件/usr/lib/systemd/user/dbus.socket的内容:
  1. # cat /usr/lib/systemd/user/dbus.socket
  2. [Unit]
  3. Description=D-Bus User Message Bus Socket
  4. [Socket]
  5. ListenStream=%t/bus
  6. ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
复制代码
与文件/lib/systemd/system/dbus-broker.service的内容:
  1. root@ast2500-default:/# cat /lib/systemd/system/dbus-broker.service
  2. [Unit]Description=D-Bus System Message BusDocumentation=man:dbus-broker-launch(1)DefaultDependencies=falseAfter=dbus.socketBefore=basic.target shutdown.targetRequires=dbus.socketConflicts=shutdown.target[Service]Type=notifySockets=dbus.socketOOMScoreAdjust=-900LimitNOFILE=16384ProtectSystem=fullPrivateTmp=truePrivateDevices=trueExecStart=/usr/bin/dbus-broker-launch --scope system --auditExecReload=/usr/bin/busctl call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus ReloadConfig[Install]Alias=dbus.service
复制代码
简朴分析函数inherit_fds(),如下:
  1. static int inherit_fds(void)
  2. ---> n = sd_listen_fds(true);  //来自于systemd的函数,参数为true.
  3.                 ---> e = getenv("LISTEN_PID");
  4.                 ---> r = parse_pid(e, &pid);
  5.                 ---> e = getenv("LISTEN_FDS");
  6.                 ---> r = safe_atoi(e, &n);
  7.                 ---> for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++)
  8.                         ---> r = fd_cloexec(fd, true);  //在fork子进程后关闭相关描述符
  9.                 ---> unsetenv_listen(unset_environment); //子进程不需要使用这些环境变量
  10. ---> s = SD_LISTEN_FDS_START;  // s = 3
  11. ---> r = sd_is_socket(s, PF_UNIX, SOCK_STREAM, 1); //判断是否为socket
  12. ---> main_fd_listen = s;
复制代码
再分析一下sd_event_loop()代码,其界说在文件src\libsystemd\sd-event\sd-event.c(systemd代码):
  1. _public_ int sd_event_loop(sd_event *e)
  2. {
  3. ...
  4.         while (e->state != SD_EVENT_FINISHED) {
  5.                 r = sd_event_run(e, UINT64_MAX);
  6.                 if (r < 0)
  7.                         return r;
  8.         }
  9. ...
  10. }
复制代码
以是这是dbus-broker依赖于systemd的由来。


  • 2.简朴分析一下dbus-broker代码流程:
  1. src\broker\main.c
  2. int main(int argc, char **argv)
  3. ---> r = parse_argv(argc, argv);
  4. ---> r = setup();
  5. ---> r = bus_selinux_init_global();
  6. ---> r = run();
  7.         ---> r = broker_new(&broker, main_arg_machine_id, main_arg_log, main_arg_controller, main_arg_max_bytes, main_arg_max_fds, main_arg_max_matches, main_arg_max_objects);
  8.         ---> r = broker_run(broker);
  9.                 ---> r = connection_open(&broker->controller.connection);
复制代码
此中,函数broker_new()调用关系如下:
  1. broker_new()
  2. ---> controller_init()
  3.    ---> controller_dispatch_connection()
  4.       --->controller_dbus_dispatch()
  5.          --->controller_dispatch_object()
  6.             --->controller_dispatch_controller()
  7.                ---> controller_method_add_listener()
  8.                   ---> controller_add_listener()
  9.                      ---> listener_init_with_fd(...)
  10.                             ---> r = dispatch_file_init(&listener->socket_file,
  11.                                                                  dispatcher,listener_dispatch,
  12.                                                                  socket_fd,EPOLLIN,EPOLLIN);
复制代码
此中函数listener_dispatch()调用关系如下:
  1. static int listener_dispatch(DispatchFile *file)
  2. ---> peer_dispatch(DispatchFile *file)
  3.    ---> peer_dispatch_connection()
  4.       ---> driver_dispatch()
  5.          ---> driver_dispatch_internal()
  6.             ---> if (string_equal(message->metadata.fields.destination, "org.freedesktop.DBus"))
  7.                  ---> driver_dispatch_interface()
  8.                          ---> static const DriverInterface interfaces[] =
  9.                          ---> { "org.freedesktop.DBus", driver_methods },
  10.                          ---> { "org.freedesktop.DBus.Monitoring", monitoring_methods },
  11.                          ---> { "org.freedesktop.DBus.Introspectable", introspectable_methods },
  12.                          ---> { "org.freedesktop.DBus.Peer", peer_methods },
  13.                          ---> { "org.freedesktop.DBus.Properties", properties_methods },
  14.                          ---> { "org.freedesktop.DBus.Debug.Stats", debug_stats_methods },
  15.                          ---> }
  16.                         
复制代码
此中函数driver_methods()界说如下:
  1. static const DriverMethod driver_methods[] = {
  2.         { "Hello",                                      false,  NULL,                           driver_method_hello,                                            c_dvar_type_unit,       driver_type_out_s,     false },
  3.         { "AddMatch",                                   true,   NULL,                           driver_method_add_match,                                        driver_type_in_s,       driver_type_out_unit,  false },
  4.         { "RemoveMatch",                                true,   NULL,                           driver_method_remove_match,                                     driver_type_in_s,       driver_type_out_unit,  false },
  5.         { "RequestName",                                true,   NULL,                           driver_method_request_name,                                     driver_type_in_su,      driver_type_out_u,     false },
  6.         { "ReleaseName",                                true,   NULL,                           driver_method_release_name,                                     driver_type_in_s,       driver_type_out_u,     false },
  7.         { "GetConnectionCredentials",                   true,   NULL,                           driver_method_get_connection_credentials,                       driver_type_in_s,       driver_type_out_apsv,  true  },
  8.         { "GetConnectionUnixUser",                      true,   NULL,                           driver_method_get_connection_unix_user,                         driver_type_in_s,       driver_type_out_u,     false },
  9.         { "GetConnectionUnixProcessID",                 true,   NULL,                           driver_method_get_connection_unix_process_id,                   driver_type_in_s,       driver_type_out_u,     false },
  10.         { "GetAdtAuditSessionData",                     true,   NULL,                           driver_method_get_adt_audit_session_data,                       driver_type_in_s,       driver_type_out_ay,    false },
  11.         { "GetConnectionSELinuxSecurityContext",        true,   NULL,                           driver_method_get_connection_selinux_security_context,          driver_type_in_s,       driver_type_out_ay,    false },
  12.         { "StartServiceByName",                         true,   NULL,                           driver_method_start_service_by_name,                            driver_type_in_su,      driver_type_out_u,     false },
  13.         { "ListQueuedOwners",                           true,   NULL,                           driver_method_list_queued_owners,                               driver_type_in_s,       driver_type_out_as,    false },
  14.         { "ListNames",                                  true,   NULL,                           driver_method_list_names,                                       c_dvar_type_unit,       driver_type_out_as,    false },
  15.         { "ListActivatableNames",                       true,   NULL,                           driver_method_list_activatable_names,                           c_dvar_type_unit,       driver_type_out_as,    false },
  16.         { "NameHasOwner",                               true,   NULL,                           driver_method_name_has_owner,                                   driver_type_in_s,       driver_type_out_b,     false },
  17.         { "UpdateActivationEnvironment",                true,   "/org/freedesktop/DBus",        driver_method_update_activation_environment,                    driver_type_in_apss,    driver_type_out_unit,  false },
  18.         { "GetNameOwner",                               true,   NULL,                           driver_method_get_name_owner,                                   driver_type_in_s,       driver_type_out_s,     false },
  19.         { "ReloadConfig",                               true,   NULL,                           driver_method_reload_config,                                    c_dvar_type_unit,       driver_type_out_unit,  false },
  20.         { "GetId",                                      true,   NULL,                           driver_method_get_id,                                           c_dvar_type_unit,       driver_type_out_s,     false },
  21.         { },
  22. };
复制代码
此中,函数:driver_method_hello()界说如下:
  1. static int driver_method_hello(Peer *peer, const char *path, CDVar *in_v, uint32_t serial, CDVar *out_v)
  2. ---> unique_name = address_to_string(&(Address)ADDRESS_INIT_ID(peer->id));
复制代码
分析函数address_to_string():
  1. const char *address_to_string(Address *address)
  2. ---> case ADDRESS_TYPE_ID:
  3.         ---> r = snprintf(address->buffer, sizeof(address->buffer), ":1.%"PRIu64, address->id);
  4. ---> case ADDRESS_TYPE_NAME:
  5.         ---> return address->name;
复制代码
可以看到使用busctl后的显示:



  • 3.注册的bus
在文件:src\launch\launcher.c中,调用到函数:
  1. r = sd_bus_start(launcher->bus_controller);
复制代码
此中,界说了:sd_bus *bus_controller;,在函数sd_bus_start()界说如:
  1. src\libsystemd\sd-bus\sd-bus.c
  2. _public_ int sd_bus_start(sd_bus *bus)
  3. --->  bus_set_state(bus, BUS_OPENING);
  4. ---> r = bus_start_fd(bus);
  5. ---> bus_send_hello(bus);
  6.         ---> if (!bus->bus_client) return 0;
复制代码
在文件:src\launch\launcher.c中界说了launcher_connect():
  1. static int launcher_connect(Launcher *launcher)
  2. --->  r = sd_bus_open_system(&launcher->bus_regular);
  3.         ---> sd_bus_open_system_with_description(ret, NULL);
  4.                 ---> r = sd_bus_new(&b);
  5.                 ---> r = bus_set_address_system(b);
  6.                         ---> e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
  7.                         ---> r = sd_bus_set_address(b, e ?: DEFAULT_SYSTEM_BUS_ADDRESS); //默认bus为: "unix:path=/run/dbus/system_bus_socket"   //这里设置了bus->address
  8.                         ---> b->runtime_scope = RUNTIME_SCOPE_SYSTEM;
  9.                 ---> b->bus_client = true;
  10.                 ---> b->trusted = false;
  11.                 ---> b->is_local = true;
  12.                 ---> r = sd_bus_start(b);
  13.                         ---> bus_set_state(bus, BUS_OPENING);
  14.                         ---> r = bus_start_address(bus);
  15.                         ---> bus_send_hello(bus);
  16.                                 ---> r = sd_bus_message_new_method_call(..,.., "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus","Hello");
  17.                                 ---> sd_bus_call_async(bus, NULL, m, hello_callback, NULL, 0);
复制代码
因此,可以看到:
  1. * 第一个bus: launcher->bus_controller
  2. * 第二个bus: launcher->bus_regular
复制代码
第二个launcher->bus_regular作为系统总线,会调用hello方法.
别的:
  1. r = sd_bus_set_fd(launcher->bus_controller, controller[0], controller[0]);
  2. launcher->bus_controller->input_fd = controller[0];
  3. launcher->bus_controller->output_fd = controller[0];
复制代码
子进程使用controller[1]。


  • 4.小结
根据上面的描述,总结一下流程图:

要想检察原图,可以访问链接: https://gitee.com/wit_yuan/dbus-broker/blob/yuan_resources/dbus-broker.jpg
接着再分析一个比较有意思的逻辑,参考下图:

  1. * 1.inherit_fds()使用systemd机制获取到socket描述符(请先了解systemd的socket机制原理,会先接手socket服务,accept默认为no,因此需要sd_listen_fds()方法获取socket描述符)
  2. * 2.父子进程通过socketpair(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, controller);中的controller[0]和controller[1]进行连接
  3. * 3.sd_bus_set_fd(launcher->bus_controller, controller[0], controller[0]);使用该函数,实际bus->input_fd = input_fd;bus->output_fd = output_fd; 实际即为controller[0]
  4. * 4.sd_bus_call(launcher->bus_controller, m, 0, NULL, NULL);发送socket数据实际依靠的是controller[0],而子进程使用的是controller[1],通道打通,数据可以传递给子进程
  5. * 5.sd_bus_message_append(m, "oh","/org/bus1/DBus/Listener/0",launcher->fd_listen);把launcher->fd_listen 为总体的systemd的监听的socket描述符传递给了子进程。
复制代码
梳理到这里,着实花了一点时间去分析sdbus-broker代码和systemd机制与代码。如有错漏,大家可以继续补充,全网没看到有人真正分析过这内里的代码!!!
2.3 systemd的流程分析

2.3.1 配置文件

在redhat systemd 介绍 中,描述了如下内容:

2.3.2 journald分析

systemd集成了journald,用来统一系统的日志记载,简朴看一下流程:
  1. src\journal\journald.c
  2. static int run(int argc, char *argv[])
  3. ---> log_set_facility(LOG_SYSLOG);
  4. ---> umask(0022);
  5. ---> r = server_new(&s);       
  6.         ---> .syslog_fd = -EBADF,
  7.         ---> .stdout_fd = -EBADF,
  8. ---> r = server_init(s, namespace);
  9.         ---> r = sd_event_default(&s->event);
  10.         ---> n = sd_listen_fds(true);
  11.         ---> native_socket = strjoina(s->runtime_directory, "/socket");  ///run/systemd/journal/socket ??
  12.         ---> stdout_socket = strjoina(s->runtime_directory, "/stdout");  ///run/systemd/journal/stdout ??
  13.         ---> syslog_socket = strjoina(s->runtime_directory, "/dev-log"); ///run/systemd/journal/dev-log ??
  14.         ---> varlink_socket = strjoina(s->runtime_directory, "/io.systemd.journal"); ///run/systemd/journal/io.systemd.journal ??
  15.         ---> r = server_open_stdout_socket(s, stdout_socket);
  16.                 ---> r = sockaddr_un_set_path(&sa.un, stdout_socket);
  17.                 ---> s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
  18.                 ---> r = bind(s->stdout_fd, &sa.sa, sa_len);
  19.                 ---> listen(s->stdout_fd, SOMAXCONN_DELUXE)
  20.                 ---> r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
  21.         ---> r = server_open_syslog_socket(s, syslog_socket);
  22.                 ---> r = sockaddr_un_set_path(&sa.un, syslog_socket);
  23.                 ---> s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
  24.                 ---> r = bind(s->syslog_fd, &sa.sa, sa_len);
  25.                 ---> r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, true);
  26.                 ---> r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, true);
  27.                 ---> r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, server_process_datagram, s);
  28.                 ---> r = sd_event_source_set_priority(s->syslog_event_source, SD_EVENT_PRIORITY_NORMAL+5);
  29.         ---> r = server_open_native_socket(s, native_socket);
  30.                 ---> r = sockaddr_un_set_path(&sa.un, native_socket);
  31.                 ---> s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
  32.                 ---> r = bind(s->native_fd, &sa.sa, sa_len);
  33.                 ---> r = setsockopt_int(s->native_fd, SOL_SOCKET, SO_PASSCRED, true);
  34.                 ---> r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, server_process_datagram, s);
  35.         ---> r = server_open_dev_kmsg(s);
  36.                 ---> s->dev_kmsg_fd = open("/dev/kmsg", mode);    //打开内核缓冲
  37.                 ---> r = sd_event_add_io(s->event, &s->dev_kmsg_event_source, s->dev_kmsg_fd, EPOLLIN, dispatch_dev_kmsg, s);
  38.                 ---> r = sd_event_source_set_priority(s->dev_kmsg_event_source, SD_EVENT_PRIORITY_IMPORTANT+10);
  39.         ---> r = server_open_varlink(s, varlink_socket, varlink_fd);
  40.                 ---> r = sd_varlink_server_new(&s->varlink_server, SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_INHERIT_USERDATA);
  41.                 ---> sd_varlink_server_set_userdata(s->varlink_server, s);
  42.                 ---> r = sd_varlink_server_add_interface(s->varlink_server, &vl_interface_io_systemd_Journal);
  43.         ---> r = server_map_seqnum_file(s, "seqnum", sizeof(SeqnumData), (void**) &s->seqnum);
  44.         ---> r = server_open_kernel_seqnum(s);
  45.         ---> r = server_open_hostname(s);
  46.                 ---> r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
  47.                 ---> r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
  48.         ---> r = server_setup_signals(s);
  49.                 ---> r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr1, s);
  50.                 ---> r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr2, s);
  51.                 ---> r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
  52.                 ---> r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
  53.                 ---> r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
  54.                 ---> r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
  55.                 ---> r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, (SIGRTMIN+1)|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigrtmin1, s);
  56.                 ---> r = sd_event_add_signal(s->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, &s->sigrtmin18_info);
  57.         ---> server_connect_notify(s);
  58.                 ---> r = sockaddr_un_set_path(&sa.un, e);
  59.                 ---> s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
  60.                 ---> r = connect(s->notify_fd, &sa.sa, sa_len);
  61.                 ---> r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
  62.         ---> r = server_system_journal_open(s, /* flush_requested= */ false, /* relinquish_requested= */ false);
  63. ---> while(1)
  64. ---> ---> r = sd_event_get_state(s->event);
  65. ---> ---> r = sd_event_now(s->event, CLOCK_REALTIME, &n);
  66. ---> ---> r = sd_event_run(s->event, t);
  67. DEFINE_MAIN_FUNCTION(run);
复制代码
看一下函数实现:
  1. src\shared\main-func.h
  2. #define DEFINE_MAIN_FUNCTION(impl)   
  3.          _DEFINE_MAIN_FUNCTION(,impl(argc, argv), exit_failure_if_negative, exit_failure_if_negative)
  4. #define _DEFINE_MAIN_FUNCTION(intro, impl, result_to_exit_status, result_to_return_value) \
  5.         int main(int argc, char *argv[]) {                              \
  6.                 int r;                                                  \
  7.                 assert_se(argc > 0 && !isempty(argv[0]));               \
  8.                 save_argc_argv(argc, argv);                             \
  9.                 intro;                                                  \
  10.                 r = impl;                                               \
  11.                 if (r < 0)                                              \
  12.                         (void) sd_notifyf(0, "ERRNO=%i", -r);           \
  13.                 (void) sd_notifyf(0, "EXIT_STATUS=%i",                  \
  14.                                   result_to_exit_status(r));            \
  15.                 ask_password_agent_close();                             \
  16.                 polkit_agent_close();                                   \
  17.                 pager_close();                                          \
  18.                 mac_selinux_finish();                                   \
  19.                 static_destruct();                                      \
  20.                 return result_to_return_value(r);                       \
  21.         }
复制代码
分析函数:server_process_datagram()调用流程:
  1. int server_process_datagram(
  2.                 sd_event_source *es,
  3.                 int fd,
  4.                 uint32_t revents,
  5.                 void *userdata) {
  6. ---> if (fd == s->syslog_fd)
  7.         ---> server_process_syslog_message(s, s->buffer, n, ucred, tv, label, label_len);
  8.                 ---> if (s->forward_to_syslog)
  9.                         ---> forward_syslog_raw(s, priority, buf, raw_len, ucred, tv);
  10.                 ---> if (s->forward_to_kmsg)
  11.                         ---> server_forward_kmsg(s, priority, identifier, msg, ucred);
  12.                 ---> if (s->forward_to_console)
  13.                         ---> server_forward_console(s, priority, identifier, msg, ucred);
  14.                 ---> if (s->forward_to_wall)
  15.                         ---> server_forward_wall(s, priority, identifier, msg, ucred);
复制代码
分析server_forward_wall():
  1. void server_forward_wall(
  2.                 Server *s,
  3.                 int priority,
  4.                 const char *identifier,
  5.                 const char *message,
  6.                 const struct ucred *ucred)
  7. ---> r = wall(l, "systemd-journald", NULL, NULL, NULL);
  8.         ---> r = wall_utmp(text, match_tty, userdata);
  9.                 ---> utmpx = utxent_start();
  10.                         ---> setutxent();
  11.                 ---> while ((u = getutxent())) {
  12.                 --->         RET_GATHER(r, write_to_terminal(tty_path, message));
复制代码
此中write_to_terminal()界说:
  1. static int write_to_terminal(const char *tty, const char *message)
  2. ---> fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
  3. ---> loop_write_full(fd, message, SIZE_MAX, TIMEOUT_USEC);
  4.         ---> k = write(fd, p, nbytes);
复制代码
分析server_forward_console():
  1. void server_forward_console(
  2.                 Server *s,
  3.                 int priority,
  4.                 const char *identifier,
  5.                 const char *message,
  6.                 const struct ucred *ucred)
  7. ---> const char *tty,
  8. ---> tty = s->tty_path ?: "/dev/console";
  9. ---> fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
  10. ---> writev(fd, iovec, n)
复制代码
分析server_forward_kmsg()界说如下:
  1. void server_forward_kmsg(
  2.                 Server *s,
  3.                 int priority,
  4.                 const char *identifier,
  5.                 const char *message,
  6.                 const struct ucred *ucred)
  7. ---> writev(s->dev_kmsg_fd, iovec, n) //之前是打开的文件 open("/dev/kmsg", mode);
复制代码
分析函数forward_syslog_raw()界说如下:
  1. static void forward_syslog_raw(Server *s, int priority, const char *buffer, size_t buffer_len, const struct ucred *ucred, const struct timeval *tv)
  2. ---> forward_syslog_iovec(s, &iovec, 1, ucred, tv);
  3.         ---> j = strjoina(s->runtime_directory, "/syslog");
  4.         ---> r = sockaddr_un_set_path(&sa.un, j);
  5.         ---> sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL)
复制代码
分析dispatch_dev_kmsg()函数界说:
  1. static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void *userdata)
  2. ---> server_read_dev_kmsg(s);
  3.         ---> char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */
  4.         ---> l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1); // s->dev_kmsg_fd 来自于open("/dev/kmsg", mode);
  5.         ---> dev_kmsg_record(s, buffer, l);
  6.                 ---> server_dispatch_message() //将读取出来的数据转发出去.
  7.                         ---> server_dispatch_message_real(s, iovec, n, m, c, tv, priority, object_pid);
  8.                                 ---> server_forward_socket(s, iovec, n, &ts, priority);
  9.                                         ---> writev(s->forward_socket_fd, iov, iov_idx)    //写到socket里面
  10.                                 ---> server_write_to_journal(s, journal_uid, iovec, n, &ts, priority);
  11.                                         ---> journal_file_append_entry()
  12.                                                 ---> journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, &o, &p);
  13.                                                         ---> Compression c = JOURNAL_FILE_COMPRESSION(f); // 支持COMPRESSION_XZ,支持COMPRESSION_LZ4,支持COMPRESSION_ZSTD
  14.                                                 ---> journal_file_append_entry_internal()
  15.                                                 ---> journal_file_post_change(f);
  16.                                                         ---> ftruncate(f->fd, f->last_stat.st_size)
复制代码
函数stdout_stream_new()界说如下:
  1. static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata)
  2. ---> fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
  3. ---> r = stdout_stream_install(s, fd, NULL);
  4. ---> r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
  5.         ---> setsockopt(fd, level, optname, &value, sizeof(value))
  6. ---> r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
  7. ---> r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
复制代码
此中stdout_stream_process()界说为:
  1. static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata)
  2. ---> l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
  3. ---> r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
  4. ---> memmove(s->buffer, p + consumed, s->length);
复制代码
函数dispatch_notify_event()界说如下:
  1. static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata)
  2. ---> if (!s->sent_notify_ready)
  3.         ---> send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); s->sent_notify_ready = true;
  4. ---> else if (s->send_watchdog)
  5.         ---> send(s->notify_fd, p, strlen(p), MSG_DONTWAIT) ; s->send_watchdog = false;
  6. ---> else if (s->stdout_streams_notify_queue)
  7.         ---> stdout_stream_send_notify(s->stdout_streams_notify_queue);
  8. ---> if (s->send_watchdog || s->stdout_streams_notify_queue) return 0;
复制代码
注意函数sd_event_add_io()界说如下:
  1. _public_ int sd_event_add_io(
  2.                 sd_event *e,
  3.                 sd_event_source **ret,
  4.                 int fd,
  5.                 uint32_t events,
  6.                 sd_event_io_handler_t callback,
  7.                 void *userdata)
  8. ---> s = source_new(e, !ret, SOURCE_IO);
  9.         --->
  10. ---> r = source_io_register(s, s->enabled, events);
复制代码
函数sd_event_run()界说如下:
  1. _public_ int sd_event_run(sd_event *e, uint64_t timeout)
  2. ---> r = sd_event_prepare(e);
  3. ---> if (r == 0)
  4.         ---> r = sd_event_wait(e, timeout);
  5.                 ---> r = process_epoll(e, timeout, threshold, &epoll_min_priority);
  6.                         ---> epoll_wait_usec(e->epoll_fd,e->event_queue,n_event_max,timeout);
复制代码
3.提示

这篇文章内容太多了,博客编写起来有点卡了。放在下一篇文章中继续写吧。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表