Fixes up syscall_blockon functions (XCC)
[akaros.git] / user / parlib / thread0_sched.c
1 /* Copyright (c) 2015 Google, Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * thread0_sched: a basic scheduler for thread0, used by SCPs without a
6  * multithreaded 2LS linked in.
7  *
8  * This is closely coupled with uthread.c */
9
10 #include <ros/arch/membar.h>
11 #include <parlib/arch/atomic.h>
12 #include <parlib/parlib.h>
13 #include <parlib/vcore.h>
14 #include <parlib/uthread.h>
15 #include <parlib/event.h>
16 #include <stdlib.h>
17
18 static void thread0_sched_entry(void);
19 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *sysc);
20
21 /* externed into uthread.c */
22 struct schedule_ops thread0_2ls_ops = {
23         .sched_entry = thread0_sched_entry,
24         .thread_blockon_sysc = thread0_thread_blockon_sysc,
25 };
26
27 /* externed into uthread.c */
28 struct uthread *thread0_uth;
29
30 /* Thread0 scheduler ops (for processes that haven't linked in a full 2LS) */
31 static void thread0_sched_entry(void)
32 {
33         if (current_uthread)
34                 run_current_uthread();
35         else
36                 run_uthread(thread0_uth);
37 }
38
39 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
40 {
41         struct syscall *sysc = (struct syscall*)arg;
42         /* We're in vcore context.  Regardless of what we do here, we'll pop back in
43          * to vcore entry, just like with any uthread_yield.  We don't have a 2LS,
44          * but we always have one uthread: the SCP's thread0.  Note that at this
45          * point, current_uthread is still set, but will be cleared as soon as the
46          * callback returns (and before we start over in vcore_entry).
47          *
48          * If notif_pending is already set (due to a concurrent signal), we'll fail
49          * to yield.  Once in VC ctx, we'll handle any other signals/events that
50          * arrived, then restart the uthread that issued the syscall, which if the
51          * syscall isn't done yet, will just blockon again.
52          *
53          * The one trick is that we don't want to register the evq twice.  The way
54          * register_evq currently works, if a SC completed (SC_DONE) while we were
55          * registering, we could end up clearing sysc->ev_q before the kernel sees
56          * it.  We'll use u_data to track whether we registered or not. */
57         #define U_DATA_BLOB ((void*)0x55555555)
58         if ((sysc->u_data == U_DATA_BLOB)
59             || register_evq(sysc, &__ros_scp_simple_evq)) {
60                 sysc->u_data = U_DATA_BLOB;
61                 /* Sending false for now - we want to signal proc code that we want to
62                  * wait (piggybacking on the MCP meaning of this variable).  If
63                  * notif_pending is set, the kernel will immediately return us. */
64                 __ros_syscall_noerrno(SYS_yield, FALSE, 0, 0, 0, 0, 0);
65         }
66 }