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服务:
同样,可以使用如下下令检察服务:
- # cat /etc/systemd/system/dbus.service
复制代码
使用下令,均可检察信息:
- # 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代码流程:
- src\launch\main.c
- int main(int argc, char **argv)
- ---> r = parse_argv(argc, argv);
- ---> r = inherit_fds();
- ---> n = sd_listen_fds(true);
- ---> s = SD_LISTEN_FDS_START;
- ---> r = sd_is_socket(s, PF_UNIX, SOCK_STREAM, 1);
- ---> r = fcntl(s, F_GETFL);
- ---> r = fcntl(s, F_SETFL, r | O_NONBLOCK);
- ---> main_fd_listen = s;
- ---> r = run();
- ---> r = launcher_new(&launcher, main_fd_listen, main_arg_audit, main_arg_configfile, main_arg_user_scope);
- ---> r = launcher_open_log(launcher);
- ---> .sun_path = "/run/systemd/journal/socket",
- ---> fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- ---> connect(fd,(struct sockaddr *)&address,offsetof(struct sockaddr_un, sun_path) + strlen(address.sun_path));
- ---> log_init_journal_consume(&launcher->log, fd);
- ---> r = sd_event_default(&launcher->event);
- ---> r = sd_event_add_signal(launcher->event, NULL, SIGTERM, NULL, NULL);
- ---> r = sd_event_add_signal(launcher->event, NULL, SIGINT, NULL, NULL);
- ---> r = sd_event_add_signal(launcher->event, NULL, SIGHUP, launcher_on_sighup, launcher);
- ---> r = sd_bus_new(&launcher->bus_controller);
- ---> r = launcher_run(launcher);
- ---> r = launcher_parse_config(launcher, &root, &nss_cache);
- ---> configfile = "/usr/share/dbus-1/system.conf";
- ---> config_parser_init(&parser); //XML parser
- ---> config_parser_read(&parser, rootp, configfile, nss_cache, dirwatch); //解析/usr/share/dbus-1/system.conf
- ---> r = sd_event_add_io(..., launcher_on_dirwatch,...) //重新加载文件
- ---> r = launcher_load_services(launcher, root, &nss_cache);
- ---> r = sd_notify(false, "READY=1");
- ---> r = launcher_load_policy(launcher, root, &policy);
- ---> r = socketpair(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, controller); //创建一对双向通信的client/server. 注意是双向通信
- ---> r = sd_bus_set_fd(launcher->bus_controller, controller[0], controller[0]);
- ---> bus->input_fd = input_fd; //systemd的代码,输入设置为controller[0]
- ---> bus->output_fd = output_fd;//systemd的代码,输出均设置为controller[0]
- ---> r = launcher_fork(launcher, controller[1]); //
- ---> launcher_run_child(launcher, log_get_fd(&launcher->log), fd_controller);
- ---> const char * const argv[] = {"dbus-broker", ...}
- ---> r = sd_id128_get_machine(&machine_id);
- ---> sd_id128_to_string(machine_id, str_machine_id);
- ---> r = execve(main_arg_broker, (char * const *)argv, environ);
- ---> r = sd_event_add_child(launcher->event, NULL, pid, WEXITED, launcher_on_child_exit, launcher); //建立子进程,在子进程中创建dbus-broker 进程。
- ---> r = sd_bus_add_object_vtable(launcher->bus_controller, NULL, "/org/bus1/DBus/Controller", "org.bus1.DBus.Controller", launcher_vtable, launcher);
- ---> r = sd_bus_add_filter(launcher->bus_controller, NULL, launcher_on_message, launcher); //launcher_on_message 是一个很重要的函数
- ---> r = sd_bus_start(launcher->bus_controller);
- ---> r = launcher_add_services(launcher);
- ---> r = launcher_add_listener(launcher, &policy, system_console_users, n_system_console_users);
- ---> r = launcher_connect(launcher);
- ---> r = sd_bus_attach_event(launcher->bus_controller, launcher->event, SD_EVENT_PRIORITY_NORMAL);
- ---> r = sd_bus_attach_event(launcher->bus_regular, launcher->event, SD_EVENT_PRIORITY_NORMAL);
- ---> r = launcher_subscribe(launcher);
- ---> r = sd_event_loop(launcher->event);
复制代码 以是回顾一下之前看到的控制台有2个进程,分别为:/usr/bin/dbus-broker-launch和dbus-broker。此中dbus-broker-launch是由systemd以服务启动的。而dbus-broker则是由如下代码启动起来的。
- const char * const argv[] = {"dbus-broker", ...}
- execve(main_arg_broker, (char * const *)argv, environ);
复制代码 检察文件/usr/lib/systemd/user/dbus.socket的内容:
- # cat /usr/lib/systemd/user/dbus.socket
- [Unit]
- Description=D-Bus User Message Bus Socket
- [Socket]
- ListenStream=%t/bus
- ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
复制代码 与文件/lib/systemd/system/dbus-broker.service的内容:
- root@ast2500-default:/# cat /lib/systemd/system/dbus-broker.service
- [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(),如下:
- static int inherit_fds(void)
- ---> n = sd_listen_fds(true); //来自于systemd的函数,参数为true.
- ---> e = getenv("LISTEN_PID");
- ---> r = parse_pid(e, &pid);
- ---> e = getenv("LISTEN_FDS");
- ---> r = safe_atoi(e, &n);
- ---> for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++)
- ---> r = fd_cloexec(fd, true); //在fork子进程后关闭相关描述符
- ---> unsetenv_listen(unset_environment); //子进程不需要使用这些环境变量
- ---> s = SD_LISTEN_FDS_START; // s = 3
- ---> r = sd_is_socket(s, PF_UNIX, SOCK_STREAM, 1); //判断是否为socket
- ---> main_fd_listen = s;
复制代码 再分析一下sd_event_loop()代码,其界说在文件src\libsystemd\sd-event\sd-event.c(systemd代码):
- _public_ int sd_event_loop(sd_event *e)
- {
- ...
- while (e->state != SD_EVENT_FINISHED) {
- r = sd_event_run(e, UINT64_MAX);
- if (r < 0)
- return r;
- }
- ...
- }
复制代码 以是这是dbus-broker依赖于systemd的由来。
- src\broker\main.c
- int main(int argc, char **argv)
- ---> r = parse_argv(argc, argv);
- ---> r = setup();
- ---> r = bus_selinux_init_global();
- ---> r = run();
- ---> 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);
- ---> r = broker_run(broker);
- ---> r = connection_open(&broker->controller.connection);
复制代码 此中,函数broker_new()调用关系如下:
- broker_new()
- ---> controller_init()
- ---> controller_dispatch_connection()
- --->controller_dbus_dispatch()
- --->controller_dispatch_object()
- --->controller_dispatch_controller()
- ---> controller_method_add_listener()
- ---> controller_add_listener()
- ---> listener_init_with_fd(...)
- ---> r = dispatch_file_init(&listener->socket_file,
- dispatcher,listener_dispatch,
- socket_fd,EPOLLIN,EPOLLIN);
复制代码 此中函数listener_dispatch()调用关系如下:
- static int listener_dispatch(DispatchFile *file)
- ---> peer_dispatch(DispatchFile *file)
- ---> peer_dispatch_connection()
- ---> driver_dispatch()
- ---> driver_dispatch_internal()
- ---> if (string_equal(message->metadata.fields.destination, "org.freedesktop.DBus"))
- ---> driver_dispatch_interface()
- ---> static const DriverInterface interfaces[] =
- ---> { "org.freedesktop.DBus", driver_methods },
- ---> { "org.freedesktop.DBus.Monitoring", monitoring_methods },
- ---> { "org.freedesktop.DBus.Introspectable", introspectable_methods },
- ---> { "org.freedesktop.DBus.Peer", peer_methods },
- ---> { "org.freedesktop.DBus.Properties", properties_methods },
- ---> { "org.freedesktop.DBus.Debug.Stats", debug_stats_methods },
- ---> }
-
复制代码 此中函数driver_methods()界说如下:
- static const DriverMethod driver_methods[] = {
- { "Hello", false, NULL, driver_method_hello, c_dvar_type_unit, driver_type_out_s, false },
- { "AddMatch", true, NULL, driver_method_add_match, driver_type_in_s, driver_type_out_unit, false },
- { "RemoveMatch", true, NULL, driver_method_remove_match, driver_type_in_s, driver_type_out_unit, false },
- { "RequestName", true, NULL, driver_method_request_name, driver_type_in_su, driver_type_out_u, false },
- { "ReleaseName", true, NULL, driver_method_release_name, driver_type_in_s, driver_type_out_u, false },
- { "GetConnectionCredentials", true, NULL, driver_method_get_connection_credentials, driver_type_in_s, driver_type_out_apsv, true },
- { "GetConnectionUnixUser", true, NULL, driver_method_get_connection_unix_user, driver_type_in_s, driver_type_out_u, false },
- { "GetConnectionUnixProcessID", true, NULL, driver_method_get_connection_unix_process_id, driver_type_in_s, driver_type_out_u, false },
- { "GetAdtAuditSessionData", true, NULL, driver_method_get_adt_audit_session_data, driver_type_in_s, driver_type_out_ay, false },
- { "GetConnectionSELinuxSecurityContext", true, NULL, driver_method_get_connection_selinux_security_context, driver_type_in_s, driver_type_out_ay, false },
- { "StartServiceByName", true, NULL, driver_method_start_service_by_name, driver_type_in_su, driver_type_out_u, false },
- { "ListQueuedOwners", true, NULL, driver_method_list_queued_owners, driver_type_in_s, driver_type_out_as, false },
- { "ListNames", true, NULL, driver_method_list_names, c_dvar_type_unit, driver_type_out_as, false },
- { "ListActivatableNames", true, NULL, driver_method_list_activatable_names, c_dvar_type_unit, driver_type_out_as, false },
- { "NameHasOwner", true, NULL, driver_method_name_has_owner, driver_type_in_s, driver_type_out_b, false },
- { "UpdateActivationEnvironment", true, "/org/freedesktop/DBus", driver_method_update_activation_environment, driver_type_in_apss, driver_type_out_unit, false },
- { "GetNameOwner", true, NULL, driver_method_get_name_owner, driver_type_in_s, driver_type_out_s, false },
- { "ReloadConfig", true, NULL, driver_method_reload_config, c_dvar_type_unit, driver_type_out_unit, false },
- { "GetId", true, NULL, driver_method_get_id, c_dvar_type_unit, driver_type_out_s, false },
- { },
- };
复制代码 此中,函数:driver_method_hello()界说如下:
- static int driver_method_hello(Peer *peer, const char *path, CDVar *in_v, uint32_t serial, CDVar *out_v)
- ---> unique_name = address_to_string(&(Address)ADDRESS_INIT_ID(peer->id));
复制代码 分析函数address_to_string():
- const char *address_to_string(Address *address)
- ---> case ADDRESS_TYPE_ID:
- ---> r = snprintf(address->buffer, sizeof(address->buffer), ":1.%"PRIu64, address->id);
- ---> case ADDRESS_TYPE_NAME:
- ---> return address->name;
复制代码 可以看到使用busctl后的显示:
在文件:src\launch\launcher.c中,调用到函数:
- r = sd_bus_start(launcher->bus_controller);
复制代码 此中,界说了:sd_bus *bus_controller;,在函数sd_bus_start()界说如:
- src\libsystemd\sd-bus\sd-bus.c
- _public_ int sd_bus_start(sd_bus *bus)
- ---> bus_set_state(bus, BUS_OPENING);
- ---> r = bus_start_fd(bus);
- ---> bus_send_hello(bus);
- ---> if (!bus->bus_client) return 0;
复制代码 在文件:src\launch\launcher.c中界说了launcher_connect():
- static int launcher_connect(Launcher *launcher)
- ---> r = sd_bus_open_system(&launcher->bus_regular);
- ---> sd_bus_open_system_with_description(ret, NULL);
- ---> r = sd_bus_new(&b);
- ---> r = bus_set_address_system(b);
- ---> e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
- ---> r = sd_bus_set_address(b, e ?: DEFAULT_SYSTEM_BUS_ADDRESS); //默认bus为: "unix:path=/run/dbus/system_bus_socket" //这里设置了bus->address
- ---> b->runtime_scope = RUNTIME_SCOPE_SYSTEM;
- ---> b->bus_client = true;
- ---> b->trusted = false;
- ---> b->is_local = true;
- ---> r = sd_bus_start(b);
- ---> bus_set_state(bus, BUS_OPENING);
- ---> r = bus_start_address(bus);
- ---> bus_send_hello(bus);
- ---> r = sd_bus_message_new_method_call(..,.., "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus","Hello");
- ---> sd_bus_call_async(bus, NULL, m, hello_callback, NULL, 0);
复制代码 因此,可以看到:
- * 第一个bus: launcher->bus_controller
- * 第二个bus: launcher->bus_regular
复制代码 第二个launcher->bus_regular作为系统总线,会调用hello方法.
别的:
- r = sd_bus_set_fd(launcher->bus_controller, controller[0], controller[0]);
- launcher->bus_controller->input_fd = controller[0];
- launcher->bus_controller->output_fd = controller[0];
复制代码 子进程使用controller[1]。
根据上面的描述,总结一下流程图:
要想检察原图,可以访问链接: https://gitee.com/wit_yuan/dbus-broker/blob/yuan_resources/dbus-broker.jpg
接着再分析一个比较有意思的逻辑,参考下图:
- * 1.inherit_fds()使用systemd机制获取到socket描述符(请先了解systemd的socket机制原理,会先接手socket服务,accept默认为no,因此需要sd_listen_fds()方法获取socket描述符)
- * 2.父子进程通过socketpair(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, controller);中的controller[0]和controller[1]进行连接
- * 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.sd_bus_call(launcher->bus_controller, m, 0, NULL, NULL);发送socket数据实际依靠的是controller[0],而子进程使用的是controller[1],通道打通,数据可以传递给子进程
- * 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,用来统一系统的日志记载,简朴看一下流程:
- src\journal\journald.c
- static int run(int argc, char *argv[])
- ---> log_set_facility(LOG_SYSLOG);
- ---> umask(0022);
- ---> r = server_new(&s);
- ---> .syslog_fd = -EBADF,
- ---> .stdout_fd = -EBADF,
- ---> r = server_init(s, namespace);
- ---> r = sd_event_default(&s->event);
- ---> n = sd_listen_fds(true);
- ---> native_socket = strjoina(s->runtime_directory, "/socket"); ///run/systemd/journal/socket ??
- ---> stdout_socket = strjoina(s->runtime_directory, "/stdout"); ///run/systemd/journal/stdout ??
- ---> syslog_socket = strjoina(s->runtime_directory, "/dev-log"); ///run/systemd/journal/dev-log ??
- ---> varlink_socket = strjoina(s->runtime_directory, "/io.systemd.journal"); ///run/systemd/journal/io.systemd.journal ??
- ---> r = server_open_stdout_socket(s, stdout_socket);
- ---> r = sockaddr_un_set_path(&sa.un, stdout_socket);
- ---> s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- ---> r = bind(s->stdout_fd, &sa.sa, sa_len);
- ---> listen(s->stdout_fd, SOMAXCONN_DELUXE)
- ---> r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
- ---> r = server_open_syslog_socket(s, syslog_socket);
- ---> r = sockaddr_un_set_path(&sa.un, syslog_socket);
- ---> s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- ---> r = bind(s->syslog_fd, &sa.sa, sa_len);
- ---> r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, true);
- ---> r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, true);
- ---> r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, server_process_datagram, s);
- ---> r = sd_event_source_set_priority(s->syslog_event_source, SD_EVENT_PRIORITY_NORMAL+5);
- ---> r = server_open_native_socket(s, native_socket);
- ---> r = sockaddr_un_set_path(&sa.un, native_socket);
- ---> s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- ---> r = bind(s->native_fd, &sa.sa, sa_len);
- ---> r = setsockopt_int(s->native_fd, SOL_SOCKET, SO_PASSCRED, true);
- ---> r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, server_process_datagram, s);
- ---> r = server_open_dev_kmsg(s);
- ---> s->dev_kmsg_fd = open("/dev/kmsg", mode); //打开内核缓冲
- ---> r = sd_event_add_io(s->event, &s->dev_kmsg_event_source, s->dev_kmsg_fd, EPOLLIN, dispatch_dev_kmsg, s);
- ---> r = sd_event_source_set_priority(s->dev_kmsg_event_source, SD_EVENT_PRIORITY_IMPORTANT+10);
- ---> r = server_open_varlink(s, varlink_socket, varlink_fd);
- ---> r = sd_varlink_server_new(&s->varlink_server, SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_INHERIT_USERDATA);
- ---> sd_varlink_server_set_userdata(s->varlink_server, s);
- ---> r = sd_varlink_server_add_interface(s->varlink_server, &vl_interface_io_systemd_Journal);
- ---> r = server_map_seqnum_file(s, "seqnum", sizeof(SeqnumData), (void**) &s->seqnum);
- ---> r = server_open_kernel_seqnum(s);
- ---> r = server_open_hostname(s);
- ---> r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
- ---> r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
- ---> r = server_setup_signals(s);
- ---> r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr1, s);
- ---> r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr2, s);
- ---> r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
- ---> r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
- ---> r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
- ---> r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
- ---> r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, (SIGRTMIN+1)|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigrtmin1, s);
- ---> r = sd_event_add_signal(s->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, &s->sigrtmin18_info);
- ---> server_connect_notify(s);
- ---> r = sockaddr_un_set_path(&sa.un, e);
- ---> s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- ---> r = connect(s->notify_fd, &sa.sa, sa_len);
- ---> r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
- ---> r = server_system_journal_open(s, /* flush_requested= */ false, /* relinquish_requested= */ false);
- ---> while(1)
- ---> ---> r = sd_event_get_state(s->event);
- ---> ---> r = sd_event_now(s->event, CLOCK_REALTIME, &n);
- ---> ---> r = sd_event_run(s->event, t);
- DEFINE_MAIN_FUNCTION(run);
复制代码 看一下函数实现:
- src\shared\main-func.h
- #define DEFINE_MAIN_FUNCTION(impl)
- _DEFINE_MAIN_FUNCTION(,impl(argc, argv), exit_failure_if_negative, exit_failure_if_negative)
- #define _DEFINE_MAIN_FUNCTION(intro, impl, result_to_exit_status, result_to_return_value) \
- int main(int argc, char *argv[]) { \
- int r; \
- assert_se(argc > 0 && !isempty(argv[0])); \
- save_argc_argv(argc, argv); \
- intro; \
- r = impl; \
- if (r < 0) \
- (void) sd_notifyf(0, "ERRNO=%i", -r); \
- (void) sd_notifyf(0, "EXIT_STATUS=%i", \
- result_to_exit_status(r)); \
- ask_password_agent_close(); \
- polkit_agent_close(); \
- pager_close(); \
- mac_selinux_finish(); \
- static_destruct(); \
- return result_to_return_value(r); \
- }
复制代码 分析函数:server_process_datagram()调用流程:
- int server_process_datagram(
- sd_event_source *es,
- int fd,
- uint32_t revents,
- void *userdata) {
- ---> if (fd == s->syslog_fd)
- ---> server_process_syslog_message(s, s->buffer, n, ucred, tv, label, label_len);
- ---> if (s->forward_to_syslog)
- ---> forward_syslog_raw(s, priority, buf, raw_len, ucred, tv);
- ---> if (s->forward_to_kmsg)
- ---> server_forward_kmsg(s, priority, identifier, msg, ucred);
- ---> if (s->forward_to_console)
- ---> server_forward_console(s, priority, identifier, msg, ucred);
- ---> if (s->forward_to_wall)
- ---> server_forward_wall(s, priority, identifier, msg, ucred);
复制代码 分析server_forward_wall():
- void server_forward_wall(
- Server *s,
- int priority,
- const char *identifier,
- const char *message,
- const struct ucred *ucred)
- ---> r = wall(l, "systemd-journald", NULL, NULL, NULL);
- ---> r = wall_utmp(text, match_tty, userdata);
- ---> utmpx = utxent_start();
- ---> setutxent();
- ---> while ((u = getutxent())) {
- ---> RET_GATHER(r, write_to_terminal(tty_path, message));
复制代码 此中write_to_terminal()界说:
- static int write_to_terminal(const char *tty, const char *message)
- ---> fd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
- ---> loop_write_full(fd, message, SIZE_MAX, TIMEOUT_USEC);
- ---> k = write(fd, p, nbytes);
复制代码 分析server_forward_console():
- void server_forward_console(
- Server *s,
- int priority,
- const char *identifier,
- const char *message,
- const struct ucred *ucred)
- ---> const char *tty,
- ---> tty = s->tty_path ?: "/dev/console";
- ---> fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
- ---> writev(fd, iovec, n)
复制代码 分析server_forward_kmsg()界说如下:
- void server_forward_kmsg(
- Server *s,
- int priority,
- const char *identifier,
- const char *message,
- const struct ucred *ucred)
- ---> writev(s->dev_kmsg_fd, iovec, n) //之前是打开的文件 open("/dev/kmsg", mode);
复制代码 分析函数forward_syslog_raw()界说如下:
- static void forward_syslog_raw(Server *s, int priority, const char *buffer, size_t buffer_len, const struct ucred *ucred, const struct timeval *tv)
- ---> forward_syslog_iovec(s, &iovec, 1, ucred, tv);
- ---> j = strjoina(s->runtime_directory, "/syslog");
- ---> r = sockaddr_un_set_path(&sa.un, j);
- ---> sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL)
复制代码 分析dispatch_dev_kmsg()函数界说:
- static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void *userdata)
- ---> server_read_dev_kmsg(s);
- ---> char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */
- ---> l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1); // s->dev_kmsg_fd 来自于open("/dev/kmsg", mode);
- ---> dev_kmsg_record(s, buffer, l);
- ---> server_dispatch_message() //将读取出来的数据转发出去.
- ---> server_dispatch_message_real(s, iovec, n, m, c, tv, priority, object_pid);
- ---> server_forward_socket(s, iovec, n, &ts, priority);
- ---> writev(s->forward_socket_fd, iov, iov_idx) //写到socket里面
- ---> server_write_to_journal(s, journal_uid, iovec, n, &ts, priority);
- ---> journal_file_append_entry()
- ---> journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, &o, &p);
- ---> Compression c = JOURNAL_FILE_COMPRESSION(f); // 支持COMPRESSION_XZ,支持COMPRESSION_LZ4,支持COMPRESSION_ZSTD
- ---> journal_file_append_entry_internal()
- ---> journal_file_post_change(f);
- ---> ftruncate(f->fd, f->last_stat.st_size)
复制代码 函数stdout_stream_new()界说如下:
- static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata)
- ---> fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
- ---> r = stdout_stream_install(s, fd, NULL);
- ---> r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
- ---> setsockopt(fd, level, optname, &value, sizeof(value))
- ---> r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
- ---> r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
复制代码 此中stdout_stream_process()界说为:
- static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata)
- ---> l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- ---> r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
- ---> memmove(s->buffer, p + consumed, s->length);
复制代码 函数dispatch_notify_event()界说如下:
- static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata)
- ---> if (!s->sent_notify_ready)
- ---> send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); s->sent_notify_ready = true;
- ---> else if (s->send_watchdog)
- ---> send(s->notify_fd, p, strlen(p), MSG_DONTWAIT) ; s->send_watchdog = false;
- ---> else if (s->stdout_streams_notify_queue)
- ---> stdout_stream_send_notify(s->stdout_streams_notify_queue);
- ---> if (s->send_watchdog || s->stdout_streams_notify_queue) return 0;
复制代码 注意函数sd_event_add_io()界说如下:
- _public_ int sd_event_add_io(
- sd_event *e,
- sd_event_source **ret,
- int fd,
- uint32_t events,
- sd_event_io_handler_t callback,
- void *userdata)
- ---> s = source_new(e, !ret, SOURCE_IO);
- --->
- ---> r = source_io_register(s, s->enabled, events);
复制代码 函数sd_event_run()界说如下:
- _public_ int sd_event_run(sd_event *e, uint64_t timeout)
- ---> r = sd_event_prepare(e);
- ---> if (r == 0)
- ---> r = sd_event_wait(e, timeout);
- ---> r = process_epoll(e, timeout, threshold, &epoll_min_priority);
- ---> epoll_wait_usec(e->epoll_fd,e->event_queue,n_event_max,timeout);
复制代码 3.提示
这篇文章内容太多了,博客编写起来有点卡了。放在下一篇文章中继续写吧。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |