为什么我的 D2XX 应用程序在分叉时不起作用?
Why does my D2XX application not work when forked?
我正在用 C 编写一个简单的应用程序,运行在 Raspberry Pi 上使用 D2XX drivers 与串行端口设备进行通信。我遵循了许多在线教程和参考指南来使其正常工作,并采取了设置自定义 udev 规则等步骤以确保驱动程序可以正确加载,我按照 FTDI 的构建说明安装共享库,我使用编译时 gcc 的 -l
参数为库中的 link,我 运行 我的 C 程序带有 sudo
以确保驱动程序具有正确的访问权限。那是成功的!该程序按预期工作。
现在我正在尝试将我的简单程序转换为可以使用 init.d 脚本(a 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
,但不幸的是它不起作用。在一个单独的控制台 window 中,我正在跟踪 /var/log/messages
文件,我可以清楚地看到它到达了我的第一条日志消息(即 "I can get to this line"),但紧接着它就死在了水。我从来没有看到第二条日志消息,事实上,在那个时候程序变得完全没有响应。我必须找到它的进程 ID 并杀死它。
换句话说,一旦它试图调用派生进程中的 D2XX 驱动程序,它就会失败。我究竟做错了什么?我已经在第一个示例中演示了代码 确实有效 ,那么 运行ning 作为守护进程会导致它完全崩溃的原因是什么?据我所知,它甚至没有机会执行相关的 D2XX 方法;就好像它一开始就找不到方法,而 运行 在分叉的过程中。
可能是因为它使用 libusb
...而且他们似乎做得不好。
在这里查看我的问题:
以及此处的讨论:https://github.com/libusb/libusb/issues/268
我的具体问题与热插拔事件有关,但我预计您也会遇到其他问题。
这在您的场景中不太明显的原因是因为它们可能在加载库时(它们的种类)而不是在您开始使用它时进行一些设置/初始化。
正如@duskwuff 所指出的,这里还有另一个答案:
刚刚玩完了,请看下面:
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)
它甚至在到达 main()
之前就在 libusb_init()
上遇到了断点,从他们的 my_init()
调用。
我正在用 C 编写一个简单的应用程序,运行在 Raspberry Pi 上使用 D2XX drivers 与串行端口设备进行通信。我遵循了许多在线教程和参考指南来使其正常工作,并采取了设置自定义 udev 规则等步骤以确保驱动程序可以正确加载,我按照 FTDI 的构建说明安装共享库,我使用编译时 gcc 的 -l
参数为库中的 link,我 运行 我的 C 程序带有 sudo
以确保驱动程序具有正确的访问权限。那是成功的!该程序按预期工作。
现在我正在尝试将我的简单程序转换为可以使用 init.d 脚本(a 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
,但不幸的是它不起作用。在一个单独的控制台 window 中,我正在跟踪 /var/log/messages
文件,我可以清楚地看到它到达了我的第一条日志消息(即 "I can get to this line"),但紧接着它就死在了水。我从来没有看到第二条日志消息,事实上,在那个时候程序变得完全没有响应。我必须找到它的进程 ID 并杀死它。
换句话说,一旦它试图调用派生进程中的 D2XX 驱动程序,它就会失败。我究竟做错了什么?我已经在第一个示例中演示了代码 确实有效 ,那么 运行ning 作为守护进程会导致它完全崩溃的原因是什么?据我所知,它甚至没有机会执行相关的 D2XX 方法;就好像它一开始就找不到方法,而 运行 在分叉的过程中。
可能是因为它使用 libusb
...而且他们似乎做得不好。
在这里查看我的问题:
以及此处的讨论:https://github.com/libusb/libusb/issues/268
我的具体问题与热插拔事件有关,但我预计您也会遇到其他问题。
这在您的场景中不太明显的原因是因为它们可能在加载库时(它们的种类)而不是在您开始使用它时进行一些设置/初始化。
正如@duskwuff 所指出的,这里还有另一个答案:
刚刚玩完了,请看下面:
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)
它甚至在到达 main()
之前就在 libusb_init()
上遇到了断点,从他们的 my_init()
调用。