Libusb-1.0 hotplug events stop working in the parent after fork () when a child call calls libusb_exit ()

I am developing an application that monitors the tree of USB devices using libusb_hotplug_register_callback(). If the device is attached, which corresponds to some of the criteria, it will be fork(), and exec()to handle the device.

The application has been working fine for some time, but I came back to try to "remove it" ...

libusb will open several file descriptors (see below) that it tracks for events, etc. The problem is that after the call fork()and before I call exec(), I would like to disable libusb by closing the file descriptors and leaving the children in a clean state.

Parent:

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]

Child:

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() , hotplug.

fork() ( ) ( ).

libusb libudev , , libusb linux_udev_stop_event_monitor(), udev_monitor_unref()... , , ', close(), . , , , netlink, udev (, SOCK_CLOEXEC).

, :

#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 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 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 PID is: %d\n", pid);

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

"toggle this" #if 1, (3x ):

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

"toggle this" #if 0, (3x , ):

# ./main
running... parent PID is: 14388
event! 1
intermediate child PID is: 14390
child 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

- ( !), . !

0
1

, fork libusb, fork exec. fork OS X. libusb-devel (2002), , libusb-1.0. .

Linux fork libudev. , , . netlink, --disable-udev. , .

+1

All Articles