signal 5.4 KB
Newer Older
Neil Turton's avatar
Neil Turton committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* Copyright 1996 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* signal.c: ANSI draft (X3J11 Oct 86) library code, section 4.7 */
/* Copyright (C) Codemist Ltd, 1988                              */
/* version 0.01d */

/* N.B. machine dependent messages (only) below. */

#include "hostsys.h"
#include <signal.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>                             /* for exit()            */
#include <errno.h>
#include "kernel.h"

extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
extern int _sprintf_lf(char *buff, const char *fmt, ...);

32 33 34
extern int _SignalNumber(int errnum);
extern _kernel_oserror *_kernel_peek_last_oserror(void);

Neil Turton's avatar
Neil Turton committed
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#define SIGLAST 11  /* one after highest signal number (see <signal.h>) */

static void (*_signalvector[SIGLAST+1])(int);

/* HIDDEN EXPORTS - for compatibility with previous shared C libraries */
extern void __ignore_signal_handler(int sig);
extern void __error_signal_marker(int sig);
extern void __default_signal_handler(int sig);

extern void __ignore_signal_handler(int sig)
{
    /* do this in case called because of SharedCLibrary botch... */
    signal(sig, SIG_IGN);
}

static void _real_default_signal_handler(int sig)
{
Ben Avison's avatar
Ben Avison committed
52
    char *s = NULL, v[128];
53 54 55 56 57 58 59 60
    _kernel_oserror *e = _kernel_peek_last_oserror();

    if (((sig == SIGSEGV || sig == SIGILL) && _SignalNumber(e->errnum) == sig) ||
        sig == SIGFPE || sig == SIGOSERROR)
    {
        _postmortem(e->errmess, *((int *)"mesg"));
        return;
    }
Neil Turton's avatar
Neil Turton committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

    switch (sig)
    {
case SIGABRT:
#ifdef DEFAULT_TEXT
        s = "Abnormal termination (e.g. abort() function)";
#endif
        s = _kernel_getmessage(s, "C39");
        break;
case SIGILL:
#ifdef DEFAULT_TEXT
#ifdef __arm
        s = "Illegal instruction (call to non-function/code corrupted) [is the floating point emulator loaded?]";
#else
        s = "Illegal instruction (call to non-function/code corrupted)";
#endif
#endif
        s = _kernel_getmessage(s, "C40");
        break;
case SIGINT:
#ifdef DEFAULT_TEXT
        s = "Interrupt received from user - program terminated";
#endif
        _sys_msg(_kernel_getmessage(s, "C41"));
        exit(EXIT_FAILURE);
        break;
case SIGSEGV:
#ifdef DEFAULT_TEXT
        s = "Illegal address (e.g. wildly outside array bounds)";
#endif
        s = _kernel_getmessage(s, "C42");
        break;
case SIGTERM:
#ifdef DEFAULT_TEXT
        s = "Termination request received";
#endif
        s = _kernel_getmessage(s, "C43");
        break;
default:
#ifdef DEFAULT_TEXT
        s = "Unknown signal number %d";
#endif
        s = _kernel_getmessage(s, "C44");
        break;
    }
    _sprintf_lf(v, s, sig);
    _postmortem(v, *((int *)"mesg"));
}

#pragma -s1

#if 0
/* Stack overflow is either a normal exception in which case it should just
 * exit with an error return or a fatal system error in which case it shoul
 * generate an external error. I choose the latter. ECN
 */
static void _default_sigstak_handler()
{
    char *s = "Stack overflow\n\r";
    while (*s!=0) _kernel_oswrch(*s++);
    _kernel_setreturncode(100);
    _kernel_exit(100);
}
#else
125
extern void _default_sigstak_handler(void);
Neil Turton's avatar
Neil Turton committed
126 127 128 129
#endif

extern void __default_signal_handler(int sig)
{
130
    if (_kernel_processor_mode() & 0xF)
Neil Turton's avatar
Neil Turton committed
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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        _kernel_exit((int)(_kernel_last_oserror()));
    else if (sig==SIGSTAK)
      _default_sigstak_handler();
    else
      _real_default_signal_handler(sig);
}

extern void __error_signal_marker(int sig)
/* This function should NEVER be called - its value is used as a marker     */
/* return from signal (SIG_ERR).   If someone manages to use pass this      */
/* value back to signal and thence get it invoked we make it behave as      */
/* if signal got SIG_DFL:                                                   */
{
    __default_signal_handler(sig);
}

int raise(int sig)
{
    void (*handler)(int);
    if (sig<=0 || sig>=SIGLAST) return (errno = ESIGNUM);
    handler = _signalvector[sig];
    /* Mustn't call default_signal_handler via _kernel_call_client unless */
    /* it really is on the other side of the compatibility veneer.        */
    if (handler==__SIG_DFL)
        (*__default_signal_handler)(sig);
    else if (handler!=__SIG_IGN)
    {   _signalvector[sig] = __SIG_DFL;
        /* And this will fail for old clients setting SIG_IGN across */
        /* the compatibility veneer... Oh yuk yuk yuk...             */
        _call_client_1(handler, sig);
    }
    return 0;
}

int _signal_real_handler(int sig)
{
    if (sig<=0 || sig>=SIGLAST) return 0;
    return (_signalvector[sig]!=__SIG_DFL);
}

#pragma -s0

void (*signal(int sig, void (*func)(int)))(int)
{
    void (*oldf)(int);
    if (sig<=0 || sig>=SIGLAST) return __SIG_ERR;
    oldf = _signalvector[sig];
    _signalvector[sig] = func;
    return oldf;
}

Ben Avison's avatar
Ben Avison committed
182
void _signal_init(void)
Neil Turton's avatar
Neil Turton committed
183 184 185 186 187 188 189
{
    int i;
    /* do the following initialisation explicitly so code restartable */
    for (i=1; i<SIGLAST; i++) signal(i, __SIG_DFL);
}

/* end of signal.c */