Skip to content

Use libusb-1.0 report of pollfd's in NUT main loop #2747

@jimklimov

Description

@jimklimov

As discussed in #2742 (comment) a NUT driver (any one of them) does some work in upsdrv_updateinfo(), effectively sleeps for the remainder of timeout in dstate_poll_fds() (if no extrafd like those for a serial port or a raw network socket gets bytes incoming, or a sockfd internal to dstate.c), and only then gets to run upsdrv_updateinfo() again and perhaps notice the absence of the device as reported by libusb.

NOTE: Currently extrafd is ignored in WIN32 builds, but we do handle sockfd so this might be extensible eventually. See also https://learn.microsoft.com/en-us/windows/win32/winsock/select-and-fd---2

Currently this shortcut is not really used by the majority of drivers, so they normally all "suffer" a standard delay between loop cycles, with the few hits being:

:; git grep extrafd
drivers/apcsmart-old.c: extrafd = upsfd;
drivers/apcsmart.c:     upsfd = extrafd = ser_open(device_path);
drivers/clone-outlet.c:         extrafd = upsfd = sstate_connect();
drivers/clone-outlet.c: extrafd = upsfd = sstate_connect();
drivers/clone.c:                extrafd = upsfd = sstate_connect();
drivers/clone.c:        extrafd = upsfd = sstate_connect();
drivers/dstate.c:int dstate_poll_fds(struct timeval timeout, TYPE_FD arg_extrafd)
drivers/dstate.c:       if (VALID_FD(arg_extrafd)) {
drivers/dstate.c:               FD_SET(arg_extrafd, &rfds);
drivers/dstate.c:               if (arg_extrafd > maxfd) {
drivers/dstate.c:                       maxfd = arg_extrafd;
drivers/dstate.c:       if (VALID_FD(arg_extrafd) && (FD_ISSET(arg_extrafd, &rfds))) {
drivers/dstate.c:       NUT_UNUSED_VARIABLE(arg_extrafd);
drivers/dstate.c:       if (VALID_FD(arg_extrafd)) {
drivers/dstate.c:               rfds[maxfd] = arg_extrafd;
drivers/dstate.c:       if (VALID_FD(arg_extrafd) && (ret == arg_extrafd)) {
drivers/dstate.h:int dstate_poll_fds(struct timeval timeout, TYPE_FD extrafd);
drivers/main.c:TYPE_FD  extrafd = ERROR_FD;
drivers/main.c:                 while (!dstate_poll_fds(timeout, extrafd) && !exit_flag) {
drivers/main.c:                         /* repeat until time is up or extrafd has data */
drivers/main.h:extern TYPE_FD           upsfd, extrafd;
drivers/netxml-ups.c:/* TODO: port extrafd to Windows */
drivers/netxml-ups.c:                   extrafd = ne_sock_fd(sock);
drivers/netxml-ups.c:/* TODO: port extrafd to Windows */
drivers/netxml-ups.c:                           extrafd = ne_sock_fd(sock);
drivers/apcsmart-old.c: extrafd = upsfd;
drivers/apcsmart.c:     upsfd = extrafd = ser_open(device_path);
drivers/clone-outlet.c:         extrafd = upsfd = sstate_connect();
drivers/clone-outlet.c: extrafd = upsfd = sstate_connect();
drivers/clone.c:                extrafd = upsfd = sstate_connect();
drivers/clone.c:        extrafd = upsfd = sstate_connect();
drivers/dstate.c:int dstate_poll_fds(struct timeval timeout, TYPE_FD arg_extrafd)
drivers/dstate.c:       if (VALID_FD(arg_extrafd)) {
drivers/dstate.c:               FD_SET(arg_extrafd, &rfds);
drivers/dstate.c:               if (arg_extrafd > maxfd) {
drivers/dstate.c:                       maxfd = arg_extrafd;
drivers/dstate.c:       if (VALID_FD(arg_extrafd) && (FD_ISSET(arg_extrafd, &rfds))) {
drivers/dstate.c:       NUT_UNUSED_VARIABLE(arg_extrafd);
drivers/dstate.c:       if (VALID_FD(arg_extrafd)) {
drivers/dstate.c:               rfds[maxfd] = arg_extrafd;
drivers/dstate.c:       if (VALID_FD(arg_extrafd) && (ret == arg_extrafd)) {
drivers/dstate.h:int dstate_poll_fds(struct timeval timeout, TYPE_FD extrafd);
drivers/main.c:TYPE_FD  extrafd = ERROR_FD;
drivers/main.c:                 while (!dstate_poll_fds(timeout, extrafd) && !exit_flag) {
drivers/main.c:                         /* repeat until time is up or extrafd has data */
drivers/main.h:extern TYPE_FD           upsfd, extrafd;
drivers/netxml-ups.c:/* TODO: port extrafd to Windows */
drivers/netxml-ups.c:                   extrafd = ne_sock_fd(sock);
drivers/netxml-ups.c:/* TODO: port extrafd to Windows */
drivers/netxml-ups.c:                           extrafd = ne_sock_fd(sock);

As documented in https://libusb.sourceforge.io/api-1.0/group__libusb__poll.html#ga54c27dcf8a95d2a3a03cfb7dd37eae63 and https://libusb.sourceforge.io/api-1.0/structlibusb__pollfd.html the LibUSB-1.0 API actually allows programs to see the collection of file descriptors (and their event flags from poll.h) associated with a context, so we have a chance to redesign driver loops (not sure OTOH there's one or more extrafd equivalents in our case) in such a way that we can react more quickly to USB device events. Note there does not seem to be any similar facility in older LibUSB-0.1 headers.

This idea may also help with #2609 as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    USBWindowsWindows-not-on-par-with-POSIXAspect of Windows builds known to be dysfunctional compared to POSIX builds; fix needed to be on parenhancement

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions