blob: c1f46a0fef13d14c8740d80091fb18a2cf0690d7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
Gennady Sharapov0805d892006-01-08 01:01:29 -08007#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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include "time_user.h"
22#include "mode.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Bodo Stroesser51a6b0c2005-05-05 16:15:38 -070024void sig_handler(ARCH_SIGHDLR_PARAM)
Linus Torvalds1da177e2005-04-16 15:20:36 -070025{
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
33extern int timer_irq_inited;
34
Bodo Stroesser51a6b0c2005-05-05 16:15:38 -070035void alarm_handler(ARCH_SIGHDLR_PARAM)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036{
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
Gennady Sharapov0805d892006-01-08 01:01:29 -080052void 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
62void 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
72void 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
91int 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
105static 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
117void block_signals(void)
118{
119 change_signals(SIG_BLOCK);
120}
121
122void 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 */
Gennady Sharapov0805d892006-01-08 01:01:29 -0800133#define SIGIO_BIT 0
134#define SIGVTALRM_BIT 1
135
136static 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
146int 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
155int 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}