signal 5.13 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 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 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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/* 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, ...);

#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)
{
    char *s, v[128];

    switch (sig)
    {
case SIGABRT:
#ifdef DEFAULT_TEXT
        s = "Abnormal termination (e.g. abort() function)";
#endif
        s = _kernel_getmessage(s, "C39");
        break;
case SIGFPE:
case SIGOSERROR:
        s = &(_kernel_last_oserror()->errmess[0]);
        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
extern void _default_sigstak_handler();
#endif

extern void __default_signal_handler(int sig)
{
    if (_kernel_processor_mode() != 0)
        _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;
}

void _signal_init()
{
    int i;
    /* do the following initialisation explicitly so code restartable */
    for (i=1; i<SIGLAST; i++) signal(i, __SIG_DFL);
}

/* end of signal.c */