summaryrefslogtreecommitdiff
path: root/arch/um/os-Linux/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/os-Linux/signal.c')
-rw-r--r--arch/um/os-Linux/signal.c55
1 files changed, 51 insertions, 4 deletions
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 8c9d162e6c51..1d501acb22ee 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -18,6 +18,7 @@
#include <sysdep/mcontext.h>
#include <um_malloc.h>
#include <sys/ucontext.h>
+#include <timetravel.h>
void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
[SIGTRAP] = relay_signal,
@@ -63,16 +64,29 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
#define SIGALRM_MASK (1 << SIGALRM_BIT)
int signals_enabled;
+#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT
+static int signals_blocked;
+#else
+#define signals_blocked false
+#endif
static unsigned int signals_pending;
static unsigned int signals_active = 0;
void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
{
- int enabled;
+ int enabled = signals_enabled;
- enabled = signals_enabled;
- if (!enabled && (sig == SIGIO)) {
- signals_pending |= SIGIO_MASK;
+ if ((signals_blocked || !enabled) && (sig == SIGIO)) {
+ /*
+ * In TT_MODE_EXTERNAL, need to still call time-travel
+ * handlers unless signals are also blocked for the
+ * external time message processing. This will mark
+ * signals_pending by itself (only if necessary.)
+ */
+ if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL)
+ sigio_run_timetravel_handlers();
+ else
+ signals_pending |= SIGIO_MASK;
return;
}
@@ -363,6 +377,39 @@ int set_signals_trace(int enable)
return ret;
}
+#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT
+void mark_sigio_pending(void)
+{
+ signals_pending |= SIGIO_MASK;
+}
+
+void block_signals_hard(void)
+{
+ if (signals_blocked)
+ return;
+ signals_blocked = 1;
+ barrier();
+}
+
+void unblock_signals_hard(void)
+{
+ if (!signals_blocked)
+ return;
+ /* Must be set to 0 before we check the pending bits etc. */
+ signals_blocked = 0;
+ barrier();
+
+ if (signals_pending && signals_enabled) {
+ /* this is a bit inefficient, but that's not really important */
+ block_signals();
+ unblock_signals();
+ } else if (signals_pending & SIGIO_MASK) {
+ /* we need to run time-travel handlers even if not enabled */
+ sigio_run_timetravel_handlers();
+ }
+}
+#endif
+
int os_is_signal_stack(void)
{
stack_t ss;