Split PROC_DYING into DYING and DYING_ABORT
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 31 Jul 2016 20:38:01 +0000 (16:38 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 1 Aug 2016 18:57:11 +0000 (11:57 -0700)
This commit just splits out the state into two different states, but
does not differentiate between them yet.  Everywhere that was checking
DYING before now checks DYING and DYING_ABORT equally.

We will need this split to deal with issues closing FDs when processes
are DYING.  In short, if the chan release methods attempt to block on a
rendez, the syscalls will abort immediately, since DYING is set.

We DYING_ABORT is a DYING state, but specifically one where we want all
syscalls to abort.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
Documentation/processes.txt
kern/include/process.h
kern/src/arsc.c
kern/src/event.c
kern/src/mm.c
kern/src/process.c
kern/src/schedule.c
kern/src/syscall.c

index a843890..43335ed 100644 (file)
@@ -112,6 +112,7 @@ PROC_RUNNABLE_S
 PROC_RUNNING_S
 PROC_WAITING
 PROC_DYING
+PROC_DYING_ABORT
 PROC_RUNNABLE_M
 PROC_RUNNING_M
 
index 6c2537e..1ccab3b 100644 (file)
  *   a while.  Possibly even using its local APIC timer.
  * - A process in an _M state will be informed about changes to its state, e.g.,
  *   will have a handler run in the event of a page fault
+ *
+ * DYING vs. DYING_ABORT:
+ * - DYING is the initial stage when a process is dying, but before all of its
+ * syscalls should abort.  At this point, we start closing FDs and blocking
+ * certain new operations.
+ * - DYING_ABORT is after all FDs were closed and all outstanding syscalls are
+ * aborted.
  */
 
 #define PROC_CREATED                   0x01
 #define PROC_RUNNING_S                 0x04
 #define PROC_WAITING                   0x08 // can split out to INT and UINT
 #define PROC_DYING                             0x10
-#define PROC_RUNNABLE_M                        0x20
-#define PROC_RUNNING_M                 0x40
-
-#define procstate2str(state) ((state)==PROC_CREATED    ? "CREATED"    : \
-                              (state)==PROC_RUNNABLE_S ? "RUNNABLE_S" : \
-                              (state)==PROC_RUNNING_S  ? "RUNNING_S"  : \
-                              (state)==PROC_WAITING    ? "WAITING"    : \
-                              (state)==PROC_DYING      ? "DYING"      : \
-                              (state)==PROC_RUNNABLE_M ? "RUNNABLE_M" : \
-                              (state)==PROC_RUNNING_M  ? "RUNNING_M"  : \
-                                                         "UNKNOWN")
+#define PROC_DYING_ABORT               0x20
+#define PROC_RUNNABLE_M                        0x40
+#define PROC_RUNNING_M                 0x80
+
+#define procstate2str(state) ((state) == PROC_CREATED     ? "CREATED"     : \
+                              (state) == PROC_RUNNABLE_S  ? "RUNNABLE_S"  : \
+                              (state) == PROC_RUNNING_S   ? "RUNNING_S"   : \
+                              (state) == PROC_WAITING     ? "WAITING"     : \
+                              (state) == PROC_DYING       ? "DYING"       : \
+                              (state) == PROC_DYING_ABORT ? "DYING_ABORT" : \
+                              (state) == PROC_RUNNABLE_M  ? "RUNNABLE_M"  : \
+                              (state) == PROC_RUNNING_M   ? "RUNNING_M"   : \
+                                                            "UNKNOWN")
 
 #define DEFAULT_PROGNAME ""
 
 #include <env.h>
 
+static bool proc_is_dying(struct proc *p)
+{
+       return (p->state == PROC_DYING) || (p->state == PROC_DYING_ABORT);
+}
+
 struct process_set {
        size_t num_processes;
        size_t size;
index 85ea128..d2f0b1c 100644 (file)
@@ -67,7 +67,7 @@ void arsc_server(uint32_t srcid, long a0, long a1, long a2)
                        /* Probably want to try to process a dying process's syscalls.  If
                         * not, just move it to an else case */
                        process_generic_syscalls (p, MAX_ASRC_BATCH);
-                       if (p->state == PROC_DYING) {
+                       if (proc_is_dying(p)) {
                                TAILQ_REMOVE(&arsc_proc_list, p, proc_arsc_link);
                                proc_decref(p);
                                /* Need to break out, so the TAILQ_FOREACH doesn't flip out.
index 5386b9c..ed5fe39 100644 (file)
@@ -367,7 +367,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
 
        assert(!in_irq_ctx(&per_cpu_info[core_id()]));
        assert(p);
-       if (p->state == PROC_DYING)
+       if (proc_is_dying(p))
                return;
        printd("[kernel] sending msg to proc %p, ev_q %p\n", p, ev_q);
        if (!ev_q) {
index 80c0d7e..1202f0f 100644 (file)
@@ -951,6 +951,7 @@ static int __hpf_load_page(struct proc *p, struct page_map *pm,
                        spin_unlock(&p->proc_lock);
                        return -EAGAIN; /* will get reflected back to userspace */
                case (PROC_DYING):
+               case (PROC_DYING_ABORT):
                        spin_unlock(&p->proc_lock);
                        return -EINVAL;
                default:
index 22b26e7..ce190ce 100644 (file)
@@ -128,6 +128,7 @@ int __proc_set_state(struct proc *p, uint32_t state)
         * RGM -> RBS
         * RGS -> D
         * RGM -> D
+        * D   -> DA
         *
         * These ought to be implemented later (allowed, not thought through yet).
         * RBS -> D
@@ -154,9 +155,12 @@ int __proc_set_state(struct proc *p, uint32_t state)
                                panic("Invalid State Transition! PROC_WAITING to %02x", state);
                        break;
                case PROC_DYING:
-                       if (state != PROC_CREATED) // when it is reused (TODO)
+                       if (state != PROC_DYING_ABORT)
                                panic("Invalid State Transition! PROC_DYING to %02x", state);
                        break;
+               case PROC_DYING_ABORT:
+                       panic("Invalid State Transition! PROC_DYING to %02x", state);
+                       break;
                case PROC_RUNNABLE_M:
                        if (!(state & (PROC_RUNNING_M | PROC_DYING)))
                                panic("Invalid State Transition! PROC_RUNNABLE_M to %02x", state);
@@ -589,6 +593,7 @@ void proc_run_s(struct proc *p)
        spin_lock(&p->proc_lock);
        switch (p->state) {
                case (PROC_DYING):
+               case (PROC_DYING_ABORT):
                        spin_unlock(&p->proc_lock);
                        printk("[kernel] _S %d not starting due to async death\n", p->pid);
                        return;
@@ -691,6 +696,7 @@ void __proc_run_m(struct proc *p)
        switch (p->state) {
                case (PROC_WAITING):
                case (PROC_DYING):
+               case (PROC_DYING_ABORT):
                        warn("ksched tried to run proc %d in state %s\n", p->pid,
                             procstate2str(p->state));
                        return;
@@ -816,6 +822,7 @@ void proc_destroy(struct proc *p)
        uint32_t pc_arr[p->procinfo->num_vcores];
        switch (p->state) {
                case PROC_DYING: /* someone else killed this already. */
+               case (PROC_DYING_ABORT):
                        spin_unlock(&p->proc_lock);
                        return;
                case PROC_CREATED:
@@ -976,6 +983,7 @@ int proc_change_to_m(struct proc *p)
                        warn("Not supporting RUNNABLE_S -> RUNNABLE_M yet.\n");
                        goto error_out;
                case (PROC_DYING):
+               case (PROC_DYING_ABORT):
                        warn("Dying, core request coming from %d\n", core_id());
                        goto error_out;
                default:
@@ -1162,6 +1170,7 @@ void proc_yield(struct proc *p, bool being_nice)
                case (PROC_RUNNING_M):
                        break;                          /* will handle this stuff below */
                case (PROC_DYING):              /* incoming __death */
+               case (PROC_DYING_ABORT):
                case (PROC_RUNNABLE_M): /* incoming (bulk) preempt/myield TODO:(BULK) */
                        goto out_failed;
                default:
@@ -1329,6 +1338,7 @@ void proc_wakeup(struct proc *p)
                        case (PROC_RUNNABLE_S):
                        case (PROC_RUNNING_S):
                        case (PROC_DYING):
+                       case (PROC_DYING_ABORT):
                                spin_unlock(&p->proc_lock);
                                return;
                        case (PROC_RUNNABLE_M):
@@ -1618,6 +1628,7 @@ int __proc_give_cores(struct proc *p, uint32_t *pc_arr, uint32_t num)
                        warn("Don't give cores to a process in a *_S state!\n");
                        return -1;
                case (PROC_DYING):
+               case (PROC_DYING_ABORT):
                case (PROC_WAITING):
                        /* can't accept, just fail */
                        return -1;
@@ -1990,6 +2001,7 @@ int proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
                        break;                          /* the only case we can proceed */
                case (PROC_RUNNING_S):  /* user bug, just return */
                case (PROC_DYING):              /* incoming __death */
+               case (PROC_DYING_ABORT):
                case (PROC_RUNNABLE_M): /* incoming (bulk) preempt/myield TODO:(BULK) */
                        goto out_locked;
                default:
index aeceb1b..7590dcd 100644 (file)
@@ -159,7 +159,7 @@ static void remove_from_any_list(struct proc *p)
  *   DYING */
 void __sched_proc_register(struct proc *p)
 {
-       assert(p->state != PROC_DYING); /* shouldn't be abel to happen yet */
+       assert(!proc_is_dying(p));              /* shouldn't be able to happen yet */
        /* one ref for the proc's existence, cradle-to-grave */
        proc_incref(p, 1);      /* need at least this OR the 'one for existing' */
        spin_lock(&sched_lock);
@@ -175,7 +175,7 @@ void __sched_proc_change_to_m(struct proc *p)
        /* Need to make sure they aren't dying.  if so, we already dealt with their
         * list membership, etc (or soon will).  taking advantage of the 'immutable
         * state' of dying (so long as refs are held). */
-       if (p->state == PROC_DYING) {
+       if (proc_is_dying(p)) {
                spin_unlock(&sched_lock);
                return;
        }
@@ -219,7 +219,7 @@ void __sched_proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t nr_cores)
 void __sched_mcp_wakeup(struct proc *p)
 {
        spin_lock(&sched_lock);
-       if (p->state == PROC_DYING) {
+       if (proc_is_dying(p)) {
                spin_unlock(&sched_lock);
                return;
        }
@@ -233,7 +233,7 @@ void __sched_mcp_wakeup(struct proc *p)
 void __sched_scp_wakeup(struct proc *p)
 {
        spin_lock(&sched_lock);
-       if (p->state == PROC_DYING) {
+       if (proc_is_dying(p)) {
                spin_unlock(&sched_lock);
                return;
        }
@@ -298,7 +298,7 @@ static bool __schedule_scp(void)
                        spin_lock(&pcpui->owning_proc->proc_lock);
                        /* process might be dying, with a KMSG to clean it up waiting on
                         * this core.  can't do much, so we'll attempt to restart */
-                       if (pcpui->owning_proc->state == PROC_DYING) {
+                       if (proc_is_dying(pcpui->owning_proc)) {
                                send_kernel_message(core_id(), __just_sched, 0, 0, 0,
                                                    KMSG_ROUTINE);
                                spin_unlock(&pcpui->owning_proc->proc_lock);
@@ -418,7 +418,7 @@ static void __run_mcp_ksched(void *arg)
                         * DYING, it'll remain DYING until we decref.  And if there is a
                         * concurrent death, that will spin on the ksched lock (which we
                         * hold, and which protects the proc lists). */
-                       if (p->state != PROC_DYING)
+                       if (proc_is_dying(p))
                                add_to_list(p, secondary_mcps);
                        proc_decref(p);                 /* fyi, this may trigger __proc_free */
                        /* need to break: the proc lists may have changed when we unlocked
index 43ce692..593dfee 100644 (file)
@@ -1068,7 +1068,7 @@ all_out:
 static pid_t try_wait(struct proc *parent, struct proc *child, int *ret_status,
                       int options)
 {
-       if (child->state == PROC_DYING) {
+       if (proc_is_dying(child)) {
                /* Disown returns -1 if it's already been disowned or we should o/w
                 * abort.  This can happen if we have concurrent waiters, both with
                 * pointers to the child (only one should reap).  Note that if we don't
@@ -1130,7 +1130,7 @@ static pid_t wait_one(struct proc *parent, struct proc *child, int *ret_status,
                /* If we're dying, then we don't need to worry about waiting.  We don't
                 * do this yet, but we'll need this outlet when we deal with orphaned
                 * children and having init inherit them. */
-               if (parent->state == PROC_DYING)
+               if (proc_is_dying(parent))
                        goto out_unlock;
                /* Any child can wake us up, but we check for the particular child we
                 * care about */
@@ -1160,7 +1160,7 @@ static pid_t wait_any(struct proc *parent, int *ret_status, int options)
        while (!retval) {
                cpu_relax();
                cv_wait(&parent->child_wait);
-               if (parent->state == PROC_DYING)
+               if (proc_is_dying(parent))
                        goto out_unlock;
                /* Any child can wake us up from the CV.  This is a linear try_wait
                 * scan.  If we have a lot of children, we could optimize this. */