So I debugged this a little and two things caught my attention:
Problem 1
https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/core/drivers/libevent2.d#L747
while ((m_activeEvents & which) == Trigger.none)
getThreadLibeventDriverCore().yieldForEvent();
What if I created the FileDescriptorEvent
with Trigger.any
, then wait(Trigger.read)
? A connection will almost always be signalled as writeable, and as long as I don't write data it will stay writeable. So the event will trigger all the time and set m_activeEvents
to Trigger.write
causing a busy loop?
I think vibed should rearm the event instead of using a repeating event, at least if the trigger changed.
Problem 2
But the real problem here is different: The event is not unarmed fast enough:
After wait yields here onFileTriggered
is called once. The first time evt.m_waiter
is set, the task is continued and wait returns as expected. However, the event is still alive and onFileTriggered
will be called many more times this time doing effectively nothing. evt.m_waiter
is null, so it only sets the triggers but nobody ever reads/writes data on the file descriptor and onFileTriggered
fires again and again. I'm not sure why this even stops eventually is this only because of the GC collecting the FileDescriptorEvent
? This is obviously also a problem even if data is still being read.
The naive solution to both problems it to create the event in wait, then delete it as soon as wait completes. I guess you ruled that out for performance reasons?
The other solution for problem two is to event_add
the event at the start of wait
and event_del
before wait
returns. Problem 1 still needs to be solved then, though. Probably by creating a new event when the trigger type changes.