signal.c 6.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6
/*
 * Copyright (C) 2004 PathScale, Inc
 * Licensed under the GPL
 */

#include <signal.h>
7 8 9 10 11 12 13 14 15 16
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <sys/mman.h>
#include "user.h"
#include "signal_kern.h"
#include "sysdep/sigcontext.h"
J
Jeff Dike 已提交
17
#include "sysdep/barrier.h"
18
#include "sigcontext.h"
L
Linus Torvalds 已提交
19
#include "mode.h"
20
#include "os.h"
L
Linus Torvalds 已提交
21

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled
 * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to
 * be able to profile all of UML, not just the non-critical sections.  If
 * profiling is not thread-safe, then that is not my problem.  We can disable
 * profiling when SMP is enabled in that case.
 */
#define SIGIO_BIT 0
#define SIGIO_MASK (1 << SIGIO_BIT)

#define SIGVTALRM_BIT 1
#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)

#define SIGALRM_BIT 2
#define SIGALRM_MASK (1 << SIGALRM_BIT)

J
Jeff Dike 已提交
37 38 39 40 41 42
/* These are used by both the signal handlers and
 * block/unblock_signals.  I don't want modifications cached in a
 * register - they must go straight to memory.
 */
static volatile int signals_enabled = 1;
static volatile int pending = 0;
43

44
void sig_handler(int sig, struct sigcontext *sc)
L
Linus Torvalds 已提交
45
{
46 47 48 49 50 51 52 53 54 55
	int enabled;

	enabled = signals_enabled;
	if(!enabled && (sig == SIGIO)){
		pending |= SIGIO_MASK;
		return;
	}

	block_signals();

L
Linus Torvalds 已提交
56 57
	CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
			 sig, sc);
58 59

	set_signals(enabled);
L
Linus Torvalds 已提交
60 61
}

62
static void real_alarm_handler(int sig, struct sigcontext *sc)
L
Linus Torvalds 已提交
63
{
J
Jeff Dike 已提交
64 65
	union uml_pt_regs regs;

L
Linus Torvalds 已提交
66 67 68
	if(sig == SIGALRM)
		switch_timers(0);

J
Jeff Dike 已提交
69 70 71 72 73
	if(sc != NULL)
		copy_sc(&regs, sc);
	regs.skas.is_user = 0;
	unblock_signals();
	timer_handler(sig, &regs);
L
Linus Torvalds 已提交
74 75 76

	if(sig == SIGALRM)
		switch_timers(1);
77 78
}

79
void alarm_handler(int sig, struct sigcontext *sc)
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
{
	int enabled;

	enabled = signals_enabled;
	if(!signals_enabled){
		if(sig == SIGVTALRM)
			pending |= SIGVTALRM_MASK;
		else pending |= SIGALRM_MASK;

		return;
	}

	block_signals();

	real_alarm_handler(sig, sc);
	set_signals(enabled);
L
Linus Torvalds 已提交
96 97
}

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
void set_sigstack(void *sig_stack, int size)
{
	stack_t stack = ((stack_t) { .ss_flags	= 0,
				     .ss_sp	= (__ptr_t) sig_stack,
				     .ss_size 	= size - sizeof(void *) });

	if(sigaltstack(&stack, NULL) != 0)
		panic("enabling signal stack failed, errno = %d\n", errno);
}

void remove_sigstack(void)
{
	stack_t stack = ((stack_t) { .ss_flags	= SS_DISABLE,
				     .ss_sp	= NULL,
				     .ss_size	= 0 });

	if(sigaltstack(&stack, NULL) != 0)
		panic("disabling signal stack failed, errno = %d\n", errno);
}

118 119
void (*handlers[_NSIG])(int sig, struct sigcontext *sc);

J
Jeff Dike 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
void handle_signal(int sig, struct sigcontext *sc)
{
	unsigned long pending = 0;

	do {
		int nested, bail;

		/*
		 * pending comes back with one bit set for each
		 * interrupt that arrived while setting up the stack,
		 * plus a bit for this interrupt, plus the zero bit is
		 * set if this is a nested interrupt.
		 * If bail is true, then we interrupted another
		 * handler setting up the stack.  In this case, we
		 * have to return, and the upper handler will deal
		 * with this interrupt.
		 */
		bail = to_irq_stack(sig, &pending);
		if(bail)
			return;

		nested = pending & 1;
		pending &= ~1;

		while((sig = ffs(pending)) != 0){
			sig--;
			pending &= ~(1 << sig);
			(*handlers[sig])(sig, sc);
		}

		/* Again, pending comes back with a mask of signals
		 * that arrived while tearing down the stack.  If this
		 * is non-zero, we just go back, set up the stack
		 * again, and handle the new interrupts.
		 */
		if(!nested)
			pending = from_irq_stack(nested);
	} while(pending);
}

160 161
extern void hard_handler(int sig);

162 163 164 165
void set_handler(int sig, void (*handler)(int), int flags, ...)
{
	struct sigaction action;
	va_list ap;
166
	sigset_t sig_mask;
167 168
	int mask;

169 170 171
	handlers[sig] = (void (*)(int, struct sigcontext *)) handler;
	action.sa_handler = hard_handler;

172
	sigemptyset(&action.sa_mask);
173 174 175

	va_start(ap, flags);
	while((mask = va_arg(ap, int)) != -1)
176 177
		sigaddset(&action.sa_mask, mask);
	va_end(ap);
178

179 180 181
	action.sa_flags = flags;
	action.sa_restorer = NULL;
	if(sigaction(sig, &action, NULL) < 0)
182 183 184 185 186 187
		panic("sigaction failed - errno = %d\n", errno);

	sigemptyset(&sig_mask);
	sigaddset(&sig_mask, sig);
	if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
		panic("sigprocmask failed - errno = %d\n", errno);
188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

int change_sig(int signal, int on)
{
	sigset_t sigset, old;

	sigemptyset(&sigset);
	sigaddset(&sigset, signal);
	sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
	return(!sigismember(&old, signal));
}

void block_signals(void)
{
202
	signals_enabled = 0;
J
Jeff Dike 已提交
203 204 205 206 207 208
	/* This must return with signals disabled, so this barrier
	 * ensures that writes are flushed out before the return.
	 * This might matter if gcc figures out how to inline this and
	 * decides to shuffle this code into the caller.
	 */
	mb();
209 210 211 212
}

void unblock_signals(void)
{
213
	int save_pending;
214

215 216
	if(signals_enabled == 1)
		return;
217

218 219 220 221 222 223 224 225 226 227
	/* We loop because the IRQ handler returns with interrupts off.  So,
	 * interrupts may have arrived and we need to re-enable them and
	 * recheck pending.
	 */
	while(1){
		/* Save and reset save_pending after enabling signals.  This
		 * way, pending won't be changed while we're reading it.
		 */
		signals_enabled = 1;

J
Jeff Dike 已提交
228 229 230 231 232
		/* Setting signals_enabled and reading pending must
		 * happen in this order.
		 */
		mb();

233
		save_pending = pending;
J
Jeff Dike 已提交
234 235 236 237 238 239 240 241 242
		if(save_pending == 0){
			/* This must return with signals enabled, so
			 * this barrier ensures that writes are
			 * flushed out before the return.  This might
			 * matter if gcc figures out how to inline
			 * this (unlikely, given its size) and decides
			 * to shuffle this code into the caller.
			 */
			mb();
243
			return;
J
Jeff Dike 已提交
244
		}
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

		pending = 0;

		/* We have pending interrupts, so disable signals, as the
		 * handlers expect them off when they are called.  They will
		 * be enabled again above.
		 */

		signals_enabled = 0;

		/* Deal with SIGIO first because the alarm handler might
		 * schedule, leaving the pending SIGIO stranded until we come
		 * back here.
		 */
		if(save_pending & SIGIO_MASK)
			CHOOSE_MODE_PROC(sig_handler_common_tt,
					 sig_handler_common_skas, SIGIO, NULL);

		if(save_pending & SIGALRM_MASK)
			real_alarm_handler(SIGALRM, NULL);

		if(save_pending & SIGVTALRM_MASK)
			real_alarm_handler(SIGVTALRM, NULL);
	}
269 270 271 272
}

int get_signals(void)
{
273
	return signals_enabled;
274 275 276 277 278
}

int set_signals(int enable)
{
	int ret;
279 280
	if(signals_enabled == enable)
		return enable;
281

282 283 284 285
	ret = signals_enabled;
	if(enable)
		unblock_signals();
	else block_signals();
286

287
	return ret;
288
}