Thread (247 messages) 247 messages, 7 authors, 2021-03-18

[RFC v8 13/20] um: lkl: integrate with irq infrastructure of UML

From: Hajime Tazaki <hidden>
Date: 2021-01-20 03:31:39
Also in: linux-um
Subsystem: the rest, user-mode linux (uml) · Maintainers: Linus Torvalds, Richard Weinberger, Anton Ivanov, Johannes Berg

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 <redacted>
---
 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)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help