In order to cooperate with UML's irq infrastructure and LKL threads based on host threads, irq handlers shall synchronize the our scheduler which is controlled by struct lkl_cpu. To do that, the irq infra notifies its entry of handlers by obtaining cpu access of thread scheduler (lkl_cpu_try_run_irq) and its release (lkl_cpu_put). In additon to that, in order to stick the signal handler's thread to the one of the idle thread, several required configurations of (thread's) signal mask are added: otherwise handlers running on arbitrary thread cannot obtain cpu access and immediately fall into pending interrupt which may slow down the delivery of signals. Signed-off-by: Hajime Tazaki <thehajime@xxxxxxxxx> --- arch/um/include/shared/os.h | 1 + arch/um/kernel/irq.c | 13 ++++++++++ arch/um/kernel/time.c | 2 ++ arch/um/lkl/include/asm/cpu.h | 4 +++ arch/um/lkl/um/cpu.c | 46 +++++++++++++++++++++++++++++++++++ arch/um/lkl/um/setup.c | 5 ++++ arch/um/lkl/um/threads.c | 3 +++ tools/um/uml/signal.c | 12 +++++++-- 8 files changed, 84 insertions(+), 2 deletions(-) diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 13d86f94cf0f..cd8583e4df12 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -243,6 +243,7 @@ extern int set_signals_trace(int enable); extern int os_is_signal_stack(void); extern void deliver_alarm(void); extern void register_pm_wake_signal(void); +extern void set_pending_signals(int sig); /* util.c */ extern void stack_protections(unsigned long address); diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 3741d2380060..d632156b52ac 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -21,6 +21,7 @@ #include <irq_user.h> #include <irq_kern.h> #include <as-layout.h> +#include <asm/cpu.h> extern void free_irqs(void); @@ -563,6 +564,11 @@ unsigned long to_irq_stack(unsigned long *mask_out) unsigned long mask, old; int nested; +#ifdef CONFIG_UMMODE_LIB + if (!lkl_irq_enter(ffs(*mask_out) - 1)) + return 1; +#endif + mask = xchg(&pending_mask, *mask_out); if (mask != 0) { /* @@ -579,6 +585,10 @@ unsigned long to_irq_stack(unsigned long *mask_out) old |= mask; mask = xchg(&pending_mask, old); } while (mask != old); + +#ifdef CONFIG_UMMODE_LIB + lkl_irq_exit(); +#endif return 1; } @@ -616,6 +626,9 @@ unsigned long from_irq_stack(int nested) *to = *ti; mask = xchg(&pending_mask, 0); +#ifdef CONFIG_UMMODE_LIB + lkl_irq_exit(); +#endif return mask & ~1; } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index f4db89b5b5a6..07d705ec5193 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -659,11 +659,13 @@ static struct clock_event_device timer_clockevent = { static irqreturn_t um_timer(int irq, void *dev) { +#ifndef CONFIG_UMMODE_LIB if (get_current()->mm != NULL) { /* userspace - relay signal, results in correct userspace timers */ os_alarm_process(get_current()->mm->context.id.u.pid); } +#endif (*timer_clockevent.event_handler)(&timer_clockevent); diff --git a/arch/um/lkl/include/asm/cpu.h b/arch/um/lkl/include/asm/cpu.h index c1164187151e..b241b5bbdc53 100644 --- a/arch/um/lkl/include/asm/cpu.h +++ b/arch/um/lkl/include/asm/cpu.h @@ -8,4 +8,8 @@ int lkl_cpu_init(void); void lkl_cpu_wait_shutdown(void); void lkl_cpu_change_owner(lkl_thread_t owner); +int lkl_cpu_try_run_irq(int irq); +void lkl_irq_exit(void); +int lkl_irq_enter(int sig); + #endif diff --git a/arch/um/lkl/um/cpu.c b/arch/um/lkl/um/cpu.c index 75452b28d741..841c7e9cc881 100644 --- a/arch/um/lkl/um/cpu.c +++ b/arch/um/lkl/um/cpu.c @@ -8,6 +8,7 @@ #include <asm/sched.h> #include <asm/syscalls.h> #include <init.h> +#include <os.h> /* * This structure is used to get access to the "LKL CPU" that allows us to run @@ -41,6 +42,7 @@ static struct lkl_cpu { */ #define MAX_THREADS 1000000 unsigned int shutdown_gate; + bool irqs_pending; /* no of threads waiting the CPU */ unsigned int sleepers; /* no of times the current thread got the CPU */ @@ -53,6 +55,16 @@ static struct lkl_cpu { struct lkl_sem *shutdown_sem; } cpu; +static void run_irqs(void) +{ + unblock_signals(); +} + +static void set_irq_pending(int sig) +{ + set_pending_signals(sig); +} + /* * internal routine to acquire LKL CPU's lock */ @@ -132,6 +144,16 @@ void lkl_cpu_put(void) !lkl_thread_equal(cpu.owner, lkl_thread_self())) lkl_bug("%s: unbalanced put\n", __func__); + /* we're going to trigger irq handlers if there are any pending + * interrupts, and not irq_disabled. + */ + while (cpu.irqs_pending && !irqs_disabled()) { + cpu.irqs_pending = false; + lkl_mutex_unlock(cpu.lock); + run_irqs(); + lkl_mutex_lock(cpu.lock); + } + /* switch to userspace code if current is host task (TIF_HOST_THREAD), * AND, there are other running tasks. */ @@ -163,6 +185,30 @@ void lkl_cpu_put(void) lkl_mutex_unlock(cpu.lock); } +int lkl_cpu_try_run_irq(int irq) +{ + int ret; + + ret = __cpu_try_get_lock(1); + if (!ret) { + set_irq_pending(irq); + cpu.irqs_pending = true; + } + __cpu_try_get_unlock(ret, 1); + + return ret; +} + +int lkl_irq_enter(int sig) +{ + return lkl_cpu_try_run_irq(sig); +} + +void lkl_irq_exit(void) +{ + return lkl_cpu_put(); +} + static void lkl_cpu_shutdown(void) { __sync_fetch_and_add(&cpu.shutdown_gate, MAX_THREADS); diff --git a/arch/um/lkl/um/setup.c b/arch/um/lkl/um/setup.c index ba8338d4fc23..12b235826573 100644 --- a/arch/um/lkl/um/setup.c +++ b/arch/um/lkl/um/setup.c @@ -36,6 +36,8 @@ static void __init *lkl_run_kernel(void *arg) panic_blink = lkl_panic_blink; + /* signal should be received at this thread (main and idle threads) */ + init_new_thread_signals(); threads_init(); lkl_cpu_get(); start_kernel(); @@ -58,6 +60,9 @@ int __init lkl_start_kernel(struct lkl_host_operations *ops, if (ret) goto out_free_init_sem; + change_sig(SIGALRM, 0); + change_sig(SIGIO, 0); + ret = lkl_thread_create(lkl_run_kernel, NULL); if (!ret) { ret = -ENOMEM; diff --git a/arch/um/lkl/um/threads.c b/arch/um/lkl/um/threads.c index 7ef9b9f2a6b7..c7ff578b7a91 100644 --- a/arch/um/lkl/um/threads.c +++ b/arch/um/lkl/um/threads.c @@ -152,6 +152,9 @@ static void *thread_bootstrap(void *_tba) int (*f)(void *) = tba->f; void *arg = tba->arg; + change_sig(SIGALRM, 0); + change_sig(SIGIO, 0); + lkl_sem_down(ti->task->thread.arch.sched_sem); kfree(tba); if (ti->task->thread.prev_sched) diff --git a/tools/um/uml/signal.c b/tools/um/uml/signal.c index 96f511d1aabe..de04b0dd34bb 100644 --- a/tools/um/uml/signal.c +++ b/tools/um/uml/signal.c @@ -230,8 +230,8 @@ void set_handler(int sig) sigemptyset(&sig_mask); sigaddset(&sig_mask, sig); - if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) - panic("sigprocmask failed - errno = %d\n", errno); + if (pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) + panic("pthread_sigmask failed - errno = %d\n", errno); } void send_sigio_to_self(void) @@ -375,3 +375,11 @@ int os_is_signal_stack(void) return ss.ss_flags & SS_ONSTACK; } + +void set_pending_signals(int sig) +{ + if (sig == SIGIO) + signals_pending |= SIGIO_MASK; + else if (sig == SIGALRM) + signals_pending |= SIGALRM_MASK; +} -- 2.21.0 (Apple Git-122.2)