Fix a deadlock bug in MCS-PDR locks
[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 static void thread0_thread_refl_fault(struct uthread *uthread,
21                                       unsigned int trap_nr, unsigned int err,
22                                       unsigned long aux);
23 static void thread0_thread_runnable(struct uthread *uth);
24 static void thread0_thread_has_blocked(struct uthread *uth, int flags);
25
26 /* externed into uthread.c */
27 struct schedule_ops thread0_2ls_ops = {
28         .sched_entry = thread0_sched_entry,
29         .thread_blockon_sysc = thread0_thread_blockon_sysc,
30         .thread_refl_fault = thread0_thread_refl_fault,
31         .thread_runnable = thread0_thread_runnable,
32         .thread_paused = thread0_thread_runnable,
33         .thread_has_blocked = thread0_thread_has_blocked,
34 };
35
36 /* externed into uthread.c */
37 struct uthread *thread0_uth;
38
39 /* Our thread0 is actually allocated in uthread as just a struct uthread, so we
40  * don't actually attach this mgmt info to it.  But since we just have one
41  * thread, it doesn't matter. */
42 struct thread0_info {
43         bool                                            is_blocked;
44 };
45 static struct thread0_info thread0_info;
46 static struct event_queue *sysc_evq;
47
48 static void thread0_handle_syscall(struct event_msg *ev_msg,
49                                    unsigned int ev_type, void *data)
50 {
51         thread0_info.is_blocked = FALSE;
52 }
53
54 void thread0_lib_init(void)
55 {
56         memset(&thread0_info, 0, sizeof(thread0_info));
57         /* we don't care about the message, so don't bother with a UCQ */
58         sysc_evq = get_eventq(EV_MBOX_BITMAP);
59         sysc_evq->ev_flags = EVENT_INDIR | EVENT_WAKEUP;
60         register_ev_handler(EV_SYSCALL, thread0_handle_syscall, 0);
61 }
62
63 /* Thread0 scheduler ops (for processes that haven't linked in a full 2LS) */
64 static void thread0_sched_entry(void)
65 {
66         /* TODO: support signal handling whenever we run a uthread */
67         if (current_uthread) {
68                 uthread_prep_pending_signals(current_uthread);
69                 run_current_uthread();
70                 assert(0);
71         }
72         while (1) {
73                 if (!thread0_info.is_blocked) {
74                         uthread_prep_pending_signals(thread0_uth);
75                         run_uthread(thread0_uth);
76                         assert(0);
77                 }
78                 sys_yield(FALSE);
79                 handle_events(0);
80         }
81 }
82
83 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
84 {
85         struct syscall *sysc = (struct syscall*)arg;
86         thread0_thread_has_blocked(uthread, 0);
87         if (!register_evq(sysc, sysc_evq))
88                 thread0_thread_runnable(uthread);
89 }
90
91 static void thread0_thread_refl_fault(struct uthread *uthread,
92                                       unsigned int trap_nr, unsigned int err,
93                                       unsigned long aux)
94 {
95         printf("SCP has unhandled fault: %d, err: %d, aux: %p\n", trap_nr, err,
96                aux);
97         print_user_context(&uthread->u_ctx);
98         printf("Turn on printx to spew unhandled, malignant trap info\n");
99         exit(-1);
100 }
101
102 static void thread0_thread_runnable(struct uthread *uth)
103 {
104         thread0_info.is_blocked = FALSE;
105 }
106
107 static void thread0_thread_has_blocked(struct uthread *uth, int flags)
108 {
109         thread0_info.is_blocked = TRUE;
110 }