Linux守护进程使用VM167 USB GPIO用户空间驱动无法识别设备问题
问题概述
我正在编写Linux守护进程,用于监控Velleman VM167型号USB GPIO设备的状态,状态变更时执行对应操作。我已完成该设备的用户空间驱动部署、/etc/udev规则配置、ldconfig路径设置,编写的简化测试程序编译后运行正常,可成功识别设备并获取驱动版本信息,迁移到标准守护进程模板后,仅能正常获取驱动版本号,无法识别设备。
正常运行的测试代码
#include <iterator> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <stdlib.h> #include <string> #include <sys/stat.h> #include <syslog.h> #include <unistd.h> #include <vector> #include "VM167.h" int test_openDevices(); void test_readWriteDigital(int card); void test_readAnalog(int card); void test_PWM(int card); int main(void) { syslog(LOG_INFO, "Loop"); int devices; devices = OpenDevices(); if (devices == 0) { syslog(LOG_ERR, "Driver error condition, exiting"); //fflush(stdout); //return -1; } else if (devices == -1) { syslog(LOG_ERR, "No devices found on system, exiting\n"); //fflush(stdout); //return -1; } int ver = VersionDLL(); syslog(LOG_INFO, "DLL Version: %d.%d.%d.%d\n", (ver>>24), (ver>>16)&0xFF, (ver>>8)&0xFF, ver&0xFF); }
测试程序syslog输出
Nov 4 01:12:12 testserver console: Loop Nov 4 01:12:12 testserver console: DLL Version: 0.1.0.19
故障守护进程代码
#include <dirent.h> #include <iterator> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <stdlib.h> #include <string> #include <sys/stat.h> #include <syslog.h> #include <unistd.h> #include <vector> #include "VM167.h" int test_openDevices(); void test_readWriteDigital(int card); void test_readAnalog(int card); void test_PWM(int card); void do_heartbeat() { // TODO: implement processing code to be performed on each heartbeat syslog(LOG_INFO, "Loop"); int devices; devices = OpenDevices(); if (devices == 0) { syslog(LOG_ERR, "Driver error condition, exiting"); //fflush(stdout); //return -1; } else if (devices == -1) { syslog(LOG_ERR, "No devices found on system, exiting\n"); //fflush(stdout); //return -1; } int ver = VersionDLL(); syslog(LOG_INFO, "DLL Version: %d.%d.%d.%d\n", (ver>>24), (ver>>16)&0xFF, (ver>>8)&0xFF, ver&0xFF); } // For security purposes, we don't allow any arguments to be passed into the daemon int main(void) { // Define variables pid_t pid, sid; // Fork the current process pid = fork(); // The parent process continues with a process ID greater than 0 if(pid > 0) { exit(EXIT_SUCCESS); } // A process ID lower than 0 indicates a failure in either process else if(pid < 0) { exit(EXIT_FAILURE); } // The parent process has now terminated, and the forked child process will continue // (the pid of the child process was 0) // Since the child process is a daemon, the umask needs to be set so files and logs can be written umask(0); // Open system logs for the child process openlog("Daemon-GPIO", LOG_NOWAIT | LOG_PID, LOG_USER); syslog(LOG_NOTICE, "Successfully started Daemon-GPIO"); // Generate a session ID for the child process sid = setsid(); // Ensure a valid SID for the child process if(sid < 0) { // Log failure and exit syslog(LOG_ERR, "Could not generate session ID for child process"); // If a new session ID could not be generated, we must terminate the child process // or it will be orphaned exit(EXIT_FAILURE); } // Change the current working directory to a directory guaranteed to exist if((chdir("/")) < 0) { // Log failure and exit syslog(LOG_ERR, "Could not change working directory to /"); // If our guaranteed directory does not exist, terminate the child process to ensure // the daemon has not been hijacked exit(EXIT_FAILURE); } // A daemon cannot use the terminal, so close standard file descriptors for security reasons close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); // Daemon-specific intialization should go here const int SLEEP_INTERVAL = 5; // Enter daemon loop while(1) { syslog(LOG_INFO, "Starting helper loop"); // Execute daemon heartbeat, where your recurring activity occurs do_heartbeat(); // Sleep for a period of time sleep(SLEEP_INTERVAL); } // Close system logs for the child process syslog(LOG_NOTICE, "Stopping Daemon-GPIO"); closelog(); // Terminate the child process when the daemon completes exit(EXIT_SUCCESS); }
守护进程syslog输出
Nov 4 00:18:10 testserver Daemon-GPIO[29638]: Loop Nov 4 00:18:10 testserver Daemon-GPIO[29638]: No devices found on system, exiting Nov 4 00:18:10 testserver Daemon-GPIO[29638]: DLL Version: 0.1.0.19
修复方案
按照以下优先级排查修复:
- 调整设备打开逻辑:不要在心跳循环中反复调用
OpenDevices(),将设备打开操作移到守护进程初始化阶段(关闭标准文件描述符之后、进入循环之前)仅执行一次,心跳循环只保留设备状态读取逻辑,反复开关设备会导致内核USB驱动资源占用异常,引发识别失败。 - 排查权限问题:确认守护进程的运行用户归属的用户组,与udev规则中分配VM167设备权限的用户组一致,测试时可以临时将udev规则中设备的MODE改为
0666验证是否为权限问题。 - 处理标准描述符关闭的影响:VM167驱动依赖的libusb在标准输入输出描述符被直接关闭的场景下可能出现异常,将关闭描述符的逻辑替换为重定向到
/dev/null:int fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close(fd); - 调整初始化顺序:libusb的上下文无法跨fork继承,可将
OpenDevices()的初始化逻辑移到fork操作之前的父进程中执行,再将设备句柄传递到子进程使用。
内容的提问来源于stack exchange,提问作者Dangerarea
相关产品推荐
相关产品推荐

