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