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/barrier.h" 19 #include "sigcontext.h" 20 #include "mode.h" 21 #include "os.h" 22 23 /* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled 24 * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to 25 * be able to profile all of UML, not just the non-critical sections. If 26 * profiling is not thread-safe, then that is not my problem. We can disable 27 * profiling when SMP is enabled in that case. 28 */ 29 #define SIGIO_BIT 0 30 #define SIGIO_MASK (1 << SIGIO_BIT) 31 32 #define SIGVTALRM_BIT 1 33 #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) 34 35 #define SIGALRM_BIT 2 36 #define SIGALRM_MASK (1 << SIGALRM_BIT) 37 38 /* These are used by both the signal handlers and 39 * block/unblock_signals. I don't want modifications cached in a 40 * register - they must go straight to memory. 41 */ 42 static volatile int signals_enabled = 1; 43 static volatile int pending = 0; 44 45 void sig_handler(int sig, struct sigcontext *sc) 46 { 47 int enabled; 48 49 enabled = signals_enabled; 50 if(!enabled && (sig == SIGIO)){ 51 pending |= SIGIO_MASK; 52 return; 53 } 54 55 block_signals(); 56 57 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, 58 sig, sc); 59 60 set_signals(enabled); 61 } 62 63 static void real_alarm_handler(int sig, struct sigcontext *sc) 64 { 65 if(sig == SIGALRM) 66 switch_timers(0); 67 68 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, 69 sig, sc); 70 71 if(sig == SIGALRM) 72 switch_timers(1); 73 74 } 75 76 void alarm_handler(int sig, struct sigcontext *sc) 77 { 78 int enabled; 79 80 enabled = signals_enabled; 81 if(!signals_enabled){ 82 if(sig == SIGVTALRM) 83 pending |= SIGVTALRM_MASK; 84 else pending |= SIGALRM_MASK; 85 86 return; 87 } 88 89 block_signals(); 90 91 real_alarm_handler(sig, sc); 92 set_signals(enabled); 93 } 94 95 void set_sigstack(void *sig_stack, int size) 96 { 97 stack_t stack = ((stack_t) { .ss_flags = 0, 98 .ss_sp = (__ptr_t) sig_stack, 99 .ss_size = size - sizeof(void *) }); 100 101 if(sigaltstack(&stack, NULL) != 0) 102 panic("enabling signal stack failed, errno = %d\n", errno); 103 } 104 105 void remove_sigstack(void) 106 { 107 stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, 108 .ss_sp = NULL, 109 .ss_size = 0 }); 110 111 if(sigaltstack(&stack, NULL) != 0) 112 panic("disabling signal stack failed, errno = %d\n", errno); 113 } 114 115 void (*handlers[_NSIG])(int sig, struct sigcontext *sc); 116 117 extern void hard_handler(int sig); 118 119 void set_handler(int sig, void (*handler)(int), int flags, ...) 120 { 121 struct sigaction action; 122 va_list ap; 123 sigset_t sig_mask; 124 int mask; 125 126 handlers[sig] = (void (*)(int, struct sigcontext *)) handler; 127 action.sa_handler = hard_handler; 128 129 sigemptyset(&action.sa_mask); 130 131 va_start(ap, flags); 132 while((mask = va_arg(ap, int)) != -1) 133 sigaddset(&action.sa_mask, mask); 134 va_end(ap); 135 136 action.sa_flags = flags; 137 action.sa_restorer = NULL; 138 if(sigaction(sig, &action, NULL) < 0) 139 panic("sigaction failed - errno = %d\n", errno); 140 141 sigemptyset(&sig_mask); 142 sigaddset(&sig_mask, sig); 143 if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) 144 panic("sigprocmask failed - errno = %d\n", errno); 145 } 146 147 int change_sig(int signal, int on) 148 { 149 sigset_t sigset, old; 150 151 sigemptyset(&sigset); 152 sigaddset(&sigset, signal); 153 sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); 154 return(!sigismember(&old, signal)); 155 } 156 157 void block_signals(void) 158 { 159 signals_enabled = 0; 160 /* This must return with signals disabled, so this barrier 161 * ensures that writes are flushed out before the return. 162 * This might matter if gcc figures out how to inline this and 163 * decides to shuffle this code into the caller. 164 */ 165 mb(); 166 } 167 168 void unblock_signals(void) 169 { 170 int save_pending; 171 172 if(signals_enabled == 1) 173 return; 174 175 /* We loop because the IRQ handler returns with interrupts off. So, 176 * interrupts may have arrived and we need to re-enable them and 177 * recheck pending. 178 */ 179 while(1){ 180 /* Save and reset save_pending after enabling signals. This 181 * way, pending won't be changed while we're reading it. 182 */ 183 signals_enabled = 1; 184 185 /* Setting signals_enabled and reading pending must 186 * happen in this order. 187 */ 188 mb(); 189 190 save_pending = pending; 191 if(save_pending == 0){ 192 /* This must return with signals enabled, so 193 * this barrier ensures that writes are 194 * flushed out before the return. This might 195 * matter if gcc figures out how to inline 196 * this (unlikely, given its size) and decides 197 * to shuffle this code into the caller. 198 */ 199 mb(); 200 return; 201 } 202 203 pending = 0; 204 205 /* We have pending interrupts, so disable signals, as the 206 * handlers expect them off when they are called. They will 207 * be enabled again above. 208 */ 209 210 signals_enabled = 0; 211 212 /* Deal with SIGIO first because the alarm handler might 213 * schedule, leaving the pending SIGIO stranded until we come 214 * back here. 215 */ 216 if(save_pending & SIGIO_MASK) 217 CHOOSE_MODE_PROC(sig_handler_common_tt, 218 sig_handler_common_skas, SIGIO, NULL); 219 220 if(save_pending & SIGALRM_MASK) 221 real_alarm_handler(SIGALRM, NULL); 222 223 if(save_pending & SIGVTALRM_MASK) 224 real_alarm_handler(SIGVTALRM, NULL); 225 } 226 } 227 228 int get_signals(void) 229 { 230 return signals_enabled; 231 } 232 233 int set_signals(int enable) 234 { 235 int ret; 236 if(signals_enabled == enable) 237 return enable; 238 239 ret = signals_enabled; 240 if(enable) 241 unblock_signals(); 242 else block_signals(); 243 244 return ret; 245 } 246