Кевент и USB последовательные порты

У меня проблемы с использованием Kevent на Mac с последовательной консолью USB. Я сузил это до:

#include <errno.h>                                                                                                                                          
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/event.h>
#include <sys/ioctl.h>
#include <termios.h>

#define DEVICE "/dev/cu.usbserial-0011111D"

int main() {
  int kqueue_fd = kqueue();
  if (kqueue_fd < 0) {
    printf("Failed to open kqueue\n");
    return -1;
  }
  int device_fd = open(DEVICE, O_RDWR | O_NONBLOCK | O_NOCTTY);
  if (device_fd < 0) {
    printf("Failed to open device: %s\n", DEVICE);
    return -1;
  }
  printf("Opened %d\n", device_fd);

  enum { MAX_EVENTS = 1 };
  struct kevent events[MAX_EVENTS];

  EV_SET(&events[0], device_fd, EVFILT_READ, EV_ADD, 0, 0, NULL);

  int r = kevent(kqueue_fd, events, 1, NULL, 0, NULL);
  if (r < 0) {
    printf("kevent failed: %s\n", strerror(errno));
    return -1;
  }

  struct timespec sleep_time;
  sleep_time.tv_sec = 5;
  sleep_time.tv_nsec = 0;

  int ready = kevent(kqueue_fd, NULL, 0, (struct kevent*) &events,
                     MAX_EVENTS, &sleep_time);
  if (ready == 0) {
    printf("No event\n");
    return 0;
  }
  for (int i = 0; i < ready; i++) {
    printf(".ident %ld, .filter %d, .flags 0x%x, .fflags 0x%x, "
           ".data: %ld, .udata %p\n",
           events[i].ident,
           events[i].filter,
           events[i].flags,
           events[i].fflags,
           events[i].data,
           events[i].udata);

    int unread = 0;
    r = ioctl(events[i].ident, FIONREAD, &unread);
    if (r < 0) {
      printf("ioctl failed: %d: %s\n", errno, strerror(errno));
    }
  }
}

Когда я запускаю это и отключаю USB-устройство во время вызова kevent(), я получаю:

Opened 4
.ident 4, .filter -1, .flags 0x1, .fflags 0x0, .data: 6, .udata 0x0
ioctl failed: 6: Device not configured

Насколько я понимаю, содержание события означает:

FD 4, EVFILT_READ, EV_ADD, 6 байтов осталось на fd. Но ioctl() завершается ошибкой (так как устройство было удалено), и errno также равно 6, поэтому кажется, что event.data возвращает errno, а не оставшиеся байты.

Как я могу различить случай обычного чтения и случай, когда устройство было удалено? Фильтр, флаги и флаги выглядят одинаково в обоих случаях.

Дополнительная информация

Если я переключаюсь с открытия последовательной консоли на канал и записываю один байт с последующим закрытием конца записи, я получаю:

pipe() fd: 5 -> 4
.ident 4, .filter -1, .flags 0x1, .fflags 0x0, .data: 1, .udata 0x0
.ident 4, .filter -1, .flags 0x8001, .fflags 0x0, .data: 0, .udata 0x0

Это то, что я ожидаю, так как 0x8000 - это EV_EOF.

0 ответов

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