blob: 6b81739279d1fe059e3d23310e7b532b363be8a0 [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"
Gennady Sharapov0805d892006-01-08 01:01:29 -080018#include "sigcontext.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "mode.h"
Gennady Sharapovcff65c42006-01-18 17:42:42 -080020#include "os.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Jeff Dike1d7173b2006-01-18 17:42:49 -080022/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
23 * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
24 * be able to profile all of UML, not just the non-critical sections. If
25 * profiling is not thread-safe, then that is not my problem. We can disable
26 * profiling when SMP is enabled in that case.
27 */
28#define SIGIO_BIT 0
29#define SIGIO_MASK (1 << SIGIO_BIT)
30
31#define SIGVTALRM_BIT 1
32#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
33
34#define SIGALRM_BIT 2
35#define SIGALRM_MASK (1 << SIGALRM_BIT)
36
37static int signals_enabled = 1;
38static int pending = 0;
39
Jeff Dike4b84c692006-09-25 23:33:04 -070040void sig_handler(int sig, struct sigcontext *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
Jeff Dike1d7173b2006-01-18 17:42:49 -080042 int enabled;
43
Jeff Dike1d7173b2006-01-18 17:42:49 -080044 enabled = signals_enabled;
45 if(!enabled && (sig == SIGIO)){
46 pending |= SIGIO_MASK;
47 return;
48 }
49
50 block_signals();
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
53 sig, sc);
Jeff Dike1d7173b2006-01-18 17:42:49 -080054
55 set_signals(enabled);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056}
57
Jeff Dike1d7173b2006-01-18 17:42:49 -080058static void real_alarm_handler(int sig, struct sigcontext *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059{
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 if(sig == SIGALRM)
61 switch_timers(0);
62
63 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
64 sig, sc);
65
66 if(sig == SIGALRM)
67 switch_timers(1);
Jeff Dike1d7173b2006-01-18 17:42:49 -080068
69}
70
Jeff Dike4b84c692006-09-25 23:33:04 -070071void alarm_handler(int sig, struct sigcontext *sc)
Jeff Dike1d7173b2006-01-18 17:42:49 -080072{
Jeff Dike1d7173b2006-01-18 17:42:49 -080073 int enabled;
74
Jeff Dike1d7173b2006-01-18 17:42:49 -080075 enabled = signals_enabled;
76 if(!signals_enabled){
77 if(sig == SIGVTALRM)
78 pending |= SIGVTALRM_MASK;
79 else pending |= SIGALRM_MASK;
80
81 return;
82 }
83
84 block_signals();
85
86 real_alarm_handler(sig, sc);
87 set_signals(enabled);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
Gennady Sharapov0805d892006-01-08 01:01:29 -080090void set_sigstack(void *sig_stack, int size)
91{
92 stack_t stack = ((stack_t) { .ss_flags = 0,
93 .ss_sp = (__ptr_t) sig_stack,
94 .ss_size = size - sizeof(void *) });
95
96 if(sigaltstack(&stack, NULL) != 0)
97 panic("enabling signal stack failed, errno = %d\n", errno);
98}
99
100void remove_sigstack(void)
101{
102 stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
103 .ss_sp = NULL,
104 .ss_size = 0 });
105
106 if(sigaltstack(&stack, NULL) != 0)
107 panic("disabling signal stack failed, errno = %d\n", errno);
108}
109
Jeff Dike4b84c692006-09-25 23:33:04 -0700110void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
111
112extern void hard_handler(int sig);
113
Gennady Sharapov0805d892006-01-08 01:01:29 -0800114void set_handler(int sig, void (*handler)(int), int flags, ...)
115{
116 struct sigaction action;
117 va_list ap;
Jeff Dike1d7173b2006-01-18 17:42:49 -0800118 sigset_t sig_mask;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800119 int mask;
120
Jeff Dike4b84c692006-09-25 23:33:04 -0700121 handlers[sig] = (void (*)(int, struct sigcontext *)) handler;
122 action.sa_handler = hard_handler;
123
Gennady Sharapov0805d892006-01-08 01:01:29 -0800124 sigemptyset(&action.sa_mask);
Jeff Dike4b84c692006-09-25 23:33:04 -0700125
126 va_start(ap, flags);
127 while((mask = va_arg(ap, int)) != -1)
Gennady Sharapov0805d892006-01-08 01:01:29 -0800128 sigaddset(&action.sa_mask, mask);
Gennady Sharapov0805d892006-01-08 01:01:29 -0800129 va_end(ap);
Jeff Dike4b84c692006-09-25 23:33:04 -0700130
Gennady Sharapov0805d892006-01-08 01:01:29 -0800131 action.sa_flags = flags;
132 action.sa_restorer = NULL;
133 if(sigaction(sig, &action, NULL) < 0)
Jeff Dike1d7173b2006-01-18 17:42:49 -0800134 panic("sigaction failed - errno = %d\n", errno);
135
136 sigemptyset(&sig_mask);
137 sigaddset(&sig_mask, sig);
138 if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
139 panic("sigprocmask failed - errno = %d\n", errno);
Gennady Sharapov0805d892006-01-08 01:01:29 -0800140}
141
142int change_sig(int signal, int on)
143{
144 sigset_t sigset, old;
145
146 sigemptyset(&sigset);
147 sigaddset(&sigset, signal);
148 sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
149 return(!sigismember(&old, signal));
150}
151
Gennady Sharapov0805d892006-01-08 01:01:29 -0800152void block_signals(void)
153{
Jeff Dike1d7173b2006-01-18 17:42:49 -0800154 signals_enabled = 0;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800155}
156
157void unblock_signals(void)
158{
Jeff Dike1d7173b2006-01-18 17:42:49 -0800159 int save_pending;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800160
Jeff Dike1d7173b2006-01-18 17:42:49 -0800161 if(signals_enabled == 1)
162 return;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800163
Jeff Dike1d7173b2006-01-18 17:42:49 -0800164 /* We loop because the IRQ handler returns with interrupts off. So,
165 * interrupts may have arrived and we need to re-enable them and
166 * recheck pending.
167 */
168 while(1){
169 /* Save and reset save_pending after enabling signals. This
170 * way, pending won't be changed while we're reading it.
171 */
172 signals_enabled = 1;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800173
Jeff Dike1d7173b2006-01-18 17:42:49 -0800174 save_pending = pending;
175 if(save_pending == 0)
176 return;
177
178 pending = 0;
179
180 /* We have pending interrupts, so disable signals, as the
181 * handlers expect them off when they are called. They will
182 * be enabled again above.
183 */
184
185 signals_enabled = 0;
186
187 /* Deal with SIGIO first because the alarm handler might
188 * schedule, leaving the pending SIGIO stranded until we come
189 * back here.
190 */
191 if(save_pending & SIGIO_MASK)
192 CHOOSE_MODE_PROC(sig_handler_common_tt,
193 sig_handler_common_skas, SIGIO, NULL);
194
195 if(save_pending & SIGALRM_MASK)
196 real_alarm_handler(SIGALRM, NULL);
197
198 if(save_pending & SIGVTALRM_MASK)
199 real_alarm_handler(SIGVTALRM, NULL);
200 }
Gennady Sharapov0805d892006-01-08 01:01:29 -0800201}
202
203int get_signals(void)
204{
Jeff Dike1d7173b2006-01-18 17:42:49 -0800205 return signals_enabled;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800206}
207
208int set_signals(int enable)
209{
Gennady Sharapov0805d892006-01-08 01:01:29 -0800210 int ret;
Jeff Dike1d7173b2006-01-18 17:42:49 -0800211 if(signals_enabled == enable)
212 return enable;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800213
Jeff Dike1d7173b2006-01-18 17:42:49 -0800214 ret = signals_enabled;
215 if(enable)
216 unblock_signals();
217 else block_signals();
Gennady Sharapov0805d892006-01-08 01:01:29 -0800218
Jeff Dike1d7173b2006-01-18 17:42:49 -0800219 return ret;
Gennady Sharapov0805d892006-01-08 01:01:29 -0800220}
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800221
222void os_usr1_signal(int on)
223{
224 change_sig(SIGUSR1, on);
225}