diff --git a/src/api/thread.c b/src/api/thread.c index bca194e..f39aa39 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -60,72 +60,15 @@ static inline int TASK_IS_CHILD(struct ktcb *task) ((task)->pagerid == current->tid)); } -int thread_delete_children(void) +int thread_destroy_child(struct ktcb *task) { - struct ktcb *task, *n; - - spin_lock(&curcont->ktcb_list.list_lock); - list_foreach_removable_struct(task, n, - &curcont->ktcb_list.list, - task_list) { - if (TASK_IS_CHILD(task)) { - spin_unlock(&curcont->ktcb_list.list_lock); - tcb_remove(task); - wake_up_all(¤t->wqh_send, 0); - wake_up_all(¤t->wqh_recv, 0); - BUG_ON(task->wqh_pager.sleepers > 0); - BUG_ON(task->state != TASK_INACTIVE); - tcb_delete(task); - spin_lock(&curcont->ktcb_list.list_lock); - } - } - spin_unlock(&curcont->ktcb_list.list_lock); - return 0; -} - -int thread_suspend_children(void) -{ - struct ktcb *task, *n; - - spin_lock(&curcont->ktcb_list.list_lock); - list_foreach_removable_struct(task, n, - &curcont->ktcb_list.list, - task_list) { - if (TASK_IS_CHILD(task)) { - spin_unlock(&curcont->ktcb_list.list_lock); - thread_suspend(task); - spin_lock(&curcont->ktcb_list.list_lock); - } - } - spin_unlock(&curcont->ktcb_list.list_lock); - return 0; - -} - -/* - * Put them in TASK_DEAD so that a suspended exiting thread - * does not run again if issued THREAD_RUN - */ -int thread_destroy(struct ktcb *task) -{ - if (task == current) { - if (current->tid == current->pagerid) { - /* Suspend children */ - thread_suspend_children(); - thread_delete_children(); - sched_exit_pager(); - } else { - sched_suspend_sync(); - } - return 0; - } thread_suspend(task); tcb_remove(task); /* Wake up waiters */ - wake_up_all(&task->wqh_send, 0); - wake_up_all(&task->wqh_recv, 0); + wake_up_all(&task->wqh_send, WAKEUP_INTERRUPT); + wake_up_all(&task->wqh_recv, WAKEUP_INTERRUPT); BUG_ON(task->wqh_pager.sleepers > 0); BUG_ON(task->state != TASK_INACTIVE); @@ -134,6 +77,41 @@ int thread_destroy(struct ktcb *task) return 0; } +int thread_destroy_children(void) +{ + struct ktcb *task, *n; + + spin_lock(&curcont->ktcb_list.list_lock); + list_foreach_removable_struct(task, n, + &curcont->ktcb_list.list, + task_list) { + if (TASK_IS_CHILD(task)) { + spin_unlock(&curcont->ktcb_list.list_lock); + thread_destroy_child(task); + spin_lock(&curcont->ktcb_list.list_lock); + } + } + spin_unlock(&curcont->ktcb_list.list_lock); + return 0; + +} + +void thread_destroy_self() +{ + thread_destroy_children(); + + sched_suspend_sync(); +} + +int thread_destroy(struct ktcb *task) +{ + if (TASK_IS_CHILD(task)) + return thread_destroy_child(task); + else if (task == current) + thread_destroy_self(); + return 0; +} + int arch_clear_thread(struct ktcb *tcb) { /* Remove from the global list */ diff --git a/src/arch/arm/exception.c b/src/arch/arm/exception.c index fa88618..03e95b2 100644 --- a/src/arch/arm/exception.c +++ b/src/arch/arm/exception.c @@ -62,7 +62,7 @@ void ipc_restore_state(struct ipc_state *state) } /* Send data fault ipc to the faulty task's pager */ -void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) +int fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) { int err; @@ -119,15 +119,24 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) /* Send ipc to the task's pager */ if ((err = ipc_sendrecv(current->pagerid, current->pagerid, 0)) < 0) { - printk("Thread (%d) faulted in kernel and its pager " - "returned error (%d). Suspend and exiting thread.\n", - current->tid, err); - BUG_ON(current->nlocks); + BUG_ON(current->nlocks); - /* Exit as if signalled */ - current->flags |= TASK_EXITING; - sched_exit_sync(); + /* Return on interrupt */ + if (err == -EINTR) { + printk("Thread (%d) page-faulted " + "and got interrupted by its pager.\n", + current->tid); + return err; + } else { /* Suspend on any other error */ + printk("Thread (%d) faulted in kernel " + "and an error occured during " + "page-fault ipc. err=%d. Suspending task.\n", + current->tid, err); + current->flags |= TASK_SUSPENDING; + sched_suspend_sync(); + } } + return 0; } /* @@ -141,6 +150,7 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far) int pager_pagein_request(unsigned long addr, unsigned long size, unsigned int flags) { + int err; u32 abort = 0; unsigned long npages = __pfn(align_up(size, PAGE_SIZE)); struct ipc_state ipc_state; @@ -154,7 +164,9 @@ int pager_pagein_request(unsigned long addr, unsigned long size, /* For every page to be used by the kernel send a page-in request */ for (int i = 0; i < npages; i++) - fault_ipc_to_pager(0, abort, addr + (i * PAGE_SIZE)); + if ((err = fault_ipc_to_pager(0, abort, + addr + (i * PAGE_SIZE))) < 0) + return err; /* Restore ipc state */ ipc_restore_state(&ipc_state); @@ -266,6 +278,11 @@ void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far) /* This notifies the pager */ fault_ipc_to_pager(faulted_pc, fsr, far); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } return; error: @@ -290,6 +307,11 @@ void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 lr) if (KERN_ADDR(lr)) goto error; fault_ipc_to_pager(faulted_pc, fsr, far); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } return; error: diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index 2999e46..0997a3a 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -225,68 +225,6 @@ void sched_resume_async(struct ktcb *task) RQ_ADD_FRONT); } -/* - * A self-paging thread deletes itself, - * schedules and disappears from the system. - */ -void sched_exit_pager(void) -{ - // printk("Pager (%d) Exiting...\n", current->tid); - /* Remove from its list, callers get -ESRCH */ - tcb_remove(current); - - /* - * If there are any sleepers on any of the task's - * waitqueues, we need to wake those tasks up. - */ - wake_up_all(¤t->wqh_send, 0); - wake_up_all(¤t->wqh_recv, 0); - - /* - * We're a self-paging thread. We're gonna - * delete ourself and disappear from the - * system as soon as we schedule - */ - preempt_disable(); - - /* - * FIXME: TOO LONG! - */ - tcb_delete(current); - - sched_rq_remove_task(current); - current->state = TASK_INACTIVE; - scheduler.prio_total -= current->priority; - BUG_ON(scheduler.prio_total < 0); - - /* As soon as we schedule, we're gone */ - preempt_enable(); - schedule(); - BUG(); -} - -void sched_exit_sync(void) -{ - struct ktcb *pager = tcb_find(current->pagerid); - - /* Go to exit list */ - ktcb_list_add(current, &pager->child_exit_list); - - preempt_disable(); - - /* Hint pager we're ready */ - wake_up(¤t->wqh_pager, 0); - - sched_rq_remove_task(current); - current->state = TASK_DEAD; - current->flags &= ~TASK_EXITING; - preempt_enable(); - - /* Quit */ - schedule(); - BUG(); -} - /* * NOTE: Could do these as sched_prepare_suspend() * + schedule() or need_resched = 1 diff --git a/src/glue/arm/systable.c b/src/glue/arm/systable.c index 542251d..83a61ce 100644 --- a/src/glue/arm/systable.c +++ b/src/glue/arm/systable.c @@ -170,9 +170,6 @@ int syscall(syscall_context_t *regs, unsigned long swi_addr) if (current->flags & TASK_SUSPENDING) { BUG_ON(current->nlocks); sched_suspend_sync(); - } else if (current->flags & TASK_EXITING) { - BUG_ON(current->nlocks); - sched_exit_sync(); } return ret;