NetBSD kqueue:用户数据类型不一致(kevent.udata)
我在macOS、FreeBSD、NetBSD、OpenBSD、DragonflyBSD上使用kqueue(2)。
kevent结构定义如下。具体来说,字段 udata 是指向某个用户自定义数据结构的指针。
struct kevent {
uintptr_t ident; /* identifier for this event */
short filter; /* filter for event */
u_short flags;
u_int fflags;
intptr_t data;
void *udata; /* opaque user data identifier */
};
在上述所有系统上都成立,除了NetBSD,其文档和系统头文件不一致。
$ uname -a
NetBSD vminetbsd 10.1 NetBSD 10.1 (GENERIC) #0: Mon Dec 16 13:08:11 UTC 2024 [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC amd64
$ grep udata /usr/include/sys/event.h
intptr_t udata; /* opaque user data identifier */
这里,udata 字段是一个整数,当传递一个用户数据结构的地址时,应用程序的编译会失败。当然,可以在某个 #ifdef 结构中使用类型转换来使应用程序具备可移植性,尽管可读性要差很多。
然而,这并不简单。
在同一台NetBSD系统上,man kqueue 也显示 intptr_t udata。不过NetBSD的网站却记录了相反的说法。
在 https://man.netbsd.org/kqueue.2,标题是 “kqueue(2) - NetBSD Manual Pages”,内容写着 “void *udata”,不是整数。
NetBSD的网站还包含一个不错的kqueue教程,位于 https://wiki.netbsd.org/tutorials/kqueue_tutorial/,它也写着 “void *udata”,不是整数。
因此,NetBSD看起来有点不一致。网站和官方文档自称“标准的”,或至少像其他BSD一样。但实际系统的最新版本(10.1)在头文件和手册页中显示的却不同。
我们能说这是NetBSD的一个bug吗?应该把这些问题报告到哪里?
在NetBSD上在应用代码中使用 #ifdef 进行类型转换,若问题得到修复,后续就会变得不再正确。
解决方案
我刚刚启动一个虚拟机,重新安装了NetBSD 10.1。它的 /usr/include/sys/event.h 将 struct kevent 的 udata 字段定义为一个 void *,并且对 EVFILT_USER 过滤器有定义。
从变更日志来看,该字段的类型以及对用户过滤器的支持是在NetBSD 9到 10.0之间新增的。你的10.1安装没有反映这一点的更新头文件(第一行应该写着文件版本为1.54),这表明你是从9.X升级而来,升级过程中出了问题,导致更新后的头文件没有覆盖旧版本的头文件,或者你的安装还有其他问题。一个正常的10.1安装确实会遵循文档。