Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macos 凯文;USB串行端口_Macos_Usbserial_Kqueue_Xnu_Kevent - Fatal编程技术网

Macos 凯文;USB串行端口

Macos 凯文;USB串行端口,macos,usbserial,kqueue,xnu,kevent,Macos,Usbserial,Kqueue,Xnu,Kevent,我在mac上使用kevent和USB串行控制台时遇到问题。我把范围缩小到: #include <errno.h> #include <fcntl.h> #include <stdio.h>

我在mac上使用kevent和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));
    }
  }
}
我的理解是,活动的内容转化为:

FD 4,EVFILT_读取,EV_添加,FD上剩余6字节。但是ioctl()失败(因为设备已被删除),并且errno也是6,因此似乎event.data返回的是errno,而不是剩余的字节

如何区分正常读取情况和设备已卸下的情况?在这两种情况下,过滤器、标志和FFLAG显示相同

其他信息

如果我从打开串行控制台切换到管道,然后写入一个字节,然后关闭写入端,我会得到:

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。

您似乎找到了区分案例的方法:后续
ioctl()操作的行为。为什么这还不够好?在kevent结构中返回信息的目的是为了避免额外的系统调用。除了断开设备连接不是文件结束条件之外
kevent()
没有任何方法来表示后续尝试读取描述符将产生错误。它所能做的就是告诉您必须从设备读取一个条件才能检测。似乎kevent正试图在数据字段中返回有关该条件的信息,因为它与ioctl()中的errno匹配。我希望设置EV_ERROR。当我阅读手册页时,
EV_ERROR
是关于
kevent()
本身在处理
changelist
时遇到错误,在第二次调用中为
NULL
。这与被监视的事物(本例中为文件描述符)上的错误无关。此外,设备的
EVFILT\u READ
的语义也不清楚。它们不是套接字、VNode、FIFO或管道。因此,我不会在
数据
字段的任何一种解释中投入太多精力。
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