blob: 884e45751944f341dbd9312fc29ca5b2f5138afb [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"
Gennady Sharapov0805d892006-01-08 01:01:29 -080015#include "user.h"
16#include "signal_kern.h"
17#include "sysdep/sigcontext.h"
18#include "sysdep/signal.h"
19#include "sigcontext.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "mode.h"
Gennady Sharapovcff65c42006-01-18 17:42:42 -080021#include "os.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Bodo Stroesser51a6b0c2005-05-05 16:15:38 -070023void sig_handler(ARCH_SIGHDLR_PARAM)
Linus Torvalds1da177e2005-04-16 15:20:36 -070024{
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
32extern int timer_irq_inited;
33
Bodo Stroesser51a6b0c2005-05-05 16:15:38 -070034void alarm_handler(ARCH_SIGHDLR_PARAM)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
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
Bodo Stroesser2c332a22006-01-18 17:42:43 -080051extern void do_boot_timer_handler(struct sigcontext * sc);
52
53void 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
Gennady Sharapov0805d892006-01-08 01:01:29 -080062void 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
72void 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
82void 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
101int 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
115static 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
127void block_signals(void)
128{
129 change_signals(SIG_BLOCK);
130}
131
132void 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 */
Gennady Sharapov0805d892006-01-08 01:01:29 -0800143#define SIGIO_BIT 0
144#define SIGVTALRM_BIT 1
145
146static 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
156int 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
165int 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}