You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

VxWorks 6.9下开机脚本启动程序的printf调试信息重定向问题

解决VxWorks 6.9中开机脚本启动程序的printf无法同步到所有Telnet会话的问题

我来帮你拆解这个问题并给出可行的解决方案——你遇到的核心问题其实和SHELL_MAX_SESSIONS关系不大,而是VxWorks中shell会话的I/O隔离机制导致的。

为什么会出现这个现象?

VxWorks里每个shell会话(不管是串口初始化的,还是后来的Telnet连接)都是独立的实例,拥有自己的标准输入/输出/错误文件描述符。当你通过开机脚本启动C程序时,程序会继承启动它的那个初始串口shell的stdio上下文,所以所有printf输出只会发送到那个串口会话的fd上;而手动在Telnet会话启动程序时,程序继承的是当前Telnet会话的stdio,自然能在当前会话看到输出。SHELL_MAX_SESSIONS只是控制允许同时存在的会话数量,完全不负责同步不同会话的输出,所以调整它的数值根本解决不了问题。

可行的解决方案

要让程序的输出同步到所有已打开的shell会话,有两种比较直接的思路:

1. 自定义多会话输出函数替代printf

这是最灵活的方案,不需要修改内核配置,只需要在你的C程序里实现一个遍历所有活跃shell会话并发送输出的函数,替换掉原来的printf

首先,你需要确保内核配置了INCLUDE_SHELL_INFO(默认可能没开,需要在Wind River Workbench的内核配置里勾选),这个选项允许我们通过shellInfoGet()函数获取所有活跃shell的信息。

下面是一个示例实现:

#include <shellLib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>

// 定义最大支持的会话数,根据你的实际场景调整
#define MAX_ACTIVE_SESSIONS 32

void multi_printf(const char *format, ...) {
    va_list args;
    char output_buf[2048];  // 缓冲区大小按需调整
    SHELL_INFO session_list[MAX_ACTIVE_SESSIONS];
    int session_count;

    // 第一步:把格式化内容写入缓冲区
    va_start(args, format);
    vsnprintf(output_buf, sizeof(output_buf), format, args);
    va_end(args);

    // 第二步:获取所有活跃的shell会话信息
    session_count = shellInfoGet(session_list, MAX_ACTIVE_SESSIONS);
    for (int i = 0; i < session_count; i++) {
        // 跳过无效会话(比如未初始化的shell)
        if (session_list[i].shellId == 0 || session_list[i].fdStdout == -1) {
            continue;
        }
        // 将缓冲区内容写入当前会话的stdout
        write(session_list[i].fdStdout, output_buf, strlen(output_buf));
    }

    // 兼容原有逻辑:同时输出到程序继承的原始stdout
    printf("%s", output_buf);
}

使用方法很简单:把你程序里所有printf("xxx")替换成multi_printf("xxx")即可。这样不管程序是从哪个会话启动的,输出都会同步到所有当前活跃的串口/Telnet会话。

2. 利用系统日志机制转发输出

如果你不想修改程序代码,可以考虑把程序的printf输出重定向到VxWorks的系统日志,然后配置日志输出到所有shell会话。

  • 首先,在程序启动时,将stdout重定向到日志设备:
    // 在程序初始化时执行
    dup2(logFdGet(), STDOUT_FILENO);
    dup2(logFdGet(), STDERR_FILENO);
    
  • 然后,编写一个辅助函数(或者在开机脚本中调用C函数),遍历所有活跃shell会话,把它们的stdout文件描述符添加到日志输出集合中:
    #include <shellLib.h>
    #include <logLib.h>
    
    void log_to_all_shells(void) {
        SHELL_INFO session_list[MAX_ACTIVE_SESSIONS];
        int session_count = shellInfoGet(session_list, MAX_ACTIVE_SESSIONS);
        for (int i = 0; i < session_count; i++) {
            if (session_list[i].shellId != 0 && session_list[i].fdStdout != -1) {
                logFdAdd(session_list[i].fdStdout);
            }
        }
    }
    
  • 最后,在开机脚本中启动程序前调用这个函数,或者把它作为系统初始化任务的一部分。

不过这种方法有个小缺点:logMsg(也就是系统日志)的输出格式会带有时间戳等前缀,如果你需要和原来的printf完全一致的输出格式,第一种方案更合适。

注意事项

  • 使用shellInfoGet()时,要注意会话的动态变化:如果有新的Telnet会话在程序启动后连接,你的multi_printf每次调用都会重新获取最新的会话列表,所以新会话也能看到后续的输出。
  • 缓冲区大小要根据你实际的输出内容调整,避免截断长输出。

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

火山引擎 最新活动