Почему мое приложение D2XX не работает при разветвлении?

Я пишу простое приложение на C, работающее на Raspberry Pi, которое использует драйверы D2XX для связи с устройством с последовательным портом. Я следовал нескольким онлайн-учебникам и справочным руководствам, чтобы заставить его работать, и предпринял шаги, такие как установка пользовательских правил udev для обеспечения правильной загрузки драйверов, я следовал инструкциям по сборке FTDI для установки разделяемой библиотеки, я использую -l аргумент gcc для ссылки в библиотеке при компиляции, и я запускаю свою программу на C с sudo чтобы обеспечить водителям надлежащий доступ. И это был успех! Программа работает как задумано.

Сейчас я пытаюсь преобразовать мою простую программу в процесс-демон, которым можно управлять с помощью скрипта init.d 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 файл, и я ясно вижу, что он достигает моего первого сообщения в журнале (т.е. "Я могу добраться до этой строки"), но сразу после этого он мертв в воде. Я никогда не вижу второе сообщение журнала, и действительно, в этот момент программа перестает отвечать на запросы. Я должен найти его идентификатор процесса и убить его.

Другими словами, как только он пытается вызвать драйверы D2XX в разветвленном процессе, он терпит неудачу. Что я делаю неправильно? На первом примере я уже продемонстрировал, что код работает, так что же такое запуск демона, который приводит к его полной поломке? Насколько я могу судить, у него даже нет шанса выполнить рассматриваемый метод D2XX; как будто он просто не может найти метод во-первых, работая в разветвленном процессе.

1 ответ

Решение

Наверное, потому что он использует libusb... и они, кажется, делают это плохо.

См. Мой вопрос здесь: события hotplug libusb-1.0 перестают работать в parent после fork(), когда child вызывает libusb_exit()

И обсуждение здесь: https://github.com/libusb/libusb/issues/268

Моя конкретная проблема была связана с событиями горячего подключения, но я ожидаю, что другие вещи пойдут не так, как надо.

Причина, по которой это менее очевидно в вашем сценарии, заключается в том, что они, вероятно, выполняют некоторую настройку / инициализацию при загрузке библиотеки (как это происходит), а не когда вы начинаете ее использовать.

Как указал @duskwuff, здесь есть еще один ответ: /questions/14493994/pochemu-ftread-terpit-neudachu-v-dochernem-protsesse-no-rabotaet-v-roditelskom-protsesse/14494009#14494009


Я только что поиграл, следуйте ниже:

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

Другие вопросы по тегам