dbus源码走读-2 BusContext的创建
BusContext的创建是调用bus_context_new()函数完成的,它的源代码在bus/bus.c中, line 767.
该函数的入参包括:
const DBusString *config_file//配置文件
BusContextFlags flags//由命令行参数生成的flags标志
DBusPipe *print_addr_pipe//
DBusPipe *print_pid_pipe//
const DBusString *address//地址字符串
输出参数:
DBusError *error//错误信息
返回值
BusContext *。
flags 是一个枚举类型,定义了以下位:
BUS_CONTEXT_FLAG_NONE = 0,
BUS_CONTEXT_FLAG_FORK_ALWAYS = (1 << 1),
BUS_CONTEXT_FLAG_FORK_NEVER = (1 << 2),
BUS_CONTEXT_FLAG_WRITE_PID_FILE = (1 << 3),
BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION = (1 << 4),
BUS_CONTEXT_FLAG_SYSLOG_ALWAYS = (1 << 5),
BUS_CONTEXT_FLAG_SYSLOG_NEVER = (1 << 6),
BUS_CONTEXT_FLAG_SYSLOG_ONLY = (1 << 7)
返回类型BusContext是一个很复杂的结构体,先浏览一下大概内容吧。
struct BusContext
{
int refcount;
DBusGUID uuid;
char *config_file;
char *type;
char *servicehelper;
char *address;
char *pidfile;
char *user;
char *log_prefix;
DBusLoop *loop;
DBusList *servers;
BusConnections *connections;
BusActivation *activation;
BusRegistry *registry;
BusPolicy *policy;
BusMatchmaker *matchmaker;
BusLimits limits;
DBusRLimit *initial_fd_limit;
BusContainers *containers;
unsigned int fork : 1;
unsigned int syslog : 1;
unsigned int keep_umask : 1;
unsigned int allow_anonymous : 1;
unsigned int systemd_activation : 1;
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
unsigned int quiet_log : 1;
#endif
dbus_bool_t watches_enabled;
};
bus_context_new首先定义了两个指针,BusContext *context 和 BusConfigParser *parser。要创建一个新的BusContext需要解析BusConfig,于是要创建一个BusConfigParser,这是很自然的。
接下来的一步令人费解,调用dbus_server_allocate_data_slot (&server_data_slot) 分配了一个data slot。什么是data slot?看server_data_slot的类型只是一个32位的整型值。估计这里面有一种类型的抽象或者一种机制,具体的功能是什么还不清楚。暂时不深究,继续往下读。[TODO]
下一步比较好理解,就是给BusContext分配内存。context = dbus_new0 (BusContext, 1);
然后是把context的引用计数设置为1. 并生成uuid。_dbus_generate_uuid (&context->uuid, error)
然后把配置文件路径拷贝到context的config_file中。
然后是调用context->loop = _dbus_loop_new ();创建了DBusLoop对象。这应该又是一个比较重要的对象,需要进一步研究。[TODO]
然后把watches_enabled设置为真。context->watches_enabled = TRUE; watches_enabled表示什么意思?[TODO]
下面是创建另一个重要的结构体: context->registry = bus_registry_new (context);它的工作机制是什么?[TODO]
接下来是创建了配置解析器。parser = bus_config_load (config_file, TRUE, NULL, error);可以预测要解析配置参数了。
配置参数分两类,
第一类是只需要处理一次的项: process_config_first_time_only (context, parser, address, flags, error)。
第二类是每次加载(比如kill -1)都要处理的参数:process_config_every_time (context, parser, FALSE, error)。
然后再次调用dbus_server_allocate_data_slot (&server_data_slot)。这次并没有真正分配data slot,只是对前面调用的data slot的引用数加1。为什么需要做这一步?[TODO]
line 854~891就是从context中读出address,加上换行符后写入print_addr_pipe中。
下面是几个重要的步骤:
1. 创建了Connection结构体: context->connections = bus_connections_new (context). [TODO]待后续深究。
2. 创建MatchMaker对象: context->matchmaker = bus_matchmaker_new ()
3. 创建Container对象: context->containers = bus_containers_new ()
然后做了一个小检查,检查配置的用户是否有效,否则fork或切换用户的时候会失败。
_dbus_verify_daemon_user (context->user)
紧接着就要做进入daemon的操作了。因为dbus server是作为daemon进程运行的。有两种方式切换为daemon进程。
1.如果允许fork一个新进程,则调用如下函数变成daemon进程。
_dbus_become_daemon (context->pidfile ? &u : NULL,print_pid_pipe,error,context->keep_umask)
2. 否则,只是把pid写入pidfile和print_pid_pipe管道。[TODO: 这样就变成daemon进程了?]
然后是修改描述符限制和切换为daemon user。
raise_file_descriptor_limit (context)
_dbus_change_to_daemon_user (context->user, error)
初始化审计系统: bus_audit_init (context)
初始化安全模块:
bus_selinux_full_init (context, error)
bus_apparmor_full_init (error)
以及安全模块初始化后的一些处理: process_config_postinit (context, parser, error)
最后是资源释放并返回context指针。
dbus_server_free_data_slot (&server_data_slot);
return context;
纵观整个bus_context_new()过程,不难发现,它很像设计模式中的Builder pattern中的构建器。它负责BusContext各个模块的创建和初始化。
这里采用广度优先的方式浏览了bus_context_new()的大致过程。下面将对BusContext中几个重点对象的构造进行浏览,以进一步窥探dbus server的内部原理。
下面是主要的流程图:

浙公网安备 33010602011771号