[PATCH] uml: move libc-dependent skas process handling
[powerpc.git] / arch / um / os-Linux / signal.c
index c7bfd5e..56ca959 100644 (file)
@@ -4,9 +4,21 @@
  */
 
 #include <signal.h>
-#include "time_user.h"
-#include "mode.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "user_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "sysdep/sigcontext.h"
 #include "sysdep/signal.h"
+#include "sigcontext.h"
+#include "mode.h"
+#include "os.h"
 
 void sig_handler(ARCH_SIGHDLR_PARAM)
 {
@@ -36,13 +48,154 @@ void alarm_handler(ARCH_SIGHDLR_PARAM)
                switch_timers(1);
 }
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
+extern void do_boot_timer_handler(struct sigcontext * sc);
+
+void boot_timer_handler(ARCH_SIGHDLR_PARAM)
+{
+       struct sigcontext *sc;
+
+       ARCH_GET_SIGCONTEXT(sc, sig);
+
+       do_boot_timer_handler(sc);
+}
+
+void set_sigstack(void *sig_stack, int size)
+{
+       stack_t stack = ((stack_t) { .ss_flags  = 0,
+                                    .ss_sp     = (__ptr_t) sig_stack,
+                                    .ss_size   = size - sizeof(void *) });
+
+       if(sigaltstack(&stack, NULL) != 0)
+               panic("enabling signal stack failed, errno = %d\n", errno);
+}
+
+void remove_sigstack(void)
+{
+       stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
+                                    .ss_sp     = NULL,
+                                    .ss_size   = 0 });
+
+       if(sigaltstack(&stack, NULL) != 0)
+               panic("disabling signal stack failed, errno = %d\n", errno);
+}
+
+void set_handler(int sig, void (*handler)(int), int flags, ...)
+{
+       struct sigaction action;
+       va_list ap;
+       int mask;
+
+       va_start(ap, flags);
+       action.sa_handler = handler;
+       sigemptyset(&action.sa_mask);
+       while((mask = va_arg(ap, int)) != -1){
+               sigaddset(&action.sa_mask, mask);
+       }
+       va_end(ap);
+       action.sa_flags = flags;
+       action.sa_restorer = NULL;
+       if(sigaction(sig, &action, NULL) < 0)
+               panic("sigaction failed");
+}
+
+int change_sig(int signal, int on)
+{
+       sigset_t sigset, old;
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset, signal);
+       sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
+       return(!sigismember(&old, signal));
+}
+
+/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
+ * disable profiling; it's safe because the profiling code does not interact
+ * with the kernel code at all.*/
+
+static void change_signals(int type)
+{
+       sigset_t mask;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGVTALRM);
+       sigaddset(&mask, SIGALRM);
+       sigaddset(&mask, SIGIO);
+       if(sigprocmask(type, &mask, NULL) < 0)
+               panic("Failed to change signal mask - errno = %d", errno);
+}
+
+void block_signals(void)
+{
+       change_signals(SIG_BLOCK);
+}
+
+void unblock_signals(void)
+{
+       change_signals(SIG_UNBLOCK);
+}
+
+/* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
+ * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
+ * be able to profile all of UML, not just the non-critical sections.  If
+ * profiling is not thread-safe, then that is not my problem.  We can disable
+ * profiling when SMP is enabled in that case.
  */
+#define SIGIO_BIT 0
+#define SIGVTALRM_BIT 1
+
+static int enable_mask(sigset_t *mask)
+{
+       int sigs;
+
+       sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
+       sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
+       sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
+       return(sigs);
+}
+
+int get_signals(void)
+{
+       sigset_t mask;
+
+       if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
+               panic("Failed to get signal mask");
+       return(enable_mask(&mask));
+}
+
+int set_signals(int enable)
+{
+       sigset_t mask;
+       int ret;
+
+       sigemptyset(&mask);
+       if(enable & (1 << SIGIO_BIT))
+               sigaddset(&mask, SIGIO);
+       if(enable & (1 << SIGVTALRM_BIT)){
+               sigaddset(&mask, SIGVTALRM);
+               sigaddset(&mask, SIGALRM);
+       }
+
+       /* This is safe - sigprocmask is guaranteed to copy locally the
+        * value of new_set, do his work and then, at the end, write to
+        * old_set.
+        */
+       if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
+               panic("Failed to enable signals");
+       ret = enable_mask(&mask);
+       sigemptyset(&mask);
+       if((enable & (1 << SIGIO_BIT)) == 0)
+               sigaddset(&mask, SIGIO);
+       if((enable & (1 << SIGVTALRM_BIT)) == 0){
+               sigaddset(&mask, SIGVTALRM);
+               sigaddset(&mask, SIGALRM);
+       }
+       if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
+               panic("Failed to block signals");
+
+       return(ret);
+}
+
+void os_usr1_signal(int on)
+{
+       change_sig(SIGUSR1, on);
+}