简体   繁体   English

在 Linux 守护进程中使用用户空间驱动程序

[英]Using a userspace driver in Linux daemon

I'm trying to write a daemon that monitors the state of a USB GPIO device (Velleman VM167) and will then act on changed.我正在尝试编写一个守护程序来监视 USB GPIO 设备 (Velleman VM167) 的状态,然后将根据更改采取行动。

I've found a userspace driver ( https://github.com/rahlskog/VM167 ) and have set some /etc/udev rules and ldconfig paths so that I can run the test and it works as expected.我找到了一个用户空间驱动程序 ( https://github.com/rahlskog/VM167 ) 并设置了一些 /etc/udev 规则和 ldconfig 路径,以便我可以运行测试并按预期工作。

If I compile the following it works as expected:如果我编译以下内容,它会按预期工作:

#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

However when I add this to a daemon template I can no longer see the USB card...但是,当我将它添加到守护程序模板时,我再也看不到 USB 卡了...

#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

Whelp, seems I forgot to close the device each loop.小鬼,似乎我忘记在每个循环中关闭设备。 That's resolved it.这样就解决了。

CloseDevices();

You call OpenDevices() at the start of every loop.您在每个循环开始时调用OpenDevices() Surely, you need to close them at the end of the loop.当然,您需要在循环结束时关闭它们。 Since your real (commented out) code has early returns, the proper C++ way of dealing with this is to add a RAII wrapper around OpenDevices() and CloseDevices() to make sure that opened devices are also closed.由于您的真实(注释掉)代码会提前返回,因此处理此问题的正确 C++ 方法是在OpenDevices()CloseDevices()周围添加一个 RAII 包装器,以确保打开的设备也已关闭。

Example:例子:

// A wrapper that open devices on creation and closes them on destruction, 
// like when it goes out of scope.
struct DeviceCtx {
    DeviceCtx() : devices(OpenDevices()) {}
    ~DeviceCtx() { CloseDevices(); }

    operator int() const { return devices; }  // implicit conversion to `int`

    int devices;
};

void do_heartbeat() { // 
    syslog(LOG_INFO, "Loop");

    DeviceCtx devices;                 // calls OpenDevices

    if (devices == 0) {
        syslog(LOG_ERR, "Driver error condition, exiting");
        return;                        // CloseDevices() will be called

    } else if (devices == -1) {
        syslog(LOG_ERR, "No devices found on system, exiting\n");
        return;                        // CloseDevices() will be called
    }

    int ver = VersionDLL();
    syslog(LOG_INFO, "DLL Version: %d.%d.%d.%d\n", (ver >> 24),
           (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);

}   // `devices` goes out of scope and calls CloseDevices()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM