当子级调用libusb_exit()后,libusb-1.0 hotplug事件在fork()之后在父级中停止工作 [英] libusb-1.0 hotplug events stop working in parent after fork(), when child calls libusb_exit()

查看:251
本文介绍了当子级调用libusb_exit()后,libusb-1.0 hotplug事件在fork()之后在父级中停止工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在开发使用libusb_hotplug_register_callback()监视USB设备树的应用程序.连接符合某些条件的设备时,它将fork()exec()一个应用程序处理该设备.

I've been developing an application that monitors the USB device tree using libusb_hotplug_register_callback(). When a device that matches some criteria is attached, it will fork() and exec() an application to handle this device.

该应用程序已经运行了一段时间,但我回来尝试整理" ...

The application has been working fine for some time now, but I've come back to try and 'tidy it up'...

libusb将打开许多文件描述符(请参见下文),以监视事件等.问题是,在我调用fork()之后,在我调用exec()之前,我想关闭libusb ,关闭文件描述符并使子节点保持干净状态.

libusb will open a number of file descriptors (see below) which it monitors for events, etc... The problem is that after I call fork() and before I call exec(), I'd like to shutdown libusb, closing the file descriptors and leaving the children in a clean state.

root@imx6q:~# ls -l /proc/14245/fd
total 0
lrwx------ 1 root root 64 Feb  9 18:15 0 -> /dev/pts/2
lrwx------ 1 root root 64 Feb  9 18:15 1 -> /dev/pts/2
lrwx------ 1 root root 64 Feb  9 18:15 2 -> /dev/pts/2
lrwx------ 1 root root 64 Feb  9 18:15 3 -> socket:[1681018]
lr-x------ 1 root root 64 Feb  9 18:15 4 -> pipe:[1681019]
l-wx------ 1 root root 64 Feb  9 18:15 5 -> pipe:[1681019]
lr-x------ 1 root root 64 Feb  9 18:15 6 -> pipe:[1681020]
l-wx------ 1 root root 64 Feb  9 18:15 7 -> pipe:[1681020]
lrwx------ 1 root root 64 Feb  9 18:15 8 -> anon_inode:[timerfd]

孩子:

root@imx6q:~# ls -l /proc/14248/fd
total 0
lr-x------ 1 root root 64 Feb  9 18:15 0 -> /dev/null
l-wx------ 1 root root 64 Feb  9 18:15 1 -> /dev/null
lrwx------ 1 root root 64 Feb  9 18:15 2 -> /dev/pts/2
lr-x------ 1 root root 64 Feb  9 18:15 4 -> pipe:[1681019]
l-wx------ 1 root root 64 Feb  9 18:15 5 -> pipe:[1681019]
lr-x------ 1 root root 64 Feb  9 18:15 6 -> pipe:[1681020]
l-wx------ 1 root root 64 Feb  9 18:15 7 -> pipe:[1681020]
lrwx------ 1 root root 64 Feb  9 18:15 8 -> anon_inode:[timerfd]

我遇到的问题是,通过在子级中调用libusb_exit(),父级将不再看到任何热插拔事件.

The issue I've come up against, is that by calling libusb_exit() in the child, the parent no longer sees any hotplug events.

我尝试在fork()之后(在父级中)没有运气(也没有错误)后重新注册我的回调.

I've tried re-registering my callback after a fork() (in the parent) with no luck (and no errors).

我在libusb和libudev来源中有一些流言语,我想知道这是否是libusb的linux_udev_stop_event_monitor()调用udev_monitor_unref()的副作用...但是可惜没有交流" '那里,当引用计数达到零时,只需调用close(). 而且无论如何,上面缺少的套接字很可能是udev打开的netlink套接字(礼貌地使用SOCK_CLOEXEC).

I've had a bit of a rummage in the libusb and libudev sources, and I'm wondering if this is a side-effect of libusb's linux_udev_stop_event_monitor() calling udev_monitor_unref()... But alas there is no 'communication' there, just a call to close() when the ref count reaches zero. And anyway, the missing socket from above is most likely the netlink socket that udev opens (politely, with SOCK_CLOEXEC).

下面是一个演示该问题的示例应用程序:

Below is an example application that demonstrates the issue:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <libusb-1.0/libusb.h>

libusb_context *libusb_ctx;
libusb_hotplug_callback_handle cb_handle;

int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data) {
    pid_t pid;
    char *cmd[] = {
        "sleep", "600", NULL
    };

    fprintf(stderr, "event! %d\n", event);

    /* fork, and return if in parent */
    pid = fork();
    assert(pid != -1);
    if (pid != 0) {
        fprintf(stderr, "intermediate child's PID is: %d\n", pid);
        return 0;
    }

    /* setsid() and re-fork() to complete daemonization */
    assert(setsid() != -1);
    pid = fork();
    assert(pid != -1);
    if (pid != 0) {
        fprintf(stderr, "child's PID is: %d\n", pid);
        exit(0);
    }

#if 1 /* toggle this */
    fprintf(stderr, "libusb is NOT shutdown in child...\n");
#else
    /* shutdown libusb */
    libusb_hotplug_deregister_callback(libusb_ctx, cb_handle);
    libusb_exit(libusb_ctx);
    fprintf(stderr, "libusb is shutdown in child...\n");
#endif

    /* now that the child has reached this point, you'll never see a hotplug event again! */

    /* exec() */
    assert(execvp(cmd[0], cmd) == 0);
    abort();
}

void main(void) {
    pid_t pid;

    /* setup libusb & hotplug callback */
    assert(libusb_init(&libusb_ctx) == 0);
    assert(libusb_hotplug_register_callback(libusb_ctx, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY,
                                            LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, &cb_handle) == LIBUSB_SUCCESS);

    pid = getpid();
    fprintf(stderr, "running... parent's PID is: %d\n", pid);

    /* allow libusb to handle events */
    while (1) {
        assert(libusb_handle_events_completed(NULL, NULL) == 0);
    }
}

将'toggle this'#if设置为1,我看到以下会话(3个连接):

With the 'toggle this' #if set to 1, I see the following session (3x connections):

# ./main
running... parent's PID is: 14370
event! 1
intermediate child's PID is: 14372
child's PID is: 14373
libusb is NOT shutdown in child...
event! 1
intermediate child's PID is: 14375
child's PID is: 14376
libusb is NOT shutdown in child...
event! 1
intermediate child's PID is: 14379
child's PID is: 14380
libusb is NOT shutdown in child...
^C

将'toggle this'#if设置为0,我看到了以下会话(3x连接,只有第一个被操作):

With the 'toggle this' #if set to 0, I see the following session (3x connections, only the first is actioned):

# ./main
running... parent's PID is: 14388
event! 1
intermediate child's PID is: 14390
child's PID is: 14391
libusb is shutdown in child...
^C

软件版本为:

  • libusb:libusb-1.0.so.0.1.0/1.0.20-r1
  • libudev:libudev.so.0.13.1/182-r7
  • 内核:3.14.38

如果有人以前看过此书,或者可以重现(或无法重现!),我将不胜感激. 预先感谢!

If anyone has seen this before, or can reproduce it (or can't reproduce it!) I'd appreciate your input. Thanks in advance!

推荐答案

通常,我不建议从可移植的libusb程序中调用fork,除非fork后面紧跟exec.这是由于OS X上fork的已知问题所致.该问题在前一段时间(2002)上的libusb-devel邮件列表中进行了讨论,似乎我忘了将此警告添加到libusb-1.0的文档中.我建议改用线程.

In general I do not recommend calling fork from an portable libusb program unless fork is immediately followed by exec. This is due to known issues with fork on OS X. The issue was discussed on the libusb-devel mailing list some time ago (2002) and it looks like I forgot to add this caveat to the documentation for libusb-1.0. I recommend using threads instead.

在Linux上,我们从libudev继承了所有fork警告.我没有在他们的文档中看到任何有关fork的内容,因此我不知道它是否应该起作用.您始终可以通过添加--disable-udev尝试使用netlink.不建议将此选项用于生产环境,但可以帮助您找出问题所在.

On Linux we inherit any fork caveats from libudev. I do not see anything in their documentation about fork so I do not know if it should work or not. You can always try with netlink by adding --disable-udev. This option is not recommended for production use but it might help isolate the problem.

这篇关于当子级调用libusb_exit()后,libusb-1.0 hotplug事件在fork()之后在父级中停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆