iv_event: Implement fairness by list splicing.

When iv_event_run_pending_events() is called, we want it to only
process events that were active before the function was called.  This
is currently done by inserting a sentinel element, but it's easier to
just move all events to a local list on entry to the function and
then work off the local list.  This simplifies the locking as well.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
iv_wait: Implement fairness by list splicing.

When iv_wait_completion() is called, we want it to only process wait
events that were queued before the function was called.  We'll do
this in the same way as iv_task and iv_event do, by moving all wait
events to a local list on entry to the function and then working off
the local list.  If we exit the function with wait events pending,
iv_event guarantees that we'll be called again at a later time.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
iv_work: Implement fairness for thread work items using sequence numbers.

When iv_work_thread_got_event() is called, we want it to only process
work items that were registered before the function was called.

We can't do this by moving all work items to a local list like it
is done elsewhere in ivykis, since the list of pending work items
is shared between all threads in the thread pool, and so this would
starve other threads of work.

What we can do instead is to (virtually) assign each work item a
sequence number at enqueue time, and when it's time to process work
items, only process work items that have a sequence number less than
or equal to the sequence number of the last work item on the list
when we entered this thread's work processing function.

If we exit iv_work_thread_got_event() with work items pending,
iv_event guarantees that we'll be called again at a later time.

To make things slightly more efficient, we'll make a small change to
the handling of the idle thread list and the idle timer: if we exit
iv_work_thread_got_event() with work items pending, we won't re-add
ourselves to the list of idle threads, and we won't restart the idle
timer.  We'll detect this condition in the next call of the function
by checking whether thr->list is on a list, and if not, we'll skip
deleting ourselves from the list of idle threads and stopping the
idle timer on entry.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
iv_work: Implement fairness for completion handlers by list splicing.

When iv_work_event() is called, we want it to only invoke work item
completion callbacks for work items that completed before the function
was called.  We'll do this in the (by now) usual way, by moving all
completed work items to a local list on entry to the function and then
working off the local list.  This simplifies the locking as well.  If
we exit the function with completed work items pending, iv_event
guarantees that we'll be called again at a later time.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
iv_work: Implement fairness for local work items by list splicing.

When iv_work_handle_local() is called, we want it to only process
work items that were registered before the function was called.  We'll
do this in the (by now) usual way, by moving all work items to a local
list on entry to the function and then working off the local list.  If
we exit the function with work items pending, iv_task guarantees that
we'll be called again at a later time.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>