mirror of
https://github.com/drasko/codezero.git
synced 2026-01-18 13:53:16 +01:00
exit() almost there.
- Implemented reasonable way to suspend task.
- A task that has a pending suspend would be interrupted
from its sleep via the suspender task.
- If suspend was raised and right after, task became about to sleep,
then scheduler wakes it up.
- If suspend was raised when task was in user mode, then an irq suspends it.
- Also suspends are checked at the end of a syscall so that if suspend was
raised because of a syscall from the task, the task is suspended before it
goes back to user mode.
- This mechanism is very similar to signals, and it may lead as a base for
implementing signal handling.
- Implemented common vma dropping for shadow vm object dropping and task exiting.
This commit is contained in:
@@ -7,10 +7,11 @@
|
||||
*/
|
||||
#include <l4/config.h>
|
||||
#include <l4/macros.h>
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/generic/platform.h>
|
||||
#include <l4/generic/tcb.h>
|
||||
#include <l4/generic/irq.h>
|
||||
#include <l4/lib/mutex.h>
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/lib/printk.h>
|
||||
#include INC_PLAT(irq.h)
|
||||
#include INC_ARCH(exception.h)
|
||||
@@ -73,5 +74,11 @@ void do_irq(void)
|
||||
printk("Spurious or broken irq\n"); BUG();
|
||||
}
|
||||
irq_enable(irq_index);
|
||||
|
||||
/* Process any pending flags for currently runnable task */
|
||||
task_process_pending_flags();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -228,6 +228,44 @@ static inline int sched_recalc_ticks(struct ktcb *task, int prio_total)
|
||||
SCHED_TICKS * task->priority / prio_total;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Could do these as sched_prepare_suspend()
|
||||
* + schedule() or need_resched = 1
|
||||
*/
|
||||
void sched_suspend_sync(void)
|
||||
{
|
||||
preempt_disable();
|
||||
sched_rq_remove_task(current);
|
||||
current->state = TASK_INACTIVE;
|
||||
current->flags &= ~TASK_SUSPENDING;
|
||||
prio_total -= current->priority;
|
||||
BUG_ON(prio_total <= 0);
|
||||
preempt_enable();
|
||||
|
||||
/* Async wake up any waiters */
|
||||
wake_up_task(find_task(current->pagerid), 0);
|
||||
schedule();
|
||||
}
|
||||
|
||||
void sched_suspend_async(void)
|
||||
{
|
||||
preempt_disable();
|
||||
sched_rq_remove_task(current);
|
||||
current->state = TASK_INACTIVE;
|
||||
current->flags &= ~TASK_SUSPENDING;
|
||||
prio_total -= current->priority;
|
||||
BUG_ON(prio_total <= 0);
|
||||
|
||||
/* This will make sure we yield soon */
|
||||
preempt_enable();
|
||||
|
||||
/* Async wake up any waiters */
|
||||
wake_up_task(find_task(current->pagerid), 0);
|
||||
need_resched = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Tasks come here, either by setting need_resched (via next irq),
|
||||
* or by directly calling it (in process context).
|
||||
@@ -270,17 +308,6 @@ void schedule()
|
||||
/* Cannot have any irqs that schedule after this */
|
||||
preempt_disable();
|
||||
|
||||
#if 0
|
||||
/* NOTE:
|
||||
* We could avoid unnecessary scheduling by detecting
|
||||
* a task that has been just woken up.
|
||||
*/
|
||||
if ((task->flags & TASK_WOKEN_UP) && in_process_context()) {
|
||||
preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reset schedule flag */
|
||||
need_resched = 0;
|
||||
|
||||
@@ -293,43 +320,13 @@ void schedule()
|
||||
sched_rq_add_task(current, rq_expired, RQ_ADD_BEHIND);
|
||||
}
|
||||
|
||||
/* Check if there's a pending suspend for thread */
|
||||
if (current->flags & TASK_SUSPENDING) {
|
||||
/*
|
||||
* The task should have no locks and be in a runnable state.
|
||||
* (e.g. properly woken up by the suspender)
|
||||
*/
|
||||
if (current->nlocks == 0 &&
|
||||
current->state == TASK_RUNNABLE) {
|
||||
/* Suspend it if suitable */
|
||||
current->state = TASK_INACTIVE;
|
||||
current->flags &= ~TASK_SUSPENDING;
|
||||
|
||||
/*
|
||||
* The task has been made inactive here.
|
||||
* A suspended task affects timeslices whereas
|
||||
* a sleeping task doesn't as it is believed
|
||||
* sleepers would become runnable soon.
|
||||
*/
|
||||
prio_total -= current->priority;
|
||||
BUG_ON(prio_total <= 0);
|
||||
|
||||
/* Prepare to wake up any waiters */
|
||||
wake_up(¤t->wqh_pager, 0);
|
||||
} else {
|
||||
if (current->state == TASK_RUNNABLE)
|
||||
sched_rq_remove_task(current);
|
||||
|
||||
/*
|
||||
* Top up task's ticks temporarily, and
|
||||
* wait for it to release its locks.
|
||||
*/
|
||||
current->state = TASK_RUNNABLE;
|
||||
current->ticks_left = max(current->ticks_left,
|
||||
SCHED_GRANULARITY);
|
||||
sched_rq_add_task(current, rq_runnable, RQ_ADD_FRONT);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If task is about to sleep and
|
||||
* it has pending events, wake it up.
|
||||
*/
|
||||
if (current->flags & TASK_SUSPENDING &&
|
||||
current->state == TASK_SLEEPING)
|
||||
wake_up_task(current, WAKEUP_INTERRUPT);
|
||||
|
||||
/* Determine the next task to be run */
|
||||
if (rq_runnable->total > 0) {
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
*/
|
||||
#include <l4/generic/tcb.h>
|
||||
#include <l4/generic/space.h>
|
||||
#include <l4/generic/scheduler.h>
|
||||
#include <l4/generic/preempt.h>
|
||||
#include <l4/lib/idpool.h>
|
||||
#include INC_ARCH(exception.h)
|
||||
|
||||
/* ID pools for threads and spaces. */
|
||||
struct id_pool *thread_id_pool;
|
||||
@@ -20,6 +23,25 @@ unsigned int need_resched_offset = offsetof(struct ktcb, ts_need_resched);
|
||||
unsigned int syscall_regs_offset = offsetof(struct ktcb, syscall_regs);
|
||||
|
||||
|
||||
/*
|
||||
* When there is an asynchronous pending event to be handled by
|
||||
* the task (e.g. task is suspending), normally it is processed
|
||||
* when the task is returning to user mode from the kernel. If
|
||||
* the event is raised when the task is in userspace, this call
|
||||
* in irq context makes sure it is handled.
|
||||
*/
|
||||
void task_process_pending_flags(void)
|
||||
{
|
||||
if (TASK_IN_USER(current)) {
|
||||
if (current->flags & TASK_SUSPENDING) {
|
||||
if (in_irq_context())
|
||||
sched_suspend_async();
|
||||
else
|
||||
sched_suspend_sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
int task_suspend(struct ktcb *task)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user