1/* 2 Title: Signal handling 3 Author: David C.J. Matthews 4 5 Copyright (c) 2000-8, 2016 David C.J. Matthews 6 7 This library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License version 2.1 as published by the Free Software Foundation. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 20*/ 21#ifdef HAVE_CONFIG_H 22#include "config.h" 23#elif defined(_WIN32) 24#include "winconfig.h" 25#else 26#error "No configuration file" 27#endif 28 29#ifdef HAVE_STDIO_H 30#include <stdio.h> 31#endif 32 33#ifdef HAVE_SYS_TYPES_H 34#include <sys/types.h> 35#endif 36 37#ifdef HAVE_SIGNAL_H 38#include <signal.h> 39#endif 40 41#ifdef HAVE_ERRNO_H 42#include <errno.h> 43#endif 44 45#ifdef HAVE_ASSERT_H 46#include <assert.h> 47#define ASSERT(x) assert(x) 48#else 49#define ASSERT(x) 0 50#endif 51 52#ifdef HAVE_STRING_H 53#include <string.h> 54#endif 55 56#ifdef HAVE_IO_H 57#include <io.h> 58#endif 59 60#ifdef HAVE_UNISTD_H 61#include <unistd.h> 62#endif 63 64#ifdef HAVE_STDLIB_H 65#include <stdlib.h> // For malloc 66#endif 67 68#if ((!defined(_WIN32) || defined(__CYGWIN__)) && defined(HAVE_SEMAPHORE_H)) 69// Don't include semaphore.h on Mingw. It's provided but doesn't compile. 70#include <semaphore.h> 71#endif 72 73#if ((!defined(_WIN32) || defined(__CYGWIN__)) && defined(HAVE_LIBPTHREAD) && defined(HAVE_PTHREAD_H) && defined(HAVE_SEMAPHORE_H)) 74// If we have the pthread library and header and we have semaphores we can use the pthread 75// signalling mechanism. But if this is a native Windows build we don't use semaphores or 76// pthread even if they're provided. 77#define USE_PTHREAD_SIGNALS 1 78#endif 79 80#if (defined(_WIN32) && ! defined(__CYGWIN__)) 81#define INVALIDSIGNAL ERROR_INVALID_PARAMETER 82#else 83#define INVALIDSIGNAL EINVAL 84#endif 85/* 86Signal handling is complicated in a multi-threaded environment. 87The pthread mutex and condition variables are not safe to use in a 88signal handler so we need to use POSIX semaphores since sem_post is safe. 89*/ 90 91 92#if (defined(HAVE_STACK_T) && defined(HAVE_SIGALTSTACK)) 93extern "C" { 94// This is missing in older versions of Mac OS X 95int sigaltstack(const stack_t *, stack_t *); 96} 97#endif 98 99#include "globals.h" 100#include "arb.h" 101#include "run_time.h" 102#include "sighandler.h" 103#include "processes.h" 104#include "machine_dep.h" 105#include "sys.h" 106#include "save_vec.h" 107#include "rts_module.h" 108#include "gc.h" // For convertedWeak 109#include "scanaddrs.h" 110#include "locking.h" 111#include "rtsentry.h" 112 113#if (defined(_WIN32) && ! defined(__CYGWIN__)) 114#include "Console.h" 115#endif 116 117extern "C" { 118 POLYEXTERNALSYMBOL POLYUNSIGNED PolySetSignalHandler(PolyObject *threadId, PolyWord signalNo, PolyWord action); 119 POLYEXTERNALSYMBOL POLYUNSIGNED PolyWaitForSignal(PolyObject *threadId); 120} 121 122#define SAVE(x) taskData->saveVec.push(x) 123#define SIZEOF(x) (sizeof(x)/sizeof(word)) 124 125#define DEFAULT_SIG 0 126#define IGNORE_SIG 1 127#define HANDLE_SIG 2 // This is only used in SignalRequest 128 129static struct _sigData 130{ 131 bool nonMaskable; // True if this sig is used within the RTS. Must not be ignored or replaced 132 PolyWord handler; // User-installed handler, TAGGED(DEFAULT_SIG) or TAGGED(IGNORE_SIG) 133 int signalCount; 134} sigData[NSIG]; 135 136unsigned receivedSignalCount = 0; // Incremented each time we get a signal 137 138// sigLock protects access to the signalCount values in sigData but 139// not the "handler" field. 140static PLock sigLock; 141 142#ifdef USE_PTHREAD_SIGNALS 143static PSemaphore *waitSema; 144static int lastSignals[NSIG]; 145static bool terminate = false; 146#endif 147 148 149// This must not be called from an asynchronous signal handler. 150static void signalArrived(int sig) 151{ 152 sigLock.Lock(); 153 receivedSignalCount++; 154 sigData[sig].signalCount++; 155 sigLock.Unlock(); 156 // To avoid deadlock we must release sigLock first. 157 processes->SignalArrived(); 158} 159 160// Called whenever a signal handler is installed other than in this 161// module. Because modules are initialised in an unspecified order 162// we may have already masked off this signal. 163void markSignalInuse(int sig) 164{ 165 sigData[sig].nonMaskable = true; 166#ifdef USE_PTHREAD_SIGNALS 167 // Enable this signal. 168 sigset_t sigset; 169 sigemptyset(&sigset); 170 sigaddset(&sigset, sig); 171 pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); 172#endif 173} 174 175/* Find the existing handler for this signal. */ 176static PolyWord findHandler(int sig) 177{ 178 if ((unsigned)sig >= NSIG) // Check it's in range. 179 return TAGGED(DEFAULT_SIG); /* Not there - default action. */ 180 else return sigData[sig].handler; 181} 182 183#if (defined(_WIN32) && ! defined(__CYGWIN__)) 184// This is called to simulate a SIGINT in Windows. 185void RequestConsoleInterrupt(void) 186{ 187 // The default action for SIGINT is to exit. 188 if (findHandler(SIGINT) == TAGGED(DEFAULT_SIG)) 189 processes->RequestProcessExit(2); // Exit with the signal value. 190 else signalArrived(SIGINT); 191} 192#endif 193 194#ifdef USE_PTHREAD_SIGNALS 195// Request the main thread to change the blocking state of a signal. 196class SignalRequest: public MainThreadRequest 197{ 198public: 199 SignalRequest(int s, int r): MainThreadRequest(MTP_SIGHANDLER), signl(s), state(r) {} 200 201 virtual void Perform(); 202 int signl, state; 203}; 204 205// Called whenever a signal is received. 206static void handle_signal(SIG_HANDLER_ARGS(s, c)) 207{ 208 if (waitSema != 0) 209 { 210 lastSignals[s]++; // Assume this is atomic with respect to reading. 211 // Wake the signal detection thread. 212 waitSema->Signal(); 213 } 214} 215 216void SignalRequest::Perform() 217{ 218 struct sigaction action; 219 memset(&action, 0, sizeof(action)); 220 221 switch (state) 222 { 223 case DEFAULT_SIG: 224 action.sa_handler = SIG_DFL; 225 sigaction(signl, &action, 0); 226 break; 227 case IGNORE_SIG: 228 action.sa_handler = SIG_IGN; 229 sigaction(signl, &action, 0); 230 break; 231 case HANDLE_SIG: 232 setSignalHandler(signl, handle_signal); 233 break; 234 } 235} 236#endif 237 238static Handle waitForSignal(TaskData *taskData) 239{ 240 while (true) 241 { 242 processes->ProcessAsynchRequests(taskData); // Check for kill. 243 sigLock.Lock(); 244 // Any pending signals? 245 for (int sig = 0; sig < NSIG; sig++) 246 { 247 if (sigData[sig].signalCount > 0) 248 { 249 sigData[sig].signalCount--; 250 if (!IS_INT(findHandler(sig))) /* If it's not DEFAULT or IGNORE. */ 251 { 252 // Create a pair of the handler and signal and pass 253 // them back to be run. 254 Handle pair = alloc_and_save(taskData, 2); 255 // Have to call findHandler again here because that 256 // allocation could have garbage collected. 257 DEREFHANDLE(pair)->Set(0, findHandler(sig)); 258 DEREFHANDLE(pair)->Set(1, TAGGED(sig)); 259 sigLock.Unlock(); 260 return pair; 261 } 262 } 263 } 264 if (convertedWeak) 265 { 266 // Last GC converted a weak SOME into NONE. This isn't 267 // anything to do with signals but the signal thread can 268 // deal with this. 269 sigLock.Unlock(); 270 convertedWeak = false; 271 return SAVE(TAGGED(0)); 272 } 273 // No pending signal. Wait until we're woken up. 274 // This releases sigLock after acquiring schedLock. 275 if (! processes->WaitForSignal(taskData, &sigLock)) 276 raise_exception_string(taskData, EXC_Fail, "Only one thread may wait for signals"); 277 } 278} 279 280POLYUNSIGNED PolySetSignalHandler(PolyObject *threadId, PolyWord signalNo, PolyWord action) 281{ 282 TaskData *taskData = TaskData::FindTaskForId(threadId); 283 ASSERT(taskData != 0); 284 taskData->PreRTSCall(); 285 Handle reset = taskData->saveVec.mark(); 286 Handle pushedAction = taskData->saveVec.push(action); 287 Handle oldaction = 0; 288 289 try { 290 { 291 int sign; 292 int action; 293 { 294 // Lock while we look at the signal vector but release 295 // it before making a root request. 296 PLocker locker(&sigLock); 297 // We have to pass this to the main thread to 298 // set up the signal handler. 299 sign = get_C_int(taskData, signalNo); 300 /* Decode the action if it is Ignore or Default. */ 301 if (pushedAction->Word().IsTagged()) 302 action = (int)pushedAction->Word().UnTagged(); 303 else action = HANDLE_SIG; /* Set the handler. */ 304 if (sign <= 0 || sign >= NSIG) 305 raise_syscall(taskData, "Invalid signal value", INVALIDSIGNAL); 306 307 /* Get the old action before updating the vector. */ 308 oldaction = SAVE(findHandler(sign)); 309 // Now update it. 310 sigData[sign].handler = pushedAction->Word(); 311 } 312 313 // Request a change in the masking by the root thread. 314 // This doesn't do anything in Windows so the only "signal" 315 // we affect is SIGINT and that is handled by RequestConsoleInterrupt. 316 if (! sigData[sign].nonMaskable) 317 { 318#ifdef USE_PTHREAD_SIGNALS 319 SignalRequest request(sign, action); 320 processes->MakeRootRequest(taskData, &request); 321#endif 322 } 323 } 324 325 } catch (...) { } // If an ML exception is raised 326 327 taskData->saveVec.reset(reset); 328 taskData->PostRTSCall(); 329 if (oldaction == 0) return TAGGED(0).AsUnsigned(); 330 else return oldaction->Word().AsUnsigned(); 331 332} 333 334// Called by the signal handler thread. Blocks until a signal is available. 335POLYUNSIGNED PolyWaitForSignal(PolyObject *threadId) 336{ 337 TaskData *taskData = TaskData::FindTaskForId(threadId); 338 ASSERT(taskData != 0); 339 taskData->PreRTSCall(); 340 Handle reset = taskData->saveVec.mark(); 341 Handle result = 0; 342 343 try { 344 result = waitForSignal(taskData); 345 } 346 catch (KillException &) { 347 processes->ThreadExit(taskData); // May test for kill 348 } 349 catch (...) { } // If an ML exception is raised 350 351 taskData->saveVec.reset(reset); 352 taskData->PostRTSCall(); 353 if (result == 0) return TAGGED(0).AsUnsigned(); 354 else return result->Word().AsUnsigned(); 355} 356 357// Set up per-thread signal data: basically signal stack. 358// This is really only needed for profiling timer signals. 359void initThreadSignals(TaskData *taskData) 360{ 361#if (!(defined(_WIN32)||defined(MACOSX))) 362 // On the i386, at least, we need to set up a signal stack for 363 // each thread if it might receive a signal. ML code checks for 364 // stack overflow but a signal could result in C code being 365 // executed on the ML stack. The signal stack avoids this. 366 // On some architectures the C stack pointer is left unused 367 // when executing ML code so this isn't a problem. 368 // In Linux each thread can receive a SIGVTALRM signal when 369 // profiling. 370 // This is currently disabled in Mac OS X. In 10.4 and before 371 // setting a signal stack in a thread seemed to set it for the 372 // whole process and crash with an illegal instruction on the 373 // second signal. This isn't currently a problem since only the 374 // main thread receives signals in Mac OS X. 375#if (defined(SA_ONSTACK) && defined(HAVE_SIGALTSTACK)) 376 taskData->signalStack = malloc(SIGSTKSZ); 377#ifdef HAVE_STACK_T 378 stack_t ex_stack; 379#else 380 // This used to be used in FreeBSD and Mac OS X 381 struct sigaltstack ex_stack; 382#endif 383 memset(&ex_stack, 0, sizeof(ex_stack)); 384 // Cast to char* because ss_sp is char* in FreeBSD. 385 // Linux simply casts it back to void*. 386 ex_stack.ss_sp = (char*)taskData->signalStack; 387 ex_stack.ss_size = SIGSTKSZ; 388 ex_stack.ss_flags = 0; /* not SS_DISABLE */ 389 int sigaltstack_result = sigaltstack(&ex_stack, NULL); 390 ASSERT(sigaltstack_result == 0); 391#endif 392#endif /* not the PC */ 393#ifdef USE_PTHREAD_SIGNALS 394 // Block all signals except those marked as in use by the RTS so 395 // that they will only be picked up by the signal detection thread. 396 // Since the signal mask is inherited we really don't need to do 397 // this for every thread, just the initial one. 398 sigset_t sigset; 399 sigfillset(&sigset); 400 for (int i = 0; i < NSIG; i++) 401 { 402 if (sigData[i].nonMaskable) 403 sigdelset(&sigset, i); 404 } 405 pthread_sigmask(SIG_SETMASK, &sigset, NULL); 406#endif 407} 408 409 410/* General purpose function to set up a signal handler. */ 411#if (!defined(_WIN32) || defined(__CYGWIN__)) 412 413bool setSignalHandler(int sig, signal_handler_type func) 414{ 415 struct sigaction sigcatch; 416 memset(&sigcatch, 0, sizeof(sigcatch)); 417 sigcatch.sa_sigaction = func; 418 419 /* 420 Both Linux and FreeBSD now use SA_SIGINFO in a similar way. If SA_SIGINFO is set the 421 handler is supposed to be in sa_sigaction rather than sa_handler (actually this is a union 422 so they're in the same place). 423 */ 424 425 init_asyncmask(&sigcatch.sa_mask); 426 sigcatch.sa_flags = 0; 427#if defined(SA_ONSTACK) && defined(HAVE_SIGALTSTACK) 428 sigcatch.sa_flags |= SA_ONSTACK; 429#endif 430#ifdef SA_RESTART 431 sigcatch.sa_flags |= SA_RESTART; 432#endif 433#ifdef SA_SIGINFO 434 sigcatch.sa_flags |= SA_SIGINFO; 435#endif 436#ifdef SV_SAVE_REGS 437 sigcatch.sa_flags |= SV_SAVE_REGS; 438#endif 439 440 return sigaction(sig, &sigcatch,NULL) >= 0; 441} 442 443// Signals to mask off when handling a signal. The signal being handled 444// is always masked off. This really only applied when emulation traps 445// and requests to GC involved signals. That no longer applies except 446// on the Sparc. 447void init_asyncmask(sigset_t *mask) 448{ 449 /* disable asynchronous interrupts while servicing interrupt */ 450 sigemptyset(mask); 451 sigaddset(mask,SIGVTALRM); 452 sigaddset(mask,SIGINT); 453 sigaddset(mask,SIGUSR2); 454 sigaddset(mask,SIGWINCH); 455 456 // This next used to be needed when emulation traps resulted in 457 // signals. This no longer applies except on the Sparc. 458#ifdef SPARC 459 sigaddset(mask,SIGILL); 460 sigaddset(mask,SIGFPE); 461 /* Mask off SIGSEGV. This is definitely needed when we are 462 installing a handler for SIGINT under Linux and may also 463 be needed in other cases as well e.g. SIGVTALRM. Without 464 it typing control-C to a program which is taking lots 465 of emulation traps can cause a crash because the signals 466 are delivered in the "wrong" order and the pc value given 467 to catchSEGV can point at the handler for SIGINT. 468 DCJM 7/2/01. */ 469 sigaddset(mask,SIGSEGV); 470 /* And, just to be sure, include SIGBUS. DCJM 22/5/02. */ 471 sigaddset(mask,SIGBUS); 472#endif 473} 474 475#endif 476 477struct _entrypts sigHandlerEPT[] = 478{ 479 { "PolySetSignalHandler", (polyRTSFunction)&PolySetSignalHandler}, 480 { "PolyWaitForSignal", (polyRTSFunction)&PolyWaitForSignal}, 481 482 { NULL, NULL} // End of list. 483}; 484 485class SigHandler: public RtsModule 486{ 487public: 488 virtual void Init(void); 489 virtual void Stop(void); 490 virtual void GarbageCollect(ScanAddress * /*process*/); 491 492#ifdef USE_PTHREAD_SIGNALS 493 SigHandler() { threadRunning = false; } 494 pthread_t detectionThreadId; 495 bool threadRunning; 496#endif 497}; 498 499// Declare this. It will be automatically added to the table. 500static SigHandler sighandlerModule; 501 502#ifdef USE_PTHREAD_SIGNALS 503// This thread is really only to convert between POSIX semaphores and 504// pthread condition variables. It waits for a semphore to be released by the 505// signal handler running on the main thread and then wakes up the ML handler 506// thread. The ML thread must not wait directly on a POSIX semaphore because it 507// may also be woken by other events, particularly a kill request when the program 508// exits. 509static void *SignalDetectionThread(void *) 510{ 511 // Block all signals so they will be delivered to the main thread. 512 sigset_t active_signals; 513 sigfillset(&active_signals); 514 pthread_sigmask(SIG_SETMASK, &active_signals, NULL); 515 int readSignals[NSIG] = {0}; 516 517 while (true) 518 { 519 if (waitSema == 0) 520 return 0; 521 // Wait until we are woken up by an arriving signal. 522 // waitSema will be incremented for each signal so we should 523 // not block until we have processed them all. 524 if (! waitSema->Wait() || terminate) return 0; 525 526 for (int j = 1; j < NSIG; j++) 527 { 528 if (readSignals[j] < lastSignals[j]) 529 { 530 readSignals[j]++; 531 signalArrived(j); 532 } 533 } 534 } 535} 536#endif 537 538void SigHandler::Init(void) 539{ 540 // Mark certain signals as non-maskable since they really 541 // indicate a fatal error. 542#ifdef SIGSEGV 543 sigData[SIGSEGV].nonMaskable = true; 544#endif 545#ifdef SIGBUS 546 sigData[SIGBUS].nonMaskable = true; 547#endif 548#ifdef SIGILL 549 sigData[SIGILL].nonMaskable = true; 550#endif 551#ifdef USE_PTHREAD_SIGNALS 552 static PSemaphore waitSemaphore; 553 // Initialise the "wait" semaphore so that it blocks immediately. 554 if (! waitSemaphore.Init(0, NSIG)) return; 555 waitSema = &waitSemaphore; 556 // Create a new thread to handle signals synchronously. 557 // for it to finish. 558 pthread_attr_t attrs; 559 pthread_attr_init(&attrs); 560#ifdef PTHREAD_STACK_MIN 561#if (PTHREAD_STACK_MIN < 4096) 562 pthread_attr_setstacksize(&attrs, 4096); // But not too small: FreeBSD makes it 2k 563#else 564 pthread_attr_setstacksize(&attrs, PTHREAD_STACK_MIN); // Only small stack. 565#endif 566#endif 567 threadRunning = pthread_create(&detectionThreadId, &attrs, SignalDetectionThread, 0) == 0; 568 pthread_attr_destroy(&attrs); 569#endif 570} 571 572// Wait for the signal thread to finish before the semaphore is deleted in the 573// final clean-up. Failing to do this causes a hang in Mac OS X. 574void SigHandler::Stop(void) 575{ 576#ifdef USE_PTHREAD_SIGNALS 577 terminate = true; 578 waitSema->Signal(); 579 pthread_join(detectionThreadId, NULL); 580#endif 581} 582 583void SigHandler::GarbageCollect(ScanAddress *process) 584{ 585 for (unsigned i = 0; i < NSIG; i++) 586 { 587 if (sigData[i].handler != PolyWord::FromUnsigned(0)) 588 process->ScanRuntimeWord(&sigData[i].handler); 589 } 590} 591