Merge branch 'upstream'
[pandora-kernel.git] / arch / um / os-Linux / signal.c
1 /*
2  * Copyright (C) 2004 PathScale, Inc
3  * Licensed under the GPL
4  */
5
6 #include <signal.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.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_kern.h"
18 #include "sysdep/sigcontext.h"
19 #include "sysdep/signal.h"
20 #include "sigcontext.h"
21 #include "time_user.h"
22 #include "mode.h"
23
24 void sig_handler(ARCH_SIGHDLR_PARAM)
25 {
26         struct sigcontext *sc;
27
28         ARCH_GET_SIGCONTEXT(sc, sig);
29         CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
30                          sig, sc);
31 }
32
33 extern int timer_irq_inited;
34
35 void alarm_handler(ARCH_SIGHDLR_PARAM)
36 {
37         struct sigcontext *sc;
38
39         ARCH_GET_SIGCONTEXT(sc, sig);
40         if(!timer_irq_inited) return;
41
42         if(sig == SIGALRM)
43                 switch_timers(0);
44
45         CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
46                          sig, sc);
47
48         if(sig == SIGALRM)
49                 switch_timers(1);
50 }
51
52 void set_sigstack(void *sig_stack, int size)
53 {
54         stack_t stack = ((stack_t) { .ss_flags  = 0,
55                                      .ss_sp     = (__ptr_t) sig_stack,
56                                      .ss_size   = size - sizeof(void *) });
57
58         if(sigaltstack(&stack, NULL) != 0)
59                 panic("enabling signal stack failed, errno = %d\n", errno);
60 }
61
62 void remove_sigstack(void)
63 {
64         stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
65                                      .ss_sp     = NULL,
66                                      .ss_size   = 0 });
67
68         if(sigaltstack(&stack, NULL) != 0)
69                 panic("disabling signal stack failed, errno = %d\n", errno);
70 }
71
72 void set_handler(int sig, void (*handler)(int), int flags, ...)
73 {
74         struct sigaction action;
75         va_list ap;
76         int mask;
77
78         va_start(ap, flags);
79         action.sa_handler = handler;
80         sigemptyset(&action.sa_mask);
81         while((mask = va_arg(ap, int)) != -1){
82                 sigaddset(&action.sa_mask, mask);
83         }
84         va_end(ap);
85         action.sa_flags = flags;
86         action.sa_restorer = NULL;
87         if(sigaction(sig, &action, NULL) < 0)
88                 panic("sigaction failed");
89 }
90
91 int change_sig(int signal, int on)
92 {
93         sigset_t sigset, old;
94
95         sigemptyset(&sigset);
96         sigaddset(&sigset, signal);
97         sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
98         return(!sigismember(&old, signal));
99 }
100
101 /* Both here and in set/get_signal we don't touch SIGPROF, because we must not
102  * disable profiling; it's safe because the profiling code does not interact
103  * with the kernel code at all.*/
104
105 static void change_signals(int type)
106 {
107         sigset_t mask;
108
109         sigemptyset(&mask);
110         sigaddset(&mask, SIGVTALRM);
111         sigaddset(&mask, SIGALRM);
112         sigaddset(&mask, SIGIO);
113         if(sigprocmask(type, &mask, NULL) < 0)
114                 panic("Failed to change signal mask - errno = %d", errno);
115 }
116
117 void block_signals(void)
118 {
119         change_signals(SIG_BLOCK);
120 }
121
122 void unblock_signals(void)
123 {
124         change_signals(SIG_UNBLOCK);
125 }
126
127 /* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
128  * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
129  * be able to profile all of UML, not just the non-critical sections.  If
130  * profiling is not thread-safe, then that is not my problem.  We can disable
131  * profiling when SMP is enabled in that case.
132  */
133 #define SIGIO_BIT 0
134 #define SIGVTALRM_BIT 1
135
136 static int enable_mask(sigset_t *mask)
137 {
138         int sigs;
139
140         sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
141         sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
142         sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
143         return(sigs);
144 }
145
146 int get_signals(void)
147 {
148         sigset_t mask;
149
150         if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
151                 panic("Failed to get signal mask");
152         return(enable_mask(&mask));
153 }
154
155 int set_signals(int enable)
156 {
157         sigset_t mask;
158         int ret;
159
160         sigemptyset(&mask);
161         if(enable & (1 << SIGIO_BIT))
162                 sigaddset(&mask, SIGIO);
163         if(enable & (1 << SIGVTALRM_BIT)){
164                 sigaddset(&mask, SIGVTALRM);
165                 sigaddset(&mask, SIGALRM);
166         }
167
168         /* This is safe - sigprocmask is guaranteed to copy locally the
169          * value of new_set, do his work and then, at the end, write to
170          * old_set.
171          */
172         if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
173                 panic("Failed to enable signals");
174         ret = enable_mask(&mask);
175         sigemptyset(&mask);
176         if((enable & (1 << SIGIO_BIT)) == 0)
177                 sigaddset(&mask, SIGIO);
178         if((enable & (1 << SIGVTALRM_BIT)) == 0){
179                 sigaddset(&mask, SIGVTALRM);
180                 sigaddset(&mask, SIGALRM);
181         }
182         if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
183                 panic("Failed to block signals");
184
185         return(ret);
186 }