diff --git a/conts/test/main.c b/conts/test/main.c index fdcc3bf..12ea2b7 100644 --- a/conts/test/main.c +++ b/conts/test/main.c @@ -15,8 +15,10 @@ int exit_test_thread(void *arg) { + while (1) + ; //l4_thread_switch(0); - l4_exit(5); + //l4_exit(5); return 0; } @@ -36,7 +38,6 @@ int exit_test(void) // l4_thread_switch(0); -#if 0 /* Kill it */ printf("Killing Thread (%d).\n", ids.tid); if ((ret = l4_thread_control(THREAD_DESTROY, &ids)) < 0) @@ -44,8 +45,8 @@ int exit_test(void) else printf("Success: Killed Thread (%d)\n", ids.tid); -#endif +#if 0 /* Wait on it */ printf("Waiting on Thread (%d) to exit.\n", ids.tid); if ((ret = l4_thread_control(THREAD_WAIT, &ids)) >= 0) @@ -54,6 +55,7 @@ int exit_test(void) printf("Error. Wait on (%d) failed. err = %d\n", ids.tid, ret); +#endif return 0; out_err: BUG(); diff --git a/include/l4/arch/arm/exception.h b/include/l4/arch/arm/exception.h index 28fd94e..91b0a0d 100644 --- a/include/l4/arch/arm/exception.h +++ b/include/l4/arch/arm/exception.h @@ -8,6 +8,7 @@ #include INC_ARCH(asm.h) + static inline void enable_irqs() { __asm__ __volatile__( @@ -38,30 +39,29 @@ static inline void disable_irqs() ); } -#if 0 /* These will be useful for nested irq disable/enable calls */ /* Disable the irqs unconditionally, but also keep the previous state such that * if it was already disabled before the call, the restore call would retain * this state. */ -static inline void irq_local_disable_save(unsigned long *flags) +static inline void irq_local_disable_save(unsigned long *state) { unsigned long temp; __asm__ __volatile__ ( "mrs %0, cpsr_fc\n" "orr %1, %0, #0x80\n" "msr cpsr_fc, %1\n" - : "=r"(*flags), "=r" (temp) + :: "r" (*state), "r" (temp) ); } /* Simply change it back to original state supplied in @flags. This might enable * or retain disabled state of the irqs for example. Useful for nested calls. */ -static inline void irq_local_restore(unsigned long flags) +static inline void irq_local_restore(unsigned long state) { __asm__ __volatile__ ( "msr cpsr_fc, %0\n" - : "r" (flags) + :: "r" (state) ); } -#endif + static inline void irq_local_enable() { enable_irqs(); diff --git a/include/l4/lib/spinlock.h b/include/l4/lib/spinlock.h index 92bd92d..3e27986 100644 --- a/include/l4/lib/spinlock.h +++ b/include/l4/lib/spinlock.h @@ -39,19 +39,21 @@ static inline void spin_unlock(struct spinlock *s) * - To be used for synchronising against processes and irqs * on other cpus. */ -static inline void spin_lock_irq(struct spinlock *s) +static inline void spin_lock_irq(struct spinlock *s, + unsigned long state) { - irq_local_disable(); /* Even in UP an irq could deadlock us */ + irq_local_disable_save(&state); #if defined(CONFIG_SMP) __spin_lock(&s->lock); #endif } -static inline void spin_unlock_irq(struct spinlock *s) +static inline void spin_unlock_irq(struct spinlock *s, + unsigned long state) { #if defined(CONFIG_SMP) __spin_unlock(&s->lock); #endif - irq_local_enable(); + irq_local_restore(state); } #endif /* __LIB__SPINLOCK_H__ */ diff --git a/src/generic/irq.c b/src/generic/irq.c index be855f5..5ad1814 100644 --- a/src/generic/irq.c +++ b/src/generic/irq.c @@ -74,15 +74,6 @@ void do_irq(void) printk("Spurious or broken irq\n"); BUG(); } irq_enable(irq_index); -#if 0 - /* Process any pending flags for currently runnable task */ - if (!in_nested_irq_context()) { - if (in_user()) { - if (current->flags & TASK_SUSPENDING) - sched_suspend_async(); - } - } -#endif } diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index a9826fa..f6934f0 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -33,6 +33,7 @@ extern unsigned int current_irq_nest_count; /* This ensures no scheduling occurs after voluntary preempt_disable() */ static int voluntary_preempt = 0; + void sched_lock_runqueues(void) { spin_lock(&scheduler.sched_rq[0].lock); @@ -89,7 +90,6 @@ int in_task_context(void) return !in_irq_context(); } - /* * In current implementation, if all task are asleep it is considered * a bug. We use idle_task() to investigate. @@ -241,6 +241,20 @@ void sched_exit_sync(void) schedule(); } +void sched_exit_async(void) +{ + preempt_disable(); + sched_rq_remove_task(current); + current->state = TASK_DEAD; + current->flags &= ~TASK_EXITING; + preempt_enable(); + + if (current->pagerid != current->tid) + wake_up(¤t->wqh_pager, 0); + + need_resched = 1; +} + /* * NOTE: Could do these as sched_prepare_suspend() * + schedule() or need_resched = 1 @@ -368,6 +382,8 @@ void schedule() } /* + * FIXME: Are these smp-safe? + * * If task is about to sleep and * it has pending events, wake it up. */ @@ -375,6 +391,20 @@ void schedule() current->state == TASK_SLEEPING) wake_up_task(current, WAKEUP_INTERRUPT); + /* + * If task has pending events, and is in userspace + * (guaranteed to have no unfinished jobs in kernel) + * handle those events + */ + if ((current->flags & TASK_PENDING_SIGNAL) && + current->state == TASK_RUNNABLE && + TASK_IN_USER(current)) { + if (current->flags & TASK_SUSPENDING) + sched_suspend_async(); + else if (current->flags & TASK_EXITING) + sched_exit_async(); + } + /* Determine the next task to be run */ if (scheduler.rq_runnable->total > 0) { next = link_to_struct(scheduler.rq_runnable->task_list.next,