在什么情况下 Linux epoll_wait return epoll_events 会构造一个空的事件字段?
Under what conditions will Linux epoll_wait return epoll_events struct with an empty events field?
我编写了一个事件循环来处理文件描述符 read/write 事件。我已经成功编写了支持kqueue的代码版本和支持select的第二版本。我正在开发我的第三个也是最后一个版本,它将支持 epoll。
我在为 EPOLLIN 事件注册新描述符时遇到问题。有问题的描述符已经是 "listening" 用于连接,所以我等待读取事件发生,以便我知道下一次调用 "accept" 会成功(非阻塞接受的常见做法)。
所有文件描述符都设置为非阻塞。
我调用了 epoll_wait returns 两个针对同一描述符的事件。第一个事件的事件字段设置为 EPOLLIN 的值。第二个事件结构的事件字段设置为 0/空。 data.fd 字段列出了与第一个结构相同的 FD 编号。
在什么情况下 epoll_wait 会 return 事件结构的事件字段为零?
这种情况并非每次都会发生,但 90% 以上的情况都会发生。
最后,我会 post 代码,但这是用 Ruby 编写的,并且有很多样板来包装 FFI 中的套接字、侦听、接受等功能,设置常量等。示例代码会很长且笨拙,所以我没有 posting 任何代码。
上面的问题是垃圾进,垃圾出的情况。在收到评论者的投诉后,我删除了 Ruby
标签,但我需要将其添加回来。问题源于 epoll_event
结构的 Ruby FFI 定义。这是原始的错误代码:
class EPollDataUnion < FFI::Union
layout \
:ptr, :pointer,
:fd, :int,
:u32, :uint32,
:u64, :uint64
end
class EPollEventStruct < FFI::Struct
layout \
:events, :uint32,
:data, EPollDataUnion
end
上面的定义产生了一个大小为 16 字节的 EpollEventStruct
。该结构应为 12 个字节。
问题是第二个结构中的 data
字段偏移了 8 个字节。默认情况下,Ruby 的 FFI 实现将所有字段对齐 8 字节边界。解决方法是指定应打包该结构。
class EPollEventStruct < FFI::Struct
pack 1 # force alignment on 1-byte boundaries
layout \
:events, :uint32, # offset at byte 0
:data, EPollDataUnion # offset at byte 4
end
因此,当我的代码将堆内存传递给 epoll_ctl
和 epoll_wait
函数时,它对过大的事件结构进行操作。这个损坏的内存反过来产生了没有意义的损坏结果(即为同一个 FD 返回 2 个事件,第二个结构没有设置 events
位)。
我编写了一个事件循环来处理文件描述符 read/write 事件。我已经成功编写了支持kqueue的代码版本和支持select的第二版本。我正在开发我的第三个也是最后一个版本,它将支持 epoll。
我在为 EPOLLIN 事件注册新描述符时遇到问题。有问题的描述符已经是 "listening" 用于连接,所以我等待读取事件发生,以便我知道下一次调用 "accept" 会成功(非阻塞接受的常见做法)。
所有文件描述符都设置为非阻塞。
我调用了 epoll_wait returns 两个针对同一描述符的事件。第一个事件的事件字段设置为 EPOLLIN 的值。第二个事件结构的事件字段设置为 0/空。 data.fd 字段列出了与第一个结构相同的 FD 编号。
在什么情况下 epoll_wait 会 return 事件结构的事件字段为零?
这种情况并非每次都会发生,但 90% 以上的情况都会发生。
最后,我会 post 代码,但这是用 Ruby 编写的,并且有很多样板来包装 FFI 中的套接字、侦听、接受等功能,设置常量等。示例代码会很长且笨拙,所以我没有 posting 任何代码。
上面的问题是垃圾进,垃圾出的情况。在收到评论者的投诉后,我删除了 Ruby
标签,但我需要将其添加回来。问题源于 epoll_event
结构的 Ruby FFI 定义。这是原始的错误代码:
class EPollDataUnion < FFI::Union
layout \
:ptr, :pointer,
:fd, :int,
:u32, :uint32,
:u64, :uint64
end
class EPollEventStruct < FFI::Struct
layout \
:events, :uint32,
:data, EPollDataUnion
end
上面的定义产生了一个大小为 16 字节的 EpollEventStruct
。该结构应为 12 个字节。
问题是第二个结构中的 data
字段偏移了 8 个字节。默认情况下,Ruby 的 FFI 实现将所有字段对齐 8 字节边界。解决方法是指定应打包该结构。
class EPollEventStruct < FFI::Struct
pack 1 # force alignment on 1-byte boundaries
layout \
:events, :uint32, # offset at byte 0
:data, EPollDataUnion # offset at byte 4
end
因此,当我的代码将堆内存传递给 epoll_ctl
和 epoll_wait
函数时,它对过大的事件结构进行操作。这个损坏的内存反过来产生了没有意义的损坏结果(即为同一个 FD 返回 2 个事件,第二个结构没有设置 events
位)。