iommu: use parse_cmd() for attach/detach
[akaros.git] / user / parlib / poke.c
1 /* Copyright (c) 2012 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Post work and poke synchronization.  This is a wait-free way to make sure
6  * some code is run, usually by the calling core, but potentially by any core.
7  * Under contention, everyone just posts work, and one core will carry out the
8  * work.  Callers post work (the meaning of which is particular to their
9  * subsystem), then call this function.  The function is not run concurrently
10  * with itself.
11  *
12  * As far as uthreads, vcores, and preemption go, poking is safe in uthread
13  * context and if preemptions occur.  However, a uthread running the poke
14  * function that gets preempted could delay the execution of the poke
15  * indefinitely.  In general, post-and-poke does not provide any guarantee about
16  * *when* the poke finally occurs.  If delays of this sort are a problem, then
17  * run poke() from vcore context.
18  *
19  * Adapted from the kernel's implementation. */
20
21 #include <parlib/poke.h>
22 #include <parlib/arch/atomic.h>
23 #include <parlib/assert.h>
24
25 /* This is the 'post (work) and poke' style of sync.  We make sure the poke
26  * tracker's function runs.  Once this returns, the func either has run or is
27  * currently running (in case someone else is running now).  We won't wait or
28  * spin or anything, and it is safe to call this recursively (deeper in the
29  * call-graph).
30  *
31  * It's up to the caller to somehow post its work.  We'll also pass arg to the
32  * func, ONLY IF the caller is the one to execute it - so there's no guarantee
33  * the func(specific_arg) combo will actually run.  It's more for info
34  * purposes/optimizations/etc.  If no one uses it, I'll get rid of it. */
35 void poke(struct poke_tracker *tracker, void *arg)
36 {
37         atomic_set(&tracker->need_to_run, TRUE);
38         /* will need to repeatedly do it if someone keeps posting work */
39         do {
40                 /* want an wrmb() btw posting work/need_to_run and in_progress.
41                  * the swap provides the HW mb. just need a cmb, which we do in
42                  * the loop to cover the iterations (even though i can't imagine
43                  * the compiler reordering the check it needed to do for the
44                  * branch).. */
45                 cmb();
46                 /* poke / make sure someone does it.  if we get a TRUE (1) back,
47                  * someone is already running and will deal with the posted
48                  * work.  (probably on their next loop).  if we got a 0 back, we
49                  * won the race and have the 'lock'. */
50                 if (atomic_swap(&tracker->run_in_progress, TRUE))
51                         return;
52                 /* if we're here, then we're the one who needs to run the func.
53                  * */
54                 /* clear the 'need to run', since we're running it now.  new
55                  * users will set it again.  this write needs to be wmb()'d
56                  * after in_progress.  the swap provided the HW mb(). */
57                 cmb();
58                 /* no internal HW mb */
59                 atomic_set(&tracker->need_to_run, FALSE);
60                 /* run the actual function.  the poke sync makes sure only one
61                  * caller is in that func at a time. */
62                 assert(tracker->func);
63                 tracker->func(arg);
64                 /* ensure the in_prog write comes after the run_again. */
65                 wmb();
66                 /* no internal HW mb */
67                 atomic_set(&tracker->run_in_progress, FALSE);
68                 /* in_prog write must come before run_again read */
69                 wrmb();
70         } while (atomic_read(&tracker->need_to_run));
71 }