Process management via active messages
[akaros.git] / kern / src / process.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  */
6
7 #ifdef __SHARC__
8 #pragma nosharc
9 #endif
10
11 #include <arch/arch.h>
12 #include <process.h>
13 #include <atomic.h>
14 #include <smp.h>
15 #include <pmap.h>
16 #include <schedule.h>
17 #include <manager.h>
18 #include <stdio.h>
19 #include <assert.h>
20 #include <timing.h>
21 #include <sys/queue.h>
22
23 /* Process Lists */
24 struct proc_list proc_freelist = TAILQ_HEAD_INITIALIZER(proc_freelist);
25 spinlock_t freelist_lock = 0;
26 struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
27 spinlock_t runnablelist_lock = 0;
28
29 /*
30  * While this could be done with just an assignment, this gives us the
31  * opportunity to check for bad transitions.  Might compile these out later, so
32  * we shouldn't rely on them for sanity checking from userspace.
33  */
34 int proc_set_state(struct proc *p, uint32_t state)
35 {
36         uint32_t curstate = p->state;
37         /* Valid transitions:
38          * C   -> RBS
39          * RBS -> RGS
40          * RGS -> RBS
41          * RGS -> W
42          * W   -> RBS
43          * RGS -> RBM
44          * RBM -> RGM
45          * RGM -> RBM
46          * RGM -> RBS
47          * RGS -> D
48          * RGM -> D
49          *
50          * These ought to be implemented later (allowed, not thought through yet).
51          * RBS -> D
52          * RBM -> D
53          *
54          * This isn't allowed yet, may be later.
55          * C   -> D
56          */
57         #if 1 // some sort of correctness flag
58         switch (curstate) {
59                 case PROC_CREATED:
60                         if (state != PROC_RUNNABLE_S)
61                                 panic("Invalid State Transition! PROC_CREATED to %d", state);
62                         break;
63                 case PROC_RUNNABLE_S:
64                         if (!(state & (PROC_RUNNING_S | PROC_DYING)))
65                                 panic("Invalid State Transition! PROC_RUNNABLE_S to %d", state);
66                         break;
67                 case PROC_RUNNING_S:
68                         if (!(state & (PROC_RUNNABLE_S | PROC_RUNNABLE_M | PROC_WAITING |
69                                        PROC_DYING)))
70                                 panic("Invalid State Transition! PROC_RUNNING_S to %d", state);
71                         break;
72                 case PROC_WAITING:
73                         if (state != PROC_RUNNABLE_S)
74                                 panic("Invalid State Transition! PROC_WAITING to %d", state);
75                         break;
76                 case PROC_DYING:
77                         if (state != PROC_CREATED) // when it is reused (TODO)
78                                 panic("Invalid State Transition! PROC_DYING to %d", state);
79                         break;
80                 case PROC_RUNNABLE_M:
81                         if (!(state & (PROC_RUNNING_M | PROC_DYING)))
82                                 panic("Invalid State Transition! PROC_RUNNABLE_M to %d", state);
83                         break;
84                 case PROC_RUNNING_M:
85                         if (!(state & (PROC_RUNNABLE_S | PROC_RUNNABLE_M | PROC_DYING)))
86                                 panic("Invalid State Transition! PROC_RUNNING_M to %d", state);
87                         break;
88         }
89         #endif
90         p->state = state;
91         return 0;
92 }
93
94 /* Change this when we aren't using an array */
95 struct proc *get_proc(unsigned pid)
96 {
97         // should have some error checking when we do this for real
98         return &envs[ENVX(pid)];
99 }
100
101 /* Whether or not actor can control target */
102 bool proc_controls(struct proc *actor, struct proc *target)
103 {
104         return target->env_parent_id == actor->env_id;
105 }
106
107 /*
108  * Dispatches a process to run, either on the current core in the case of a
109  * RUNNABLE_S, or on its partition in the case of a RUNNABLE_M.
110  * This should never be called to "restart" a core.
111  */
112 void proc_run(struct proc *p)
113 {
114         spin_lock_irqsave(&p->proc_lock);
115         switch (p->state) {
116                 case (PROC_DYING):
117                         spin_unlock_irqsave(&p->proc_lock);
118                         printk("Process %d not starting due to async death\n", p->env_id);
119                         // There should be no core cleanup to do (like decref).
120                         assert(current != p);
121                         // if we're a worker core, smp_idle, o/w return
122                         if (!management_core())
123                                 smp_idle(); // this never returns
124                         return;
125                 case (PROC_RUNNABLE_S):
126                         proc_set_state(p, PROC_RUNNING_S);
127                         // We will want to know where this process is running, even if it is
128                         // only in RUNNING_S.  can use the vcoremap, which makes death easy.
129                         // we may need the pcoremap entry to mark it as a RUNNING_S core, or
130                         // else update it here. (TODO) (PCORE)
131                         p->num_vcores = 0;
132                         p->vcoremap[0] = core_id();
133                         spin_unlock_irqsave(&p->proc_lock);
134                         // This normally doesn't return, but might error out in the future.
135                         proc_startcore(p, &p->env_tf);
136                         break;
137                 case (PROC_RUNNABLE_M):
138                         proc_set_state(p, PROC_RUNNING_M);
139                         /* vcoremap[i] holds the coreid of the physical core allocated to
140                          * this process.  It is set outside proc_run.  For the active
141                          * message, a0 = struct proc*, a1 = struct trapframe*.   */
142                         if (p->num_vcores) {
143                                 // TODO: handle silly state (HSS)
144                                 // set virtual core 0 to run the main context
145                                 send_active_msg_sync(p->vcoremap[0], __startcore, p,
146                                                      &p->env_tf, 0);
147                                 /* handle the others.  note the sync message will spin until
148                                  * there is a free active message slot, which could lock up the
149                                  * system.  think about this. (TODO) */
150                                 for (int i = 1; i < p->num_vcores; i++)
151                                         send_active_msg_sync(p->vcoremap[i], __startcore, p, 0, 0);
152                         }
153                         /* There a subtle (attempted) race avoidance here.  proc_startcore
154                          * can handle a death message, but we can't have the startcore come
155                          * after the death message.  Otherwise, it would look like a new
156                          * process.  So we hold the lock to make sure our message went out
157                          * before a possible death message.
158                          * - Likewise, we need interrupts to be disabled, in case one of the
159                          *   messages was for us, and reenable them after letting go of the
160                          *   lock.  This is done by spin_lock_irqsave, so be careful if you
161                          *   change this.
162                          * - This can also be done far more intelligently / efficiently,
163                          *   like skipping in case it's busy and coming back later.
164                          * - Note there is no guarantee this core's interrupts were on, so
165                          *   it may not get the message for a while... */
166                         spin_unlock_irqsave(&p->proc_lock);
167                         break;
168                 default:
169                         spin_unlock_irqsave(&p->proc_lock);
170                         panic("Invalid process state in proc_run()!!");
171         }
172 }
173
174 /*
175  * Runs the given context (trapframe) of process p on the core this code
176  * executes on.  The refcnt tracks how many cores have "an interest" in this
177  * process, which so far just means it uses the process's page table.  See the
178  * massive comments around the incref function
179  *
180  * Given we are RUNNING_*, an IPI for death or preemption could come in:
181  * 1. death attempt (IPI to kill whatever is on your core):
182  *              we don't need to worry about protecting the stack, since we're
183  *              abandoning ship - just need to get a good cr3 and decref current, which
184  *              the death handler will do.
185  *              If a death IPI comes in, we immediately stop this function and will
186  *              never come back.
187  * 2. preempt attempt (IPI to package state and maybe run something else):
188  *              - if a preempt attempt comes in while we're in the kernel, it'll
189  *              just set a flag.  we could attempt to bundle the kernel state
190  *              and rerun it later, but it's really messy (and possibly given
191  *              back to userspace).  we'll disable ints, check this flag, and if
192  *              so, handle the preemption using the same funcs as the normal
193  *              preemption handler.  nonblocking kernel calls will just slow
194  *              down the preemption while they work.  blocking kernel calls will
195  *              need to package their state properly anyway.
196  *
197  * TODO: in general, think about when we no longer need the stack, in case we
198  * are preempted and expected to run again from somewhere else.  we can't
199  * expect to have the kernel stack around anymore.  the nice thing about being
200  * at this point is that we are just about ready to give up the stack anyways.
201  *
202  * I think we need to make it such that the kernel in "process context" never
203  * gets removed from the core (displaced from its stack) without going through
204  * some "bundling" code.
205  */
206 void proc_startcore(struct proc *p, trapframe_t *tf) {
207         // it's possible to be DYING, but it's a rare race.
208         //if (p->state & (PROC_RUNNING_S | PROC_RUNNING_M))
209         //      printk("dying before (re)startcore on core %d\n", core_id());
210
211         // sucks to have ints disabled when doing env_decref and possibly freeing
212         disable_irq();
213         if (per_cpu_info[core_id()].preempt_pending) {
214                 // TODO: handle preemption
215                 // the functions will need to consider deal with current like down below
216                 panic("Preemption not supported!");
217         }
218         /* If the process wasn't here, then we need to load its address space. */
219         if (p != current) {
220                 if (proc_incref(p)) {
221                         // getting here would mean someone tried killing this while we tried
222                         // to start one of it's contexts (from scratch, o/w we had it's CR3
223                         // loaded already)
224                         // if this happens, a no-op death-IPI ought to be on its way...  we can
225                         // just smp_idle()
226                         smp_idle();
227                 }
228                 lcr3(p->env_cr3);
229                 // we unloaded the old cr3, so decref it (if it exists)
230                 // TODO: Consider moving this to wherever we really "mean to leave the
231                 // process's context".
232                 if (current)
233                         proc_decref(current);
234                 current = p;
235         }
236         /* need to load our silly state, preferably somewhere other than here so we
237          * can avoid the case where the context was just running here.  it's not
238          * sufficient to do it in the "new process" if-block above (could be things
239          * like page faults that cause us to keep the same process, but want a
240          * different context.
241          * for now, we load this silly state here. (TODO) (HSS)
242          * We also need this to be per trapframe, and not per process...
243          */
244         env_pop_ancillary_state(p);
245         env_pop_tf(tf);
246 }
247
248 /*
249  * Destroys the given process.  This may be called from another process, a light
250  * kernel thread (no real process context), asynchronously/cross-core, or from
251  * the process on its own core.
252  *
253  * Here's the way process death works:
254  * 0. grab the lock (protects state transition and core map)
255  * 1. set state to dying.  that keeps the kernel from doing anything for the
256  * process (like proc_running it).
257  * 2. figure out where the process is running (cross-core/async or RUNNING_M)
258  * 3. IPI to clean up those cores (decref, etc).
259  * 4. Unlock
260  * 5. Clean up your core, if applicable
261  * (Last core/kernel thread to decref cleans up and deallocates resources.)
262  *
263  * Note that some cores can be processing async calls, but will eventually
264  * decref.  Should think about this more.
265  */
266 void proc_destroy(struct proc *p)
267 {
268         // Note this code relies on this lock disabling interrupts, similar to
269         // proc_run.
270         spin_lock_irqsave(&p->proc_lock);
271         switch (p->state) {
272                 case PROC_DYING:
273                         return; // someone else killed this already.
274                 case PROC_RUNNABLE_S:
275                 case PROC_RUNNABLE_M:
276                         // Think about other lists, like WAITING, or better ways to do this
277                         deschedule_proc(p);
278                         break;
279                 case PROC_RUNNING_S:
280                         #if 0
281                         // here's how to do it manually
282                         if (current == p) {
283                                 lcr3(boot_cr3);
284                                 proc_decref(p); // this decref is for the cr3
285                                 current = NULL;
286                         }
287                         #endif
288                         send_active_msg_sync(p->vcoremap[0], __death, 0, 0, 0);
289                         break;
290                 case PROC_RUNNING_M:
291                         /* Send the DEATH message to every core running this process. */
292                         for (int i = 0; i < p->num_vcores; i++)
293                                 send_active_msg_sync(p->vcoremap[i], __death, 0, 0, 0);
294                         /* TODO: might need to update the pcoremap that's currently in
295                          * schedule, though probably not. */
296                         break;
297                 default:
298                         panic("Weird state in proc_destroy");
299         }
300         proc_set_state(p, PROC_DYING);
301
302         atomic_dec(&num_envs);
303         /* TODO: (REF) dirty hack.  decref currently uses a lock, but needs to use
304          * CAS instead (another lock would be slightly less ghetto).  but we need to
305          * decref before releasing the lock, since that could enable interrupts,
306          * which would have us receive the DEATH IPI if this was called locally by
307          * the target process. */
308         //proc_decref(p); // this decref is for the process in general
309         p->env_refcnt--;
310         size_t refcnt = p->env_refcnt; // need to copy this in so it's not reloaded
311
312         /* After unlocking, we can receive a DEATH IPI and clean up */
313         spin_unlock_irqsave(&p->proc_lock);
314
315         // coupled with the refcnt-- above, from decref.  if this happened,
316         // proc_destroy was called "remotely", and with no one else refcnting
317         if (!refcnt)
318                 env_free(p);
319
320         /* If we were running the process, we should have received an IPI by now.
321          * If not, odds are interrupts are disabled, which shouldn't happen while
322          * servicing syscalls. */
323         assert(current != p);
324         return;
325 }
326
327 /*
328  * The process refcnt is the number of places the process 'exists' in the
329  * system.  Creation counts as 1.  Having your page tables loaded somewhere
330  * (lcr3) counts as another 1.  A non-RUNNING_* process should have refcnt at
331  * least 1.  If the kernel is on another core and in a processes address space
332  * (like processing its backring), that counts as another 1.
333  *
334  * Note that the actual loading and unloading of cr3 is up to the caller, since
335  * that's not the only use for this (and decoupling is more flexible).
336  *
337  * The refcnt should always be greater than 0 for processes that aren't dying.
338  * When refcnt is 0, the process is dying and should not allow any more increfs.
339  * A process can be dying with a refcnt greater than 0, since it could be
340  * waiting for other cores to "get the message" to die, or a kernel core can be
341  * finishing work in the processes's address space.
342  *
343  * Implementation aside, the important thing is that we atomically increment
344  * only if it wasn't already 0.  If it was 0, then we shouldn't be attaching to
345  * the process, so we return an error, which should be handled however is
346  * appropriate.  We currently use spinlocks, but some sort of clever atomics
347  * would work too.
348  *
349  * Also, no one should ever update the refcnt outside of these functions.
350  * Eventually, we'll have Ivy support for this. (TODO)
351  *
352  * TODO: (REF) change to use CAS.
353  */
354 error_t proc_incref(struct proc *p)
355 {
356         error_t retval = 0;
357         spin_lock_irqsave(&p->proc_lock);
358         if (p->env_refcnt)
359                 p->env_refcnt++;
360         else
361                 retval = -EBADENV;
362         spin_unlock_irqsave(&p->proc_lock);
363         return retval;
364 }
365
366 /*
367  * When the kernel is done with a process, it decrements its reference count.
368  * When the count hits 0, no one is using it and it should be freed.
369  * "Last one out" actually finalizes the death of the process.  This is tightly
370  * coupled with the previous function (incref)
371  * Be sure to load a different cr3 before calling this!
372  *
373  * TODO: (REF) change to use CAS.  Note that when we do so, we may be holding
374  * the process lock when calling env_free().
375  */
376 void proc_decref(struct proc *p)
377 {
378         spin_lock_irqsave(&p->proc_lock);
379         p->env_refcnt--;
380         size_t refcnt = p->env_refcnt; // need to copy this in so it's not reloaded
381         spin_unlock_irqsave(&p->proc_lock);
382         // if we hit 0, no one else will increment and we can check outside the lock
383         if (!refcnt)
384                 env_free(p);
385 }