为什么我的D2XX应用程序在分叉时不起作用?

时间:2017-03-24 03:43:57

标签: c linux raspberry-pi daemon d2xx

我在C中编写一个简单的应用程序,在Raspberry Pi上运行,它利用D2XX drivers与串行端口设备进行通信。我已经按照一些在线教程和参考指南来实现它,并采取了诸如设置自定义udev规则以确保驱动程序可以正确加载的步骤,我按照FTDI的构建说明安装共享库,我使用编译时链接在库中的gcc的-l参数,我用sudo运行我的C程序以确保驱动程序具有适当的访问权限。这是成功的!该计划按预期运作。

现在我正在尝试将我的简单程序转换为可以使用init.d脚本(la service start)控制的守护进程,并且遇到了麻烦。

为简单起见,这是我的C程序的淡化版本,可以工作

myprog.c中:

#include <stdlib.h>
#include "ftd2xx.h"

int main(int argc, char *argv[])
{
    DWORD i, iNumDevs = 0;
    char *serialNumber = malloc(64);
    FT_STATUS ftStatus = FT_CreateDeviceInfoList(&iNumDevs);
    for (i = 0; i < iNumDevs; i++) {
        ftStatus = FT_ListDevices((PVOID)i, serialNumber, FT_LIST_BY_INDEX|FT_OPEN_BY_SERIAL_NUMBER);
        if (FT_OK == ftStatus) {
            break;
        }
    }

    // more code here...

    return EXIT_SUCCESS;
}

我用gcc -lftd2xx -o myprog myprog.c编译它,然后用sudo ./myprog运行它,并接受我的话,它会做它应该做的所有事情。但是现在我正在尝试将相同的代码重新编写成一个守护进程,我一直在关注其他一些在线教程,上面的代码已经变成了看起来更像这样的东西。目前,此不起作用:

mydaemon.c:

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "ftd2xx.h"

int main(int argc, char *argv[])
{
    pid_t pid, sid;
    pid = fork();
    if (pid < 0) {
        return EXIT_FAILURE;
    }

    if (pid > 0) {
        return EXIT_SUCCESS;
    }

    umask(0);
    openlog("mydaemon", LOG_PID|LOG_CONS, LOG_USER);

    sid = setsid();
    if (sid < 0) {
        syslog(LOG_ERR, "Failed to set session ID on child process");
        return EXIT_FAILURE;
    }

    if ((chdir("/")) < 0) {
        syslog(LOG_ERR, "Failed to change working directory");
        return EXIT_FAILURE;
    }

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    while (1) {

        DWORD i, iNumDevs = 0;
        char *serialNumber = malloc(64);

        syslog(LOG_INFO, "I get to this line");
        FT_STATUS ftStatus = FT_CreateDeviceInfoList(&iNumDevs);
        syslog(LOG_INFO, "I do not get to this line :( ");

        // more code here...

        sleep(10);
    }

    return EXIT_SUCCESS;
}

我以完全相同的方式编译该程序:gcc -lftd2xx -o mydaemon mydaemon.c;我以同样的方式运行它:sudo ./mydaemon,但不幸的是它不起作用。在一个单独的控制台窗口中,我正在拖尾/var/log/messages文件,我可以清楚地看到它到达我的第一条日志消息(即“我可以到达这条线”),但在此之后它立即死在水中。我从来没有看到第二条日志消息,事实上,在这一点上,程序变得完全没有响应。我必须找到它的进程ID并将其删除。

换句话说,只要它尝试在分叉进程中调用D2XX驱动程序,它就会失败。我究竟做错了什么?我已经使用第一个示例演示了代码是否正常工作,那么作为一个守护进程运行导致它完全崩溃的是什么呢?据我所知,它甚至没有机会执行有问题的D2XX方法;就好像在分叉的过程中运行时,它首先无法找到方法。

1 个答案:

答案 0 :(得分:0)

可能是因为它使用了libusb ......而且它们看起来很糟糕。

在此处查看我的问题:libusb-1.0 hotplug events stop working in parent after fork(), when child calls libusb_exit()

这里的讨论:https://github.com/libusb/libusb/issues/268

我的具体问题与hotplug事件有关,但我希望其他事情也会出错。

在你的场景中这不太明显的原因是因为他们可能在库加载时会做一些setup / init(它们是怎样的),而不是在你开始使用它的时候。

正如@duskwuff所指出的,这里有另一个答案:https://stackoverflow.com/a/35186414/149341

我刚刚完成了一些游戏,请按照以下步骤进行操作:

cd $(mktemp -d)
curl http://www.ftdichip.com/Drivers/D2XX/Linux/libftd2xx-x86_64-1.3.6.tgz | tar -xvz

将其放入test.c

#include <stdio.h>
#include "ftd2xx.h"

int main(void) {
    int num_devs;

    fprintf(stderr, "in to main()\n");

    FT_STATUS ft_status = FT_CreateDeviceInfoList(&num_devs);
    fprintf(stderr, "FT_CreateDeviceInfoList() returned: %d\n", ft_status);

    fprintf(stderr, "out of main()\n");

    return 0;
}

编译:

gcc test.c -o test -g -I release -L release/build -lftd2xx -ldl -lpthread

现在在gdb

[...]
Reading symbols from test...done.
(gdb) b libusb_init
Breakpoint 1 at 0x40cd20
(gdb) start
Temporary breakpoint 2 at 0x401d75: file test.c, line 7.
Starting program: /tmp/tmp.jJpBNywVzB/test 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x000000000040cd20 in libusb_init ()
(gdb) bt
#0  0x000000000040cd20 in libusb_init ()
#1  0x0000000000401f36 in my_init ()
#2  0x000000000041a05d in __libc_csu_init ()
#3  0x00007ffff7614ed5 in __libc_start_main (main=0x401d6d <main>, argc=1, argv=0x7fffffffe228, init=0x41a010 <__libc_csu_init>, fini=<optimised out>, rtld_fini=<optimised out>, stack_end=0x7fffffffe218)
    at libc-start.c:246
#4  0x0000000000401ca9 in _start ()
(gdb)

它在libusb_init()之前点击了main()之前的断点,从他们my_init()打来的recyclerview