Merge branch 'upstream'
[pandora-kernel.git] / arch / um / kernel / signal_user.c
1 /* 
2  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include "user_util.h"
15 #include "kern_util.h"
16 #include "user.h"
17 #include "signal_user.h"
18 #include "signal_kern.h"
19 #include "sysdep/sigcontext.h"
20 #include "sigcontext.h"
21
22 void set_sigstack(void *sig_stack, int size)
23 {
24         stack_t stack = ((stack_t) { .ss_flags  = 0,
25                                      .ss_sp     = (__ptr_t) sig_stack,
26                                      .ss_size   = size - sizeof(void *) });
27
28         if(sigaltstack(&stack, NULL) != 0)
29                 panic("enabling signal stack failed, errno = %d\n", errno);
30 }
31
32 void set_handler(int sig, void (*handler)(int), int flags, ...)
33 {
34         struct sigaction action;
35         va_list ap;
36         int mask;
37
38         va_start(ap, flags);
39         action.sa_handler = handler;
40         sigemptyset(&action.sa_mask);
41         while((mask = va_arg(ap, int)) != -1){
42                 sigaddset(&action.sa_mask, mask);
43         }
44         va_end(ap);
45         action.sa_flags = flags;
46         action.sa_restorer = NULL;
47         if(sigaction(sig, &action, NULL) < 0)
48                 panic("sigaction failed");
49 }
50
51 int change_sig(int signal, int on)
52 {
53         sigset_t sigset, old;
54
55         sigemptyset(&sigset);
56         sigaddset(&sigset, signal);
57         sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
58         return(!sigismember(&old, signal));
59 }
60
61 /* Both here and in set/get_signal we don't touch SIGPROF, because we must not
62  * disable profiling; it's safe because the profiling code does not interact
63  * with the kernel code at all.*/
64
65 static void change_signals(int type)
66 {
67         sigset_t mask;
68
69         sigemptyset(&mask);
70         sigaddset(&mask, SIGVTALRM);
71         sigaddset(&mask, SIGALRM);
72         sigaddset(&mask, SIGIO);
73         if(sigprocmask(type, &mask, NULL) < 0)
74                 panic("Failed to change signal mask - errno = %d", errno);
75 }
76
77 void block_signals(void)
78 {
79         change_signals(SIG_BLOCK);
80 }
81
82 void unblock_signals(void)
83 {
84         change_signals(SIG_UNBLOCK);
85 }
86
87 /* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
88  * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
89  * be able to profile all of UML, not just the non-critical sections.  If
90  * profiling is not thread-safe, then that is not my problem.  We can disable
91  * profiling when SMP is enabled in that case.
92  */
93 #define SIGIO_BIT 0
94 #define SIGVTALRM_BIT 1
95
96 static int enable_mask(sigset_t *mask)
97 {
98         int sigs;
99
100         sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
101         sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
102         sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
103         return(sigs);
104 }
105
106 int get_signals(void)
107 {
108         sigset_t mask;
109         
110         if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
111                 panic("Failed to get signal mask");
112         return(enable_mask(&mask));
113 }
114
115 int set_signals(int enable)
116 {
117         sigset_t mask;
118         int ret;
119
120         sigemptyset(&mask);
121         if(enable & (1 << SIGIO_BIT)) 
122                 sigaddset(&mask, SIGIO);
123         if(enable & (1 << SIGVTALRM_BIT)){
124                 sigaddset(&mask, SIGVTALRM);
125                 sigaddset(&mask, SIGALRM);
126         }
127
128         /* This is safe - sigprocmask is guaranteed to copy locally the
129          * value of new_set, do his work and then, at the end, write to
130          * old_set.
131          */
132         if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
133                 panic("Failed to enable signals");
134         ret = enable_mask(&mask);
135         sigemptyset(&mask);
136         if((enable & (1 << SIGIO_BIT)) == 0) 
137                 sigaddset(&mask, SIGIO);
138         if((enable & (1 << SIGVTALRM_BIT)) == 0){
139                 sigaddset(&mask, SIGVTALRM);
140                 sigaddset(&mask, SIGALRM);
141         }
142         if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
143                 panic("Failed to block signals");
144
145         return(ret);
146 }
147
148 /*
149  * Overrides for Emacs so that we follow Linus's tabbing style.
150  * Emacs will notice this stuff at the end of the file and automatically
151  * adjust the settings for this buffer only.  This must remain at the end
152  * of the file.
153  * ---------------------------------------------------------------------------
154  * Local variables:
155  * c-file-style: "linux"
156  * End:
157  */