You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

sd-bus接收dbus signal消息与发送数据不匹配返回旧消息问题咨询

问题根因及修复方案

核心问题点

  • 未循环调用sd_bus_process:该接口单次调用仅处理1条待处理DBus消息,如果多个信号同时到达队列,剩余消息会堆积到下一轮处理,自然会读取到旧消息。
  • 多余的30ms睡眠:sd_bus_wait本身已经是阻塞等待新消息的接口,额外加30ms睡眠会强制降低消息处理频率,高频率发送信号时必然出现消息堆积。
  • 未校验数组读取返回值:如果sd_bus_message_read_array调用失败,pReceivedArray会指向之前读取的旧消息内存地址,直接打印和拷贝自然得到旧内容。
  • 回调返回值不符合规范:sd-bus要求回调处理成功返回0,失败返回负数,你当前返回1属于非法返回值,会导致sd-bus不会自动重置消息读取上下文,甚至出现资源泄漏。
  • 无需手动unref pMessage:消息对象的生命周期由sd-bus库管理,回调返回后库会自动回收,手动unref会触发重复释放导致段错误,你的判断是正确的。

修正后代码

回调函数修正
int dbusCallback(sd_bus_message * pMessage, void * userdata, sd_bus_error * ret_error)
{
    int                   sdbusErr = 0;
    uint8_t *             pReceivedArray;
    size_t                rxDecodedFrameLength;
    eNetworkStateEvents_t returnState;

    /* 读取消息前先校验返回值 */
    sdbusErr = sd_bus_message_read_array(pMessage, 'y',  (const void**) &pReceivedArray, &rxDecodedFrameLength);
    if (sdbusErr < 0) {
        printf("D-Bus read array failed: %s\n", strerror(-sdbusErr));
        return 0;
    }
    printf("Rx buffer %x %x", pReceivedArray[0], pReceivedArray[1]);

    /* 增加长度校验防止越界拷贝 */
    if (rxDecodedFrameLength > sizeof(packetDecodedRxBuffer)) {
        printf("D-Bus message too long: %zu\n", rxDecodedFrameLength);
        return 0;
    }
    memcpy(packetDecodedRxBuffer, pReceivedArray, rxDecodedFrameLength);
    /* 同步更新全局长度变量,避免读取旧长度 */
    globalRxFrameLength = rxDecodedFrameLength;

    /* 按规范返回0表示处理完成 */
    return 0;
}
DBus线程循环修正
/* 订阅信号时增加返回值校验 */
    sdbusErr = sd_bus_match_signal(bus,
                        NULL,
                        SERVICE_NAME,
                        OBJECT_PATH,
                        INTERFACE_NAME,
                        MESSAGE_FROM_SIGNAL,
                        dbusCallback,
                        NULL);
    if (sdbusErr < 0) {
        printf("D-Bus match signal failed: %s\n", strerror(-sdbusErr));
        // 补充错误处理逻辑
    }

    for (;;)
    {
        SysMonitorSignalThreadGood(SYSMONITOR_DBUS_THREAD_WATCHDOG_FLAG);

        /* 循环处理所有待处理消息,直到没有未处理消息为止 */
        do {
            sdbusErr = sd_bus_process(bus, NULL);
            if (0 > sdbusErr) {
                printf("D-Bus: Failed to process bus: %s\n", strerror(-sdbusErr));
                break;
            }
        } while (sdbusErr > 0);

        /* 所有消息处理完成后再等待新消息,不需要超时可填UINT64_MAX */
        sdbusErr = sd_bus_wait(bus, UINT64_MAX);

        /* EINTR是被系统信号打断,属于正常情况不需要报错 */
        if (0 > sdbusErr && sdbusErr != -EINTR) {
            printf("D-Bus: Failed to wait on bus: %s\n", strerror(-sdbusErr));
        }

        /* 删掉多余的30ms睡眠 */
        // tx_thread_sleep(MS_TO_TICKS(30u));
    }

    sd_bus_unref(bus);
}

额外注意事项

  • 全局变量packetDecodedRxBuffer和对应的长度变量建议加线程锁保护,避免其他线程读取时出现半写的脏数据。
  • 你日志中出现的EINTR错误是正常系统行为,不需要特殊处理,直接进入下一轮循环即可。

内容的提问来源于stack exchange,提问作者Indigo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:30:05