-
Notifications
You must be signed in to change notification settings - Fork 78
Description
In contrast to the kernel-native implementation on BSD-based systems such as Darwin, libkqueue deviates from that/those implementations and the specification, insofar as the man page is a proxy for one in that not all changes to extant entries in the queue are not honored across calls to kqueue:
The kqueue man page cites:
All changes contained in the changelist are applied before any pending events are read from the queue.
This is particularly evident with EVFILT_TIMER in which the only opportunity to influence and set the timeout value is in evfilt_timer_knote_create in src/linux/timer.c.
This is demonstrated with the attached sample program, compiled and executed with:
% clang -Wall -Werror -fsanitize=address kqueue-timer-example.c -o kqueue-timer-example && ./kqueue-timer-example
on Darwin and with:
% clang-11 -Wall -Werror -fsanitize=address -I/usr/local/include/kqueue kqueue-timer-example.c -L/usr/local/lib -lkqueue -o kqueue-timer-example && ./kqueue-timer-example
on Linux. On Darwin, the changes to the EVFILT_TIMER data value are observed across kqueue calls and the wait correctly expires four (4) times at the second of the two data values pushed for the event, as expected. However, on Linux, using libkqueue-2.5.1, the wait only expires two (2) of the four (4) expected and does so at the first of the two data values pushed for those events.
The as-implemented behavior makes using kqueue via libkqueue for CFRunLoop timer support in opencflite problematic when multiple timers are at play when a later-added timer has a smaller or larger expiry than the prior timer, requiring the timer event in the kqueue to be adjusted downward or upward.