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