DBusMessage 消息生命周期管理
1. 概述
消息生命周期管理包括消息的创建、修改、锁定、发送、接收和释放。D-Bus 使用引用计数管理内存,使用锁定机制确保消息在传输过程中的一致性。
1.1 生命周期阶段
创建 → 填充 → 锁定 → 发送 → 接收 → 使用 → 释放
↓ ↓ ↓ ↓ ↓ ↓ ↓
new set lock send recv get unref
2. 消息锁定
2.1 锁定机制
消息锁定是确保消息在传输过程中不被修改的机制。
void dbus_message_lock(DBusMessage *message);
2.2 锁定实现
void dbus_message_lock(DBusMessage *message)
{
if (!message->locked) {
// 更新消息头长度字段
_dbus_header_update_lengths(&message->header,
_dbus_string_get_length(&message->body));
// 验证:如果有消息体,必须有签名
_dbus_assert(_dbus_string_get_length(&message->body) == 0 ||
dbus_message_get_signature(message) != NULL);
message->locked = TRUE;
}
}
2.3 锁定后的限制
锁定后,以下操作会失败或触发断言:
- 修改头字段(
dbus_message_set_path()等) - 添加参数(
dbus_message_append_args()等) - 修改参数(通过迭代器)
- 删除字段
2.4 锁定时机
消息在以下情况下会被自动锁定:
-
显式锁定:
dbus_message_lock(msg); -
发送时自动锁定:
dbus_connection_send(conn, msg, NULL); // 自动锁定 -
序列化时自动锁定:
dbus_message_marshal(msg, &data, &len); // 自动锁定
2.5 锁定检查
所有修改操作都会检查锁定状态:
static dbus_bool_t check_locked(DBusMessage *message)
{
if (message->locked) {
_dbus_warn("Message is locked, cannot modify");
return FALSE;
}
return TRUE;
}
2.6 解锁
注意:D-Bus 不提供显式解锁函数。一旦锁定,消息就不能再修改。
设计原因:
- 确保消息在传输过程中的一致性
- 防止竞态条件
- 支持消息缓存和重用
3. 引用计数
3.1 引用计数机制
DBusMessage 使用原子引用计数管理内存:
struct DBusMessage
{
DBusAtomic refcount; // 原子整数
// ...
};
3.2 引用计数操作
// 增加引用计数
DBusMessage* dbus_message_ref(DBusMessage *message);
// 减少引用计数
void dbus_message_unref(DBusMessage *message);
3.3 实现细节
3.3.1 增加引用
DBusMessage* dbus_message_ref(DBusMessage *message)
{
if (message == NULL)
return NULL;
_dbus_atomic_inc(&message->refcount);
return message;
}
3.3.2 减少引用
void dbus_message_unref(DBusMessage *message)
{
if (message == NULL)
return;
if (_dbus_atomic_dec(&message->refcount) == 1) {
// 引用计数为 0,释放消息
_dbus_message_finalize(message);
}
}
3.4 引用计数规则
| 操作 | 引用计数变化 | 说明 |
|---|---|---|
dbus_message_new_*() | 0 → 1 | 创建消息 |
dbus_message_ref() | n → n+1 | 增加引用 |
dbus_message_unref() | n → n-1 | 减少引用 |
dbus_message_unref() (refcount=1) | 1 → 0 | 释放消息 |
3.5 使用示例
3.5.1 基本使用
// 创建消息(refcount = 1)
DBusMessage *msg = dbus_message_new_method_call(...);
// 使用消息...
// 释放消息(refcount = 0)
dbus_message_unref(msg);
3.5.2 多引用共享
// 创建消息(refcount = 1)
DBusMessage *msg = dbus_message_new_method_call(...);
// 传递给回调函数(增加引用)
dbus_message_ref(msg);
callback_function(msg); // 回调函数内部会 unref
// 继续使用消息(refcount = 1)
process_message(msg);
// 释放消息(refcount = 0)
dbus_message_unref(msg);
3.5.3 错误处理
DBusMessage *msg = dbus_message_new_method_call(...);
if (msg == NULL) {
// 处理内存不足
return;
}
// 使用消息
if (some_error_condition) {
dbus_message_unref(msg); // 确保释放
return;
}
// 正常流程
dbus_message_unref(msg);
3.6 自动清理宏
static inline void dbus_clear_message(DBusMessage **pointer_to_message);
功能:自动清理消息指针,避免内存泄漏
实现:
static inline void dbus_clear_message(DBusMessage **pointer_to_message)
{
_dbus_clear_pointer_impl(DBusMessage, pointer_to_message,
dbus_message_unref);
}
使用示例:
DBusMessage *msg = dbus_message_new_method_call(...);
// 使用消息...
// 自动清理(unref 并设置为 NULL)
dbus_clear_message(&msg);
// msg 现在是 NULL
优势:
- 自动释放,避免忘记 unref
- 设置为 NULL,避免悬空指针
- 支持多次调用(幂等)
4. 消息复制
4.1 复制函数
DBusMessage* dbus_message_copy(const DBusMessage *message);
4.2 复制内容
复制函数会复制:
- 消息头(包括所有字段)
- 消息体(包括所有参数)
- Unix 文件描述符(需要
dup()) - 数据槽(如果支持)
4.3 实现细节
DBusMessage* dbus_message_copy(const DBusMessage *message)
{
DBusMessage *copy;
// 创建新消息
copy = dbus_message_new_empty_header();
if (copy == NULL)
return NULL;
// 复制消息头
if (!_dbus_header_copy(&message->header, ©->header)) {
dbus_message_unref(copy);
return NULL;
}
// 复制消息体
if (!_dbus_string_copy(&message->body, 0, ©->body, 0)) {
dbus_message_unref(copy);
return NULL;
}
// 复制 Unix 文件描述符
#ifdef HAVE_UNIX_FD_PASSING
if (message->n_unix_fds > 0) {
// 分配 fd 数组
// dup() 每个 fd
}
#endif
// 复制其他字段...
return copy;
}
4.4 使用场景
-
发送到多个目标:
DBusMessage *msg = create_message(); // 发送到目标1 dbus_connection_send(conn1, msg, NULL); // 复制并发送到目标2 DBusMessage *copy = dbus_message_copy(msg); dbus_connection_send(conn2, copy, NULL); dbus_message_unref(copy); dbus_message_unref(msg); -
延迟处理:
// 接收消息 DBusMessage *msg = dbus_connection_pop_message(conn); // 复制消息用于异步处理 DBusMessage *copy = dbus_message_copy(msg); queue_for_async_processing(copy); // 立即返回,不阻塞 dbus_message_unref(msg); -
修改已锁定消息:
// 消息已锁定,无法修改 DBusMessage *copy = dbus_message_copy(msg); // 修改副本 dbus_message_set_path(copy, new_path); // 发送副本 dbus_connection_send(conn, copy, NULL); dbus_message_unref(copy);
4.5 复制注意事项
- 序列号重置:复制的消息序列号会被重置为 0
- 锁定状态:复制的消息未锁定,可以修改
- 引用计数:复制的消息引用计数为 1
- Unix fd:会
dup()文件描述符,需要单独关闭
5. 迭代器失效检测
5.1 changed_stamp 机制
消息使用 changed_stamp 检测迭代器是否失效:
struct DBusMessage
{
dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; // 21 位
// ...
};
struct DBusMessageRealIter
{
DBusMessage *message;
dbus_uint32_t changed_stamp; // 保存创建时的 changed_stamp
// ...
};
5.2 工作原理
- 消息修改时:
changed_stamp递增 - 迭代器创建时:保存当前的
changed_stamp - 迭代器使用时:检查
changed_stamp是否匹配 - 不匹配时:迭代器失效,操作失败
5.3 失效检测实现
static dbus_bool_t _dbus_message_iter_check(DBusMessageRealIter *iter)
{
if (iter->message->changed_stamp != iter->changed_stamp) {
_dbus_warn("Iterator invalid: message has been modified");
return FALSE;
}
return TRUE;
}
5.4 失效场景
迭代器在以下情况下会失效:
-
消息被修改:
DBusMessageIter iter; dbus_message_iter_init(msg, &iter); // 修改消息 dbus_message_append_args(msg, ...); // changed_stamp 递增 // 迭代器失效 dbus_message_iter_get_basic(&iter, ...); // 失败 -
消息被锁定:
DBusMessageIter iter; dbus_message_iter_init_append(msg, &iter); dbus_message_lock(msg); // changed_stamp 可能变化 // 迭代器失效 dbus_message_iter_append_basic(&iter, ...); // 失败 -
消息被复制:
DBusMessageIter iter; dbus_message_iter_init(msg, &iter); DBusMessage *copy = dbus_message_copy(msg); // 原消息的 changed_stamp 可能变化 // 迭代器可能失效
5.5 防止失效
-
完成迭代后再修改:
DBusMessageIter iter; dbus_message_iter_init(msg, &iter); // 完成所有读取操作 while (dbus_message_iter_next(&iter)) { // 读取参数 } // 现在可以安全地修改消息 dbus_message_append_args(msg, ...); -
使用副本:
DBusMessage *copy = dbus_message_copy(msg); // 在副本上迭代 DBusMessageIter iter; dbus_message_iter_init(copy, &iter); // 可以安全地修改原消息 dbus_message_append_args(msg, ...); dbus_message_unref(copy);
6. 消息验证
6.1 完整性验证
消息在以下情况下会被验证:
- 反序列化时
- 接收时
- 发送前(某些检查)
6.2 验证内容
-
消息头格式:
- 字节序有效性
- 消息类型有效性
- 长度字段合理性
-
字段完整性:
- 必需字段存在
- 字段类型正确
- 字段值有效
-
消息体完整性:
- 类型签名有效
- 参数类型匹配
- 对齐正确
6.3 验证函数
dbus_bool_t _dbus_message_loader_queue_messages(DBusMessageLoader *loader);
功能:验证并解析消息
返回值:
TRUE:消息有效FALSE:消息无效或损坏
7. 消息缓存
7.1 缓存机制
D-Bus 实现了消息缓存,用于减少消息分配开销:
#define MAX_MESSAGE_SIZE_TO_CACHE 10 * _DBUS_ONE_KILOBYTE
#define MAX_MESSAGE_CACHE_SIZE 5
static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE];
static int message_cache_count = 0;
7.2 缓存策略
- 缓存条件:消息大小小于 10KB
- 缓存数量:最多缓存 5 个消息
- 缓存时机:消息释放时(如果满足条件)
7.3 性能影响
根据 D-Bus 源码注释,消息缓存可以带来约 8% 的性能提升:
- 减少
malloc()调用 - 减少
free()调用 - 减少字符串初始化开销
7.4 缓存实现
static DBusMessage* dbus_message_new_empty_header(void)
{
DBusMessage *message;
// 尝试从缓存获取
_DBUS_LOCK(message_cache);
if (message_cache_count > 0) {
message = message_cache[--message_cache_count];
message_cache[message_cache_count] = NULL;
_DBUS_UNLOCK(message_cache);
// 重新初始化消息
_dbus_header_reinit(&message->header);
_dbus_string_set_length(&message->body, 0);
// ...
return message;
}
_DBUS_UNLOCK(message_cache);
// 缓存为空,分配新消息
message = dbus_new0(DBusMessage, 1);
// ... 初始化
return message;
}
8. 内存管理
8.1 消息释放
消息释放时会清理所有资源:
static void _dbus_message_finalize(DBusMessage *message)
{
// 1. 减少计数器
if (message->counters) {
// 减少所有计数器的值
}
// 2. 释放 Unix 文件描述符
#ifdef HAVE_UNIX_FD_PASSING
if (message->unix_fds) {
for (unsigned i = 0; i < message->n_unix_fds; i++) {
close(message->unix_fds[i]);
}
dbus_free(message->unix_fds);
}
#endif
// 3. 释放数据槽
_dbus_data_slot_list_free(&message->slot_list);
// 4. 释放消息头和消息体
_dbus_header_free(&message->header);
_dbus_string_free(&message->body);
// 5. 尝试缓存消息(如果满足条件)
if (message_size < MAX_MESSAGE_SIZE_TO_CACHE &&
message_cache_count < MAX_MESSAGE_CACHE_SIZE) {
// 添加到缓存
} else {
// 释放消息
dbus_free(message);
}
}
8.2 资源清理顺序
- 减少计数器(通知资源管理器)
- 关闭 Unix 文件描述符
- 释放数据槽(调用释放函数)
- 释放消息头和消息体
- 释放消息结构本身
8.3 内存泄漏预防
常见错误:
// 错误:忘记 unref
DBusMessage *msg = dbus_message_new_method_call(...);
// 使用消息...
// 忘记 dbus_message_unref(msg);
正确做法:
// 方法1:手动管理
DBusMessage *msg = dbus_message_new_method_call(...);
// 使用消息...
dbus_message_unref(msg);
// 方法2:使用自动清理宏
DBusMessage *msg = dbus_message_new_method_call(...);
// 使用消息...
dbus_clear_message(&msg); // 自动 unref 并设置为 NULL
9. 线程安全
9.1 引用计数线程安全
引用计数使用原子操作,是线程安全的:
// 线程安全
DBusMessage *msg = dbus_message_new_method_call(...);
dbus_message_ref(msg); // 线程安全
dbus_message_unref(msg); // 线程安全
9.2 消息修改非线程安全
消息的修改操作不是线程安全的:
// 非线程安全
dbus_message_set_path(msg, path); // 需要外部同步
dbus_message_append_args(msg, ...); // 需要外部同步
9.3 最佳实践
- 多线程访问:使用互斥锁保护消息修改
- 只读访问:多个线程可以安全地读取消息
- 引用计数:可以安全地在多个线程间传递消息引用
1283

被折叠的 条评论
为什么被折叠?



