epoll: Give every waiter their own event queue
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 24 Feb 2017 19:40:14 +0000 (14:40 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 2 Mar 2017 18:01:28 +0000 (13:01 -0500)
commit40387f0228ae20b430c91294b7fbc219377eeff5
tree0f5b4f02ca5ca80cde333a0651eb7e404e03b5be
parent31e572ba36f16f7f17724bc3703977f6b9789d86
epoll: Give every waiter their own event queue

This was a brutal bug.  Basically, multiple epoll_wait() calls with
timeouts could consume each other's events.  They had independent async
syscs, but the notifications all went to the same evq (the old
ep->alarm_evq).

As a result, when uthreads blocked on the alarm evq, either for the main
blockon(ceq_evq, alarm_evq) or the dummy alarm_evq, they could wake up due
to another uthread's call.  Eventually, some uthread would get a real
event, then would try to cancel their alarm.  But someone else would get
the event_queue message (the one from the aborted syscall 'completing').
Then the original uthread would sleep for a long, undetermined amount of
time, based on when our uth happened to extract someone *else's* message,
since ours was gone.

The fix is to have separate event queues for each waiter (that has a
timeout), just like how they have their own syscall structures.

This is actually a nice opportunity to use a slab allocator, since we want
a bunch of constructed alarm objects sitting around.  Due to the INDIR/RCU
problem (can't safely reuse memory until all INDIRs are done), we don't
want to reuse the memory - keeping the objects around in a kmem_cache is
ideal.  The other benefit of the slab allocator is that we can use the same
pool of these for all epoll controllers, which means we'll never have more
of these than we have threads, instead of threads * nr_epoll_ctlrs.  (Round
up to the nearest slab size, btw).

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/iplib/epoll.c