Kernel message parameters are now longs
[akaros.git] / kern / src / kthread.c
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Kernel threading.  These are for blocking within the kernel for whatever
6  * reason, usually during blocking IO operations. */
7
8 #include <kthread.h>
9 #include <slab.h>
10 #include <page_alloc.h>
11 #include <pmap.h>
12 #include <smp.h>
13 #include <schedule.h>
14
15 struct kmem_cache *kthread_kcache;
16
17 void kthread_init(void)
18 {
19         kthread_kcache = kmem_cache_create("kthread", sizeof(struct kthread),
20                                            __alignof__(struct kthread), 0, 0, 0);
21 }
22
23 /* This downs the semaphore and suspends the current kernel context on its
24  * waitqueue if there are no pending signals.  Note that the case where the
25  * signal is already there is not optimized. */
26 void sleep_on(struct semaphore *sem)
27 {
28         volatile bool blocking = TRUE;  /* signal to short circuit when restarting*/
29         struct kthread *kthread;
30         struct page *page;                              /* assumption here that stacks are PGSIZE */
31         register uintptr_t new_stacktop;
32         int8_t irq_state = 0;
33         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
34
35         /* interrups would be messy here */
36         disable_irqsave(&irq_state);
37         /* Try to down the semaphore.  If there is a signal there, we can skip all
38          * of the sleep prep and just return. */
39         spin_lock(&sem->lock);  /* no need for irqsave, since we disabled ints */
40         if (sem->nr_signals > 0) {
41                 sem->nr_signals--;
42                 spin_unlock(&sem->lock);
43                 goto block_return_path_np;
44         }
45         /* we're probably going to sleep, so get ready.  We'll check again later. */
46         spin_unlock(&sem->lock);
47         /* Try to get the spare first.  If there is one, we'll use it (o/w, we'll
48          * get a fresh kthread.  Why we need this is more clear when we try to
49          * restart kthreads.  Having them also ought to cut down on contention.
50          * Note we do this with interrupts disabled (which protects us from
51          * concurrent modifications). */
52         if (pcpui->spare) {
53                 kthread = pcpui->spare;
54                 /* we're using the spare, so we use the page the spare held */
55                 new_stacktop = kthread->stacktop;
56                 pcpui->spare = 0;
57         } else {
58                 kthread = kmem_cache_alloc(kthread_kcache, 0);
59                 assert(kthread);
60                 assert(!kpage_alloc(&page));    /* decref'd when the kthread is freed */
61 #ifdef __CONFIG_KTHREAD_POISON__
62                 /* TODO: KTHR-STACK don't poison like this */
63                 *(uintptr_t*)page2kva(page) = 0;
64 #endif /* __CONFIG_KTHREAD_POISON__ */
65                 new_stacktop = (uintptr_t)page2kva(page) + PGSIZE;
66         }
67         /* This is the stacktop we are currently on and wish to save */
68         kthread->stacktop = get_stack_top();
69         /* Set the core's new default stack */
70         set_stack_top(new_stacktop);
71 #ifdef __CONFIG_KTHREAD_POISON__
72         /* Mark the new stack as in-use, and unmark the current kthread */
73         /* TODO: KTHR-STACK don't poison like this */
74         uintptr_t *new_stack_poison, *kth_stack_poison;
75         new_stack_poison = (uintptr_t*)ROUNDDOWN(new_stacktop - 1, PGSIZE);
76         assert(!*new_stack_poison);
77         *new_stack_poison = 0xdeadbeef;
78         kth_stack_poison = (uintptr_t*)ROUNDDOWN(kthread->stacktop - 1, PGSIZE);
79         assert(*kth_stack_poison == 0xdeadbeef);
80         *kth_stack_poison = 0;
81 #endif /* __CONFIG_KTHREAD_POISON__ */
82         /* The kthread needs to stay in the process context (if there is one), but
83          * we want the core (which could be a vcore) to stay in the context too.  If
84          * we want to leave, we'll need to do that in smp_idle() or elsewhere in the
85          * code. */
86         kthread->proc = current;
87         /* kthread tracks the syscall it is working on, which implies errno */
88         kthread->sysc = pcpui->cur_sysc;
89         pcpui->cur_sysc = 0;                            /* this core no longer works on sysc */
90         if (kthread->proc)
91                 proc_incref(kthread->proc, 1);
92         /* Save the context, toggle blocking for the reactivation */
93         save_kernel_tf(&kthread->context);
94         if (!blocking)
95                 goto block_return_path;
96         blocking = FALSE;                                       /* for when it starts back up */
97         /* Down the semaphore.  We need this to be inline.  If we're sleeping, once
98          * we unlock the kthread could be started up again and can return and start
99          * trashing this function's stack, hence the weird control flow. */
100         spin_lock(&sem->lock);  /* no need for irqsave, since we disabled ints */
101         if (sem->nr_signals-- <= 0)
102                 TAILQ_INSERT_TAIL(&sem->waiters, kthread, link);
103         else                                                            /* we didn't sleep */
104                 goto unwind_sleep_prep;
105         spin_unlock(&sem->lock);
106         /* Switch to the core's default stack.  After this, don't use local
107          * variables.  TODO: we shouldn't be using new_stacktop either, can't always
108          * trust the register keyword (AFAIK). */
109         set_stack_pointer(new_stacktop);
110         smp_idle();
111         /* smp_idle never returns */
112         assert(0);
113 unwind_sleep_prep:
114         /* We get here if we should not sleep on sem (the signal beat the sleep).
115          * Note we are not optimizing for cases where the signal won. */
116         spin_unlock(&sem->lock);
117         printd("[kernel] Didn't sleep, unwinding...\n");
118         /* Restore the core's current and default stacktop */
119         current = kthread->proc;                        /* arguably unnecessary */
120         if (kthread->proc)
121                 proc_decref(kthread->proc);
122         set_stack_top(kthread->stacktop);
123         /* Save the allocs as the spare */
124         assert(!pcpui->spare);
125         pcpui->spare = kthread;
126         /* save the "freshly alloc'd" stack/page, not the one we came in on */
127         kthread->stacktop = new_stacktop;
128 #ifdef __CONFIG_KTHREAD_POISON__
129         /* TODO: KTHR-STACK don't unpoison like this */
130         /* switch back to old stack in use, new one not */
131         *new_stack_poison = 0;
132         *kth_stack_poison = 0xdeadbeef;
133 #endif /* __CONFIG_KTHREAD_POISON__ */
134 block_return_path:
135         printd("[kernel] Returning from being 'blocked'! at %llu\n", read_tsc());
136 block_return_path_np:
137         enable_irqsave(&irq_state);
138         return;
139 }
140
141 /* Starts kthread on the calling core.  This does not return, and will handle
142  * the details of cleaning up whatever is currently running (freeing its stack,
143  * etc). */
144 void restart_kthread(struct kthread *kthread)
145 {
146         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
147         uintptr_t current_stacktop;
148         /* Avoid messy complications.  The kthread will enable_irqsave() when it
149          * comes back up. */
150         disable_irq();
151         /* Free any spare, since we need ours to become the spare (since we can't
152          * free our current kthread *before* popping it, nor can we free the current
153          * stack until we pop to the kthread's stack). */
154         if (pcpui->spare) {
155                 /* assumes the stack is a page, and that stacktop is somewhere in
156                  * (pg_bottom, pg_bottom + PGSIZE].  Normally, it ought to be pg_bottom
157                  * + PGSIZE (on x86).  kva2page can take any kva, not just a page
158                  * aligned addr. */
159                 page_decref(kva2page((void*)pcpui->spare->stacktop - 1));
160                 kmem_cache_free(kthread_kcache, pcpui->spare);
161         }
162         current_stacktop = get_stack_top();
163         /* When a kthread runs, its stack is the default kernel stack */
164         set_stack_top(kthread->stacktop);
165 #ifdef __CONFIG_KTHREAD_POISON__
166         /* TODO: KTHR-STACK */
167         /* Assert and switch to cur stack not in use, kthr stack in use */
168         uintptr_t *cur_stack_poison, *kth_stack_poison;
169         cur_stack_poison = (uintptr_t*)ROUNDDOWN(current_stacktop - 1, PGSIZE);
170         assert(*cur_stack_poison == 0xdeadbeef);
171         *cur_stack_poison = 0;
172         kth_stack_poison = (uintptr_t*)ROUNDDOWN(kthread->stacktop - 1, PGSIZE);
173         assert(!*kth_stack_poison);
174         *kth_stack_poison = 0xdeadbeef;
175 #endif /* __CONFIG_KTHREAD_POISON__ */
176         /* Set the spare stuff (current kthread, current (not kthread) stacktop) */
177         pcpui->spare = kthread;
178         kthread->stacktop = current_stacktop;
179         if (current) {
180                 /* __launch_kthread() should have abandoned if it was diff */
181                 assert(current == kthread->proc);
182                 /* no longer need this ref, current holds it */
183                 proc_decref(kthread->proc);
184         } else {
185                 /* ref gets transfered (or it was 0 (no ref held)) */
186                 current = kthread->proc;
187                 if (kthread->proc)
188                         lcr3(kthread->proc->env_cr3);
189         }
190         /* Tell the core which syscall we are running (if any) */
191         assert(!pcpui->cur_sysc);       /* catch bugs, prev user should clear */
192         pcpui->cur_sysc = kthread->sysc;
193         /* Finally, restart our thread */
194         pop_kernel_tf(&kthread->context);
195 }
196
197 /* Call this when a kthread becomes runnable/unblocked.  We don't do anything
198  * particularly smart yet, but when we do, we can put it here. */
199 void kthread_runnable(struct kthread *kthread)
200 {
201         uint32_t dst = core_id();
202         #if 0
203         /* turn this block on if you want to test migrating non-core0 kthreads */
204         switch (dst) {
205                 case 0:
206                         break;
207                 case 7:
208                         dst = 2;
209                         break;
210                 default:
211                         dst++;
212         }
213         #endif
214         /* For lack of anything better, send it to ourselves. (TODO: KSCHED) */
215         send_kernel_message(dst, __launch_kthread, (long)kthread, 0, 0,
216                             KMSG_ROUTINE);
217 }
218
219 /* Kmsg handler to launch/run a kthread.  This must be a routine message, since
220  * it does not return.  Furthermore, like all routine kmsgs that don't return,
221  * this needs to handle the fact that it won't return to the given TF (which is
222  * a proc's TF, since this was routine). */
223 void __launch_kthread(struct trapframe *tf, uint32_t srcid, long a0, long a1,
224                           long a2)
225 {
226         struct kthread *kthread = (struct kthread*)a0;
227         struct proc *cur_proc = current;
228         /* If there is no proc running, don't worry about not returning. */
229         if (cur_proc) {
230                 /* If we're dying, we have a message incoming that we need to deal with,
231                  * so we send this message to ourselves (at the end of the queue).  This
232                  * is a bit ghetto, and a lot of this will need work. */
233                 if (cur_proc->state == PROC_DYING) {
234                         /* We could fake it and send it manually, but this is fine */
235                         send_kernel_message(core_id(), __launch_kthread, (long)kthread,
236                                             0, 0, KMSG_ROUTINE);
237                         return;
238                 }
239                 /* TODO: this whole area needs serious work */
240                 if (cur_proc != kthread->proc) {
241                         /* we're running the kthread from a different proc.  For now, we
242                          * can't be _M, since that would be taking away someone's vcore to
243                          * process another process's work. */
244                         /* Keep in mind this can happen if you yield your core after
245                          * submitting work (like sys_block()) that will complete on the
246                          * current core, and then someone else gets it.
247                          * TODO: This can also happen if we started running another _M
248                          * here... */
249                         if (cur_proc->state != PROC_RUNNING_S) {
250                                 printk("cur_proc: %08p, kthread->proc: %08p\n", cur_proc,
251                                        kthread->proc);
252                         }
253                         assert(cur_proc->state == PROC_RUNNING_S);
254                         spin_lock(&cur_proc->proc_lock);
255                         /* Wrap up / yield the current _S proc, which calls schedule_proc */
256                         __proc_yield_s(cur_proc, tf);
257                         spin_unlock(&cur_proc->proc_lock);
258                         abandon_core();
259                 } else {
260                         /* possible to get here if there is only one _S proc that blocked */
261                         //assert(cur_proc->state == PROC_RUNNING_M);
262                         /* Our proc was current, but also wants an old kthread restarted.
263                          * This could happen if we are in the kernel servicing a call, and a
264                          * kthread tries to get restarted here on the way out.  cur_tf ought
265                          * to be the TF that needs to be restarted when the kernel is done
266                          * (regardless of whether or not we rerun kthreads). */
267                         assert(tf == current_tf);
268                         /* And just let the kthread restart, abandoning the call path via
269                          * proc_restartcore (or however we got here). */
270                 }
271         }
272         restart_kthread(kthread);
273         assert(0);
274 }