Exemple #1
0
os_result
os_signalHandlerEnableExceptionSignals (
    void)
{
    os_signalHandler _this = signalHandlerObj;
    unsigned i, iException;
    int r;

    if (isSignallingSafe(0) && _this) {

        for (i = 0; i < lengthof(exceptions); i++) {
            const int sig = exceptions[i];
            r = os_sigsetDel(&_this->action.sa_mask, sig);
            if (r < 0) {
                OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                        "os_sigsetDel(0x%"PA_PRIxADDR", %d) failed, result = %d",
                        (os_address)&_this->action, sig, r);
                goto err_exceptionSigSetDel;
            }
        }

        for (iException = 0; iException < lengthof(exceptions); iException++) {
            const int sig = exceptions[iException];
            /* For exceptions we always set our own signal handler, since
             * applications that cause an exception are not in a position
             * to ignore it. However, we will chain the old handler to our
             * own. */
            r = os_sigactionSet(sig, &_this->action, &old_signalHandler[sig]);
            if (r < 0) {
                OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                        "os_sigactionSet(%d, 0x%"PA_PRIxADDR", 0x%"PA_PRIxADDR") failed, result = %d",
                        sig, (os_address)&_this->action, (os_address)&old_signalHandler[sig], r);
                goto err_exceptionSigSet;
            }
        }

        _this->handleExceptions = OS_TRUE;
    }

    return os_resultSuccess;

err_exceptionSigSet:
    while(iException) {
        const int sig = exceptions[--iException];
        r = os_sigactionSet(sig, &old_signalHandler[sig], NULL);
        if (r < 0) {
            OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                      "Failed to restore original handler: os_sigactionSet(%d, 0x%"PA_PRIxADDR", NULL) failed, result = %d",
                       sig, (os_address)&old_signalHandler[sig], r);
        }
    }
err_exceptionSigSetDel:
    /* No undo needed for os_sigsetDel(...) */
    return os_resultFail;
}
Exemple #2
0
void
os_signalHandlerFree(
    void)
{
#if !defined INTEGRITY && !defined VXWORKS_RTP
    int i;
    os_ssize_t r;
    os_signalHandler _this = signalHandlerObj;

    if (isSignallingSafe(0) && _this) {
        if (_this->handleExceptions) {
            for (i=0; i<lengthof(exceptions); i++) {
                const int sig = exceptions[i];
                r = os_sigactionSet(sig, &old_signalHandler[sig], NULL);
                if (r<0) {
                    OS_REPORT(OS_ERROR,
                            "os_signalHandlerFree", 0,
                            "os_sigactionSet(%d, 0x%"PA_PRIxADDR", NULL) failed, result = %"PA_PRIdSIZE,
                            sig, (os_address)&old_signalHandler[sig], r);
                    assert(OS_FALSE);
                }
            }
        }
        for (i=0; i<lengthof(quits); i++) {
            const int sig = quits[i];
            r = os_sigactionSet(sig, &old_signalHandler[sig], NULL);
            if (r<0) {
                OS_REPORT(OS_ERROR,
                        "os_signalHandlerFree", 0,
                        "os_sigactionSet(%d, 0x%"PA_PRIxADDR", NULL) failed, result = %"PA_PRIdSIZE,
                        sig, (os_address)&old_signalHandler[sig], r);
                assert(OS_FALSE);
            }
        }
        os__signalHandlerThreadStop(_this);
        close(_this->pipeIn[0]);
        close(_this->pipeIn[1]);
        close(_this->pipeOut[0]);
        close(_this->pipeOut[1]);

        os__signalHandlerCallbackDeinit(&_this->callbackInfo);

        os_free(_this);
        signalHandlerObj = NULL;
    }
#endif
}
os_result
os_signalHandlerSetHandler(
    os_signal signal,
    os_actionHandler handler)
{
    os_sigset mask;
    os_result result;
    os_sigaction action;
    int r;

    /* block all signals during handling of a signal */
    result = os_sigsetFill(&mask);
    if (result != os_resultSuccess)
    {
        OS_REPORT_2(OS_ERROR,
                    "os_signalHandlerInit", 0,
                    "os_sigsetFill(0x%x) failed, result = %d",
                    &action.sa_mask, result);
    } else
    {
        action = os_sigactionNew(handler, &mask, SA_SIGINFO);
    }
    if (result == os_resultSuccess)
    {
        r = os_sigsetDel(&action.sa_mask, signal);
        if (r < 0)
        {
            OS_REPORT_3(OS_ERROR,
                        "os_signalHandlerInit", 0,
                        "os_sigsetDel(0x%x, %d) failed, result = %d",
                        &action, signal, r);
            result = os_resultFail;
            assert(OS_FALSE);
        }
    }
    if (result == os_resultSuccess)
    {
        r = os_sigactionSet(signal, &action, &old_signalHandler[signal]);
        if (r < 0) {
            OS_REPORT_4(OS_ERROR,
                        "os_signalHandlerInit", 0,
                        "os_sigactionSet(%d, 0x%x, 0x%x) failed, result = %d",
                        signal, &action, &old_signalHandler[signal], r);
            result = os_resultFail;
            assert(OS_FALSE);
        }
    }
    return result;
}
void
os_signalHandlerFree(
    void)
{
#if !defined INTEGRITY && !defined VXWORKS_RTP
    void *thread_result;
    int i, r;
    os_signalHandler _this = signalHandlerObj;
    struct sig_context info;

    if (isSignallingSafe(0) && _this) {
        for (i=0; i<lengthof(exceptions); i++) {
            const int sig = exceptions[i];
            r = os_sigactionSet(sig, &old_signalHandler[sig], NULL);
            if (r<0) {
                OS_REPORT_3(OS_ERROR,
                            "os_signalHandlerFree", 0,
                            "os_sigactionSet(%d, 0x%x, NULL) failed, result = %d",
                            sig, &old_signalHandler[sig], r);
                assert(OS_FALSE);
            }
        }
        memset (&info, 0, sizeof(info));
        info.info.si_signo = SIGNAL_THREAD_STOP;
        r = write(_this->pipeIn[1], &info, sizeof(info));
        /* when signalhandler is the exiting thread itself, this can happen when an exit call is done in the signalhandler of the customer
         * do not call os_threadWaitExit but just let this thread run out of its main function */
        if (os_threadIdSelf() != _this->threadId ) {
            os_threadWaitExit(_this->threadId, &thread_result);
        }
        close(_this->pipeIn[0]);
        close(_this->pipeIn[1]);
        close(_this->pipeOut[0]);
        close(_this->pipeOut[1]);
        os_free(_this);
        signalHandlerObj = NULL;
    }
#endif
}
/**
 * This is the signal-handler routine that is performed in case of a signal. It
 * distinguishes:
 * - synchronous:
 *     - exceptions
 * - asynchronous:
 *     - exceptions
 *     - quits (termination requests).
 *
 * @remarks Do not perform any signal-handling context unsafe operations in this
 * function.
 */
static void
signalHandler(
    int sig,
    siginfo_t *info,
    void* uap)
{
    struct sig_context sync;
    struct sig_context sigInfo;

    sigInfo.info = *info;
#ifdef OS_HAS_UCONTEXT_T
    sigInfo.uc = *(ucontext_t *)uap;
#endif

    /* WARNING: Don't do any async/signalling-unsafe calls here (so refrain from
     * using OS_REPORT_X and the like). */
    if (sigismember(&exceptionsMask, sig) == 1 && sigInfo.info.si_code != SI_USER) {
        os_sigaction *xo;
        /* We have an exception (synchronous) here. The assumption is
         * that exception don't occur in middleware-code, so we can
         * synchronously call the signalHandlerThread in order to detach user-
         * layer from all Domains (kernels). */
        signalHandlerThreadNotify(sigInfo, &sync);
        /* BEWARE: This may be an interleaved handling of an exception, so use
         * sync from now on instead of sigInfo.*/

        /* Reset the original signal-handler. Since the exception was
         * synchronous, running out of this handler will regenerate the signal,
         * which will then be handled by the original signal-handler. */
        xo = &old_signalHandler[sync.info.si_signo];
        os_sigactionSet(sync.info.si_signo, xo, NULL);
    } else {
        /* Pass signal to signal-handler thread for asynchronous handling */
        signalHandlerThreadNotify(sigInfo, NULL);
    }
}
Exemple #6
0
static os_result
os_signalHandlerEnableExitSignals (
    void)
{
    os_signalHandler _this = signalHandlerObj;
    unsigned iExit;
    int r;

    if (isSignallingSafe(0) && _this) {

        for (iExit = 0; iExit < quits_len; iExit++) {
            const int sig = quits[iExit];
            /* By passing NULL we only retrieve the currently set handler. If
             * the signal should be ignored, we don't do anything. Otherwise we
             * chain the old handler to our own.
             * man-page of sigaction only states behaviour when new
             * action is non-NULL, but all known implementations act as
             * expected. That is: return the currently set signal-hand-
             * ler (and not the previous, as the man-pages state).
             * NOTE: Not MT-safe */
            r = os_sigactionSet(sig, NULL, &old_signalHandler[sig]);
            if (r < 0) {
                OS_REPORT(OS_ERROR, "os_signalHandlerEnableQuitSignals", 0,
                        "Could not retrieve currently set signal-handler for signal %d", sig);
                goto err_exitSigSet;
            }
            if(old_signalHandler[sig].sa_handler != SIG_IGN){
                /* We don't know if the oldHandler has been modified in the mean
                 * time, since there is no way to make the signal handler reentrant.
                 * It doesn't make sense to look for modifications now, since a
                 * new modification could be on its way while we are processing
                 * the current modification.
                 * For that reason we will ignore any intermediate modifications
                 * and continue setting our own handler. Processes should therefore
                 * refrain from modifying the signal handler in multiple threads.
                 */
                r = os_sigactionSet(sig, &_this->action, NULL);
                if (r != 0) {
                    OS_REPORT(OS_ERROR, "os_signalHandlerEnableQuitSignals", 0,
                            "os_sigactionSet(%d, 0x%"PA_PRIxADDR", 0x%"PA_PRIxADDR") failed, result = %d",
                            sig, (os_address)&_this->action, (os_address)&old_signalHandler[sig], r);
                    goto err_exitSigSet;
                }
            }
        }
    }

    return os_resultSuccess;

err_exitSigSet:
    while(iExit) {
        const int sig = quits[--iExit];
        r = os_sigactionSet(sig, &old_signalHandler[sig], NULL);
        if (r < 0) {
            OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                "Failed to restore original handler: os_sigactionSet(%d, 0x%"PA_PRIxADDR", NULL) failed, result = %d",
                sig, (os_address)&old_signalHandler[sig], r);
        }
    }

    return os_resultFail;
}
Exemple #7
0
static void *
signalHandlerThread(
    void *arg)
{
    ssize_t r;
    size_t nread;
    int sig, pid;
    struct sig_context info;
    int cont = 1;
    os_signalHandler _this = (os_signalHandler)arg;

    if (_this == NULL) return NULL;

    while (cont) {
        os_report_stack_open(NULL, 0, NULL, NULL);
        nread = 0;
        r = 0;
        while(nread < sizeof(info) && ((r = read(_this->pipeIn[0], &info + nread, sizeof(info) - nread)) > 0)){
            nread += (size_t) r;
        }
        if (r < 0) {
            int errorNr = os_getErrno();
            OS_REPORT(OS_ERROR,
                        "os_signalHandlerThread", 0,
                        "read(_this->pipeIn[0]) failed, error %d: %s",
                        errorNr, os_strError(errorNr));
            assert(OS_FALSE);
            sig = SIGNAL_THREAD_STOP;
        } else {
            sig = info.info.si_signo;
        }
        if(sig != SIGNAL_THREAD_STOP){
            if (sig < 1 || sig >= OS_NSIG) {
                OS_REPORT_NOW(OS_WARNING,
                            "os_signalHandlerThread", 0, info.domainId,
                            "Unexpected signal, value out of range 1-%d: signal = %d",
                            OS_NSIG, sig);
            } else {
                if(sigismember(&exceptionsMask, sig) == 1){
                    if(info.info.si_code == SI_USER || info.info.si_code == SI_QUEUE){
                        /* Sent by kill or sigqueue, so we can report the origin
                         * of the asynchronous delivery. */
                        OS_REPORT_NOW(OS_INFO, "signalHandlerThread", 0, info.domainId,
                            "Synchronous exception (signal %d) asynchronously received from PID %d%s, UID %d",
                            sig,
                            info.info.si_pid,
                            info.info.si_pid == getpid() ? " (self)" : "",
                            info.info.si_uid);
                    } else {
                        OS_REPORT_WID(OS_ERROR, "signalHandlerThread", 0, info.domainId,
                            "Exception (signal %d; 0x%" PA_PRIxADDR "; 0x%" PA_PRIxADDR ") %s in process",
                            sig,
                            (sig == SIGSEGV) ? (os_address)info.info.si_addr : (os_address)0,
                            (os_address)pc_from_ucontext(&info.uc),
                            /* Positive values for si_code are reserved for kernel-
                             * generated signals. This report allows to distinguish
                             * an actual kernel-signal and signals within the process
                             * like from pthread_kill(...) for example. */
                            info.info.si_code > 0 ? "occurred" : "generated");
                    }

                    /* If an exceptionCallback was set, this should always be invoked. The main
                     * goal is to protect SHM in case of an exception, even if a customer
                     * installed a handler as well. */
                    os__signalHandlerExceptionCallbackInvoke(&_this->callbackInfo);
                    if(info.info.si_code == SI_USER){
                        /* Mimic an exception by re-raising it. A random thread received the signal
                         * asynchronously, so when we raise it again another random thread will
                         * receive the signal. */
                        os_sigaction *xo;

                        /* Reset the original signal-handler. */
                        xo = &old_signalHandler[info.info.si_signo];
                        os_sigactionSet(info.info.si_signo, xo, NULL);

                        /* Since the exception was actually asynchronous (issued by an external/soft
                         * source), the original signal-handler will not be called by running
                         * out of the handler. We chain by re-raising, since SIG_DFL or SIG_IGN
                         * cannot be called directly. */
                        /* OSPL-2762: Instead of re-raising we use kill to
                           make sure the signal isn't delivered to this thread
                           as that would cause a dead lock. */
                        pid = getpid();
                        /* Don't think it's possible to not send the signal */
                        OS_REPORT_NOW (OS_DEBUG, "os_signalHandlerThread", 0, info.domainId,
                            "Invoking kill (signal %d) on PID %d (self)",
                            info.info.si_signo, pid);
                        (void)kill (pid, info.info.si_signo);
                    } else {
                        /* Notify waiting signal handler to unblock. */
                        r = write(_this->pipeOut[1], &info, sizeof(info));
                        if (r<0) {
                            int errorNr = os_getErrno();
                            OS_REPORT_WID(OS_ERROR,
                                      "os_signalHandlerThread", 0, info.domainId,
                                      "write(_this->pipeOut[1]) failed, error %d: %s",
                                      errorNr, os_strError(errorNr));
                            assert(OS_FALSE);
                        }
                    }
                } else if (sigismember(&quitsMask, sig) == 1){
                    os_callbackArg cbarg;
                    OS_REPORT_NOW(OS_INFO, "signalHandlerThread", 0, info.domainId,
                        "Termination request (signal %d) received from PID %d%s, UID %d",
                        sig,
                        (info.info.si_code == SI_USER) ? info.info.si_pid : getpid(),
                        (info.info.si_code != SI_USER  || info.info.si_pid == getpid()) ? " (self)" : "",
                        (info.info.si_code == SI_USER) ? info.info.si_uid : getuid());

                    cbarg.sig = (void*)(os_address)sig;

                    /* Quit-signals which were set to SIG_IGN shouldn't have our signal-handler
                     * set at all. */
                    assert(old_signalHandler[sig].sa_handler != SIG_IGN);
                    if(old_signalHandler[sig].sa_handler == SIG_DFL){
                        (void) os__signalHandlerExitRequestCallbackInvoke(&_this->callbackInfo, cbarg);
                    } else {
                        /* Execute the original signal-handler within our safe context. For quit-signals our
                         * own exitRequestCallback is not executed. We don't chain exit-request-handlers. */
                        if ((old_signalHandler[sig].sa_flags & SA_SIGINFO) == SA_SIGINFO) {
#ifdef OS_HAS_UCONTEXT_T
                            old_signalHandler[sig].sa_sigaction(sig, &info.info, &info.uc);
#else
                            old_signalHandler[sig].sa_sigaction(sig, &info.info, NULL);
#endif
                        } else {
                            old_signalHandler[sig].sa_handler(sig);
                        }
                    }
                    os_signalHandlerDeleteDeregisteredExitRequestCallbacks(&_this->callbackInfo);
                } /* Else do nothing */
            }
        } else {
            cont = 0;
        }
        os_report_flush((os_report_stack_size() > 0), "os_signalHandler", __FILE__, __LINE__, -1);
    }
    return NULL;
}
Exemple #8
0
os_result
os_signalHandlerFinishExitRequest(
    os_callbackArg arg)
{
    os_result r = os_resultSuccess;
    int sig = (int)(os_address)arg.sig;
    os_sigaction * xo;

    /* This is a request from the application to round up an (asynchronous)
     * exit-request. */
    if (sig < 1 || sig >= OS_NSIG){
        OS_REPORT(OS_WARNING,
            "os_signalHandlerFinishExitRequest", 0,
            "Callback-arg contains invalid signal, value out of range 1-%d: arg = %d",
            OS_NSIG, sig);
        r = os_resultInvalid;
    } else if (sigismember(&quitsMask, sig) == 0){
#if OS_NSIG >= 100
#error "Worst-case allocation assumes max. signal of 99, which apparently is not correct"
#endif
        /* We know which signal-number exist, all take at most 2 digits + ", ",
         * so allocate worst-case 4 * quits_len */
        char *expected = os_malloc(quits_len * 4 + 1);
        if(expected){
            unsigned i;
            int pos;
            assert(quits_len > 0);
            pos = sprintf(expected, "%d", quits[0]);
            for(i = 1; i < quits_len; i++){
                pos += sprintf(expected + pos, ", %d", quits[i]);
            }
        }
        OS_REPORT(OS_WARNING,
            "os_signalHandlerFinishExitRequest", 0,
            "Unexpected Signal, value out of range: signal = %d. Expected one of %s.",
            sig, expected ? expected : "the asynchronous exit request signals");
        os_free(expected);
        r = os_resultInvalid;
    }

    if(r == os_resultSuccess){
        /* We need to restore the original signal-handler and than re-raise the
         * original signal. */
        xo = &old_signalHandler[sig];
        if(os_sigactionSet(sig, xo, NULL) != 0){
            OS_REPORT(OS_WARNING,
               "os_signalHandlerFinishExitRequest", 0,
               "Resetting original signal handler for signal %d failed, sigaction did not return 0.",sig);
            abort(); /* We were unable to reset the original handler, which is pretty serious. */
        } else {
            os_sigset current_sigset, old_sigset;
            /* Determine the current mask, and make sure that the signal to be
             * raised is not blocked (this code is typically executed in the
             * signalHandlerThread (if callback is implemented synchronously),
             * which blocks all signals). */
            os_sigThreadSetMask(NULL, &current_sigset);
            os_sigsetDel(&current_sigset, sig);
            raise(sig);
            /* Set mask temporarily, this should raise the pending signal set above. */
            os_sigThreadSetMask(&current_sigset, &old_sigset);
            /* Reset the mask to the original state. If this is the signal-
             * HandlerThread this is essential (if sig is handled), otherwise just
             * the proper thing to do. */
            os_sigThreadSetMask(&old_sigset, NULL);
        }
    }
    return r;
}
Exemple #9
0
/**
 * This is the signal-handler routine that is performed in case of a signal. It
 * distinguishes:
 * - synchronous:
 *     - exceptions
 * - asynchronous:
 *     - exceptions
 *     - quits (termination requests).
 *
 * @remarks Do not perform any signal-handling context unsafe operations in this
 * function.
 */
static void
signalHandler(
    int sig,
    siginfo_t *info,
    void* uap)
{
    struct sig_context sync;
    struct sig_context sigInfo;
    os_signalHandlerCallbackInfo *cbInfo = os__signalHandlerGetCallbackInfo();

    /* info can be NULL on Solaris */
    if (info == NULL) {
        /* Pretend that it was an SI_USER signal. */
        memset(&sigInfo.info, 0, sizeof(siginfo_t));
        sigInfo.info.si_signo = sig;
        sigInfo.info.si_code = SI_USER;
        sigInfo.info.si_pid = getpid();
        sigInfo.info.si_uid = getuid();
    } else {
        sigInfo.info = *info;
    }
    sigInfo.ThreadIdSignalRaised = os_threadIdToInteger(os_threadIdSelf());
    sigInfo.domainId = os_reportGetDomain();
#ifdef OS_HAS_UCONTEXT_T
    sigInfo.uc = *(ucontext_t *)uap;
#endif

    /* WARNING: Don't do any async/signalling-unsafe calls here (so refrain from
     * using OS_REPORT_X and the like). */
    if (sigismember(&exceptionsMask, sig) == 1 && sigInfo.info.si_code != SI_USER){
        os_sigaction *xo;

        if (inSignalHandlerThread()) {
            /* The signalHandlerThread caught an exception (synchronous)
             * itself. The fact that the signalHandlerThread caught an
             * exception means there is a bug in the error handling code. */
            const char panicmsg[] = "FATAL ERROR: Synchronously trapped signal in signalHandlerThread\n";
            panic(panicmsg, sizeof(panicmsg) - 1);
            /* This line will not be reached anymore */
        }

        /* Grab the Mutex for the ExceptionHandler stack and hold it during
         * the processing of the exception. This way you avoid handlers
         * being added or removed right in between writing the exception
         * context into the pipe and the signal handler thread reading it
         * and handling it from the pipe. Also you avoid another signal from
         * another thread overwriting our context.
         * To visualize the the duration for this mutex claim, the resulting
         * handler code has been placed in its own (indented) scope.
         */
        {
            os_mutexLock(&cbInfo->exceptionMtx);

            /* Obtain the context of the thread that called the signalHandler.
             * This information will be needed by the callback invoked by the
             * signalHandlerThread, to decide what kind of action needs to
             * be taken.
             */
            os__signalHandlerExceptionGetThreadContextCallbackInvoke(cbInfo);

            /* We have an exception (synchronous) here. The assumption is
             * that exception don't occur in middleware-code, so we can
             * synchronously call the signalHandlerThread in order to detach user-
             * layer from all Domains (kernels). */
            signalHandlerThreadNotify(sigInfo, &sync);

            os_mutexUnlock(&cbInfo->exceptionMtx);
        }

        /* BEWARE: This may be an interleaved handling of an exception, so use
         * sync from now on instead of sigInfo.*/

        /* Reset the original signal-handler. If the exception was synchronous,
         * running out of this handler will regenerate the signal, which will
         * then be handled by the original signal-handler. Otherwise it needs
         * to be re-raised. */
        xo = &old_signalHandler[sync.info.si_signo];
        os_sigactionSet(sync.info.si_signo, xo, NULL);

        /* Positive values are reserved for kernel-generated signals, i.e.,
         * actual synchronous hard errors. The rest are 'soft' errors and thus
         * need to be re-raised. */
        if(sigInfo.info.si_code <= 0){
            raise(sig);
        }
    } else {
        /* Pass signal to signal-handler thread for asynchronous handling */
        os_uint32 index = pa_inc32_nv(&cbInfo->exitRequestInsertionIndex) % EXIT_REQUEST_BUFFER_SIZE;
        os__signalHandlerExitRequestGetThreadContextCallbackInvoke(cbInfo, index);
        signalHandlerThreadNotify(sigInfo, NULL);
    }
}
static os_result
os_signalHandlerInit(
    os_signalHandler _this)
{
    os_result result = os_resultSuccess;
    os_sigaction action;
    os_sigset block_all_sigset, old_sigset;
    int i, r;

    if (_this == NULL) {
        result = os_resultFail;
    }
    _this->exitRequestCallback = (os_signalHandlerExitRequestCallback)0;
    _this->exceptionCallback = (os_signalHandlerExceptionCallback)0;


    if(isSignallingSafe(1)) {
        /* Initialise the exceptionsMask */
        sigemptyset(&exceptionsMask);
        for(i = 0; i < lengthof(exceptions); i++) {
            sigaddset(&exceptionsMask, exceptions[i]);
        }

        /* Initialise the quitsMask */
        sigemptyset(&quitsMask);
        for(i = 0; i < lengthof(quits); i++) {
            sigaddset(&quitsMask, quits[i]);
        }

        /* create signal handling pipes */
        if (result == os_resultSuccess) {
            r = pipe(_this->pipeIn);
            if (r<0) {
                OS_REPORT_1(OS_ERROR,
                            "os_signalHandlerInit", 0,
                            "pipe(_this->pipeIn) failed, result = %d",
                            r);
                result = os_resultFail;
            } else {
                r = fcntl(_this->pipeIn[0], F_SETFD, 1);
                if (r<0) {
                    OS_REPORT_1(OS_WARNING,
                                "os_signalHandlerInit", 0,
                                "fcntl(_this->pipeIn[0]) failed, result = %d", r);
                    assert(OS_FALSE);
                }
                r = fcntl(_this->pipeIn[1], F_SETFD, 1);
                if (r<0) {
                    OS_REPORT_1(OS_WARNING,
                                "os_signalHandlerInit", 0,
                                "fcntl(_this->pipeIn[1]) failed, result = %d", r);
                    assert(OS_FALSE);
                }
            }
        }
        if (result == os_resultSuccess) {
            r = pipe(_this->pipeOut);
            if (r<0) {
                OS_REPORT_1(OS_ERROR,
                            "os_signalHandlerInit", 1,
                            "pipe(_this->pipeOut) failed, result = %d",
                            r);
                result = os_resultFail;
            } else {
                r = fcntl(_this->pipeOut[0], F_SETFD, 1);
                if (r<0) {
                    OS_REPORT_1(OS_WARNING,
                                "os_signalHandlerInit", 0,
                                "fcntl(_this->pipeOut[0]) failed, result = %d",
                                r);
                    assert(OS_FALSE);
                }
                r = fcntl(_this->pipeOut[1], F_SETFD, 1);
                if (r<0) {
                    OS_REPORT_1(OS_WARNING,
                                "os_signalHandlerInit", 0,
                                "fcntl(_this->pipeOut[1]) failed, result = %d",
                                r);
                    assert(OS_FALSE);
                }
            }
        }
        /* Block all signals */
        if (result == os_resultSuccess) {
            result = os_sigsetFill(&block_all_sigset);
            if (result != os_resultSuccess) {
                OS_REPORT_1(OS_ERROR,
                            "os_signalHandlerInit", 0,
                            "os_sigsetFill(&block_all_sigset) failed, result = %d",
                            r);
                assert(OS_FALSE);
            } else {
                result = os_sigThreadSetMask(&block_all_sigset, &old_sigset);
                if (result != os_resultSuccess) {
                    OS_REPORT_3(OS_ERROR,
                                "os_signalHandlerInit", 0,
                                "os_sigThreadSetMask(0x%x, 0x%x) failed, result = %d",
                                &block_all_sigset, &old_sigset, r);
                    assert(OS_FALSE);
                }
            }
        }
        /* Setup signal handler thread. */
        if (result == os_resultSuccess) {
            os_threadAttr thrAttr;

            result = os_threadAttrInit(&thrAttr);
            if (result != os_resultSuccess) {
                OS_REPORT_2(OS_ERROR,
                            "os_signalHandlerInit", 0,
                            "pthread_attr_init(0x%x) failed, result = %d",
                            &thrAttr, r);
                assert(OS_FALSE);
            } else {
                thrAttr.stackSize = 4*1024*1024; /* 4 MB */
                result = os_threadCreate(&_this->threadId,
                                         "signalHandler",
                                         &thrAttr,
                                         signalHandlerThread,
                                         (void*)_this);

                if (result != os_resultSuccess) {
                    OS_REPORT_4(OS_ERROR,
                                "os_signalHandlerInit", 0,
                                "os_threadCreate(0x%x, 0x%x,0x%x,0) failed, result = %d",
                                &_this->threadId,
                                &thrAttr,
                                signalHandlerThread,
                                result);
                    assert(OS_FALSE);
                }
            }
        }
        /* Reset signal mask to original value. */
        if (result == os_resultSuccess) {
            result = os_sigThreadSetMask(&old_sigset, NULL);
            if (result != os_resultSuccess) {
                OS_REPORT_2(OS_ERROR,
                            "os_signalHandlerInit", 0,
                            "os_sigThreadSetMask(0x%x, NULL) failed, result = %d",
                            &old_sigset, r);
                result = os_resultFail;
                assert(OS_FALSE);
            }
        }
        /* install signal handlers */
        if (result == os_resultSuccess) {
            os_sigset mask;
            /* block all signals during handling of a signal */
            result = os_sigsetFill(&mask);
            if (result != os_resultSuccess) {
                OS_REPORT_2(OS_ERROR,
                            "os_signalHandlerInit", 0,
                            "os_sigsetFill(0x%x) failed, result = %d",
                            &action.sa_mask, result);
            } else {
                action = os_sigactionNew(signalHandler, &mask, SA_SIGINFO);
            }
            if (result == os_resultSuccess) {
                for (i=0; i<lengthof(exceptions); i++) {
                    const int sig = exceptions[i];
                    r = os_sigsetDel(&action.sa_mask, sig);
                    if (r<0) {
                        OS_REPORT_3(OS_ERROR,
                                    "os_signalHandlerInit", 0,
                                    "os_sigsetDel(0x%x, %d) failed, result = %d",
                                    &action, sig, r);
                        result = os_resultFail;
                        assert(OS_FALSE);
                    }
                }
            }
            if (result == os_resultSuccess) {
                for (i=0; i<lengthof(exceptions); i++) {
                    const int sig = exceptions[i];
                    /* For exceptions we always set our own signal handler, since
                     * applications that cause an exception are not in a position
                     * to ignore it. However, we will chain the old handler to our
                     * own.
                     */
                    r = os_sigactionSet(sig, &action, &old_signalHandler[sig]);
                    if (r < 0) {
                        OS_REPORT_4(OS_ERROR,
                                    "os_signalHandlerInit", 0,
                                    "os_sigactionSet(%d, 0x%x, 0x%x) failed, result = %d",
                                    sig, &action, &old_signalHandler[sig], r);
                        result = os_resultFail;
                        assert(OS_FALSE);
                    }
                }
            }
            if (result == os_resultSuccess) {
                for (i=0; i<lengthof(quits); i++) {
                    const int sig = quits[i];
                    /* By passing NULL we only retrieve the currently set handler. If
                     * the signal should be ignored, we don't do anything. Otherwise we
                     * chain the old handler to our own.
                     * man-page of sigaction only states behaviour when new
                     * action is non-NULL, but all known implementations act as
                     * expected. That is: return the currently set signal-hand-
                     * ler (and not the previous, as the man-pages state).
                     * NOTE: Not MT-safe */
                    r = os_sigactionSet(sig, NULL, &old_signalHandler[sig]);
                    if (r == 0) {
                        if(old_signalHandler[sig].sa_handler != SIG_IGN) {
                            /* We don't know if the oldHandler has been modified in the mean
                             * time, since there is no way to make the signal handler reentrant.
                             * It doesn't make sense to look for modifications now, since a
                             * new modification could be on its way while we are processing
                             * the current modification.
                             * For that reason we will ignore any intermediate modifications
                             * and continue setting our own handler. Processes should therefore
                             * refrain from modifying the signal handler in multiple threads.
                             */
                            r = os_sigactionSet(sig, &action, NULL);
                            if (r != 0) {
                                OS_REPORT_4(OS_ERROR,
                                            "os_signalHandlerInit", 0,
                                            "os_sigactionSet(%d, 0x%x, 0x%x) failed, result = %d",
                                            sig, &action, &old_signalHandler[sig], r);
                                result = os_resultFail;
                                assert(OS_FALSE);
                            }
                        } else {
                            OS_REPORT_1(OS_INFO,
                                        "os_signalHandlerThread", 0,
                                        "Not installing a signal handler for the already ignored signal %d.",
                                        sig);
                        }
                    } else {
                        OS_REPORT_1(OS_ERROR, "os_signalHandlerInit", 0, "Could not retrieve currently set signal-handler for signal %d", sig);
                        result = os_resultFail;
                        assert(OS_FALSE);
                    }
                }
            }
        }
    } else {
        result = os_resultSuccess;
    }
    return result;
}
static void *
signalHandlerThread(
    void *arg)
{
    ssize_t r;
    size_t nread;
    int sig, pid;
    struct sig_context info;
    int cont = 1;
    os_signalHandler _this = (os_signalHandler)arg;

    if (_this == NULL) return NULL;

    while (cont) {
        nread = 0;
        while(nread < sizeof(info) && ((r = read(_this->pipeIn[0], &info + nread, sizeof(info) - nread)) > 0)) {
            nread += r;
        }
        if (r < 0) {
            int errorNr = errno;
            OS_REPORT_2(OS_ERROR,
                        "os_signalHandlerThread", 0,
                        "read(_this->pipeIn[0]) failed, error %d: %s",
                        errorNr, strerror(errorNr));
            assert(OS_FALSE);
            sig = SIGNAL_THREAD_STOP;
        } else {
            sig = info.info.si_signo;
        }
        if(sig != SIGNAL_THREAD_STOP) {
            if (sig < 1 || sig >= OS_NSIG) {
                OS_REPORT_2(OS_WARNING,
                            "os_signalHandlerThread", 0,
                            "Unexpected signal, value out of range 1-%d: signal = %d",
                            OS_NSIG, sig);
            } else {
                if(sigismember(&exceptionsMask, sig) == 1) {
                    if(info.info.si_code == SI_USER) {
                        OS_REPORT_4(OS_INFO, "signalHandlerThread", 0,
                                    "Synchronous exception (signal %d) asynchronously received from PID %d%s, UID %d",
                                    sig,
                                    info.info.si_pid,
                                    info.info.si_pid == getpid() ? " (self)" : "",
                                    info.info.si_uid);
                    } else {
                        OS_REPORT_1(OS_INFO, "signalHandlerThread", 0,
                                    "Exception (signal %d) occurred in process",
                                    sig);
                    }

                    /* If an exceptionCallback was set, this should always be invoked. The main
                     * goal is to protect SHM in case of an exception, even if a customer
                     * installed a handler as well. */
                    if (_this->exceptionCallback &&
                            (_this->exceptionCallback() != os_resultSuccess)) {
                        OS_REPORT(OS_ERROR,
                                  "os_signalHandlerThread", 0,
                                  "Exception-callback failed");
                    }

                    if(info.info.si_code == SI_USER) {
                        /* Mimic an exception by re-raising it. A random thread received the signal
                         * asynchronously, so when we raise it again another random thread will
                         * receive the signal. */
                        os_sigaction *xo;
                        os_sigset ss;

                        /* Reset the original signal-handler. */
                        xo = &old_signalHandler[info.info.si_signo];
                        os_sigactionSet(info.info.si_signo, xo, NULL);

                        /* Since the exception was actually asynchronous (issued by an external
                         * source), the original signal-handler will not be called by running
                         * out of the handler. We chain by re-raising, since SIG_DFL or SIG_IGN
                         * cannot be called directly. */
                        /* OSPL-2762: Instead of re-raising we use kill to
                           make sure the signal isn't delivered to this thread
                           as that would cause a dead lock. */
                        pid = getpid();
                        /* Don't think it's possible to not send the signal */
                        OS_REPORT_2 (OS_DEBUG, "os_signalHandlerThread", 0,
                                     "Invoking kill (signal %d) on PID %d (self)",
                                     info.info.si_signo, pid);
                        (void)kill (pid, info.info.si_signo);
                    } else {
                        /* Notify waiting signal handler to unblock. */
                        r = write(_this->pipeOut[1], &info, sizeof(info));
                        if (r<0) {
                            int errorNr = errno;
                            OS_REPORT_2(OS_ERROR,
                                        "os_signalHandlerThread", 0,
                                        "write(_this->pipeOut[1]) failed, error %d: %s",
                                        errorNr, strerror(errorNr));
                            assert(OS_FALSE);
                        }
                    }
                } else if (sigismember(&quitsMask, sig) == 1) {
                    os_callbackArg arg;
                    OS_REPORT_4(OS_INFO, "signalHandlerThread", 0,
                                "Termination request (signal %d) received from PID %d%s, UID %d",
                                sig,
                                (info.info.si_code == SI_USER) ? info.info.si_pid : getpid(),
                                (info.info.si_code != SI_USER  || info.info.si_pid == getpid()) ? " (self)" : "",
                                (info.info.si_code == SI_USER) ? info.info.si_uid : getuid());

                    arg.sig = (void*)(os_address)sig;

                    /* Quit-signals which were set to SIG_IGN shouldn't have our signal-handler
                     * set at all. */
                    assert(old_signalHandler[sig].sa_handler != SIG_IGN);
                    if(old_signalHandler[sig].sa_handler == SIG_DFL) {
                        if (_this->exitRequestCallback &&
                                (_this->exitRequestCallback(arg) != os_resultSuccess)) {
                            OS_REPORT(OS_ERROR,
                                      "os_signalHandlerThread", 0,
                                      "Exit request-callback failed");
                        }
                    } else {
                        /* Execute the original signal-handler within our safe context. For quit-signals our
                         * own exitRequestCallback is not executed. We don't chain exit-request-handlers. */
                        if ((old_signalHandler[sig].sa_flags & SA_SIGINFO) == SA_SIGINFO) {
#ifdef OS_HAS_UCONTEXT_T
                            old_signalHandler[sig].sa_sigaction(sig, &info.info, &info.uc);
#else
                            old_signalHandler[sig].sa_sigaction(sig, &info.info, NULL);
#endif
                        } else {
                            old_signalHandler[sig].sa_handler(sig);
                        }
                    }
                } /* Else do nothing */
            }
        } else {
            cont = 0;
        }
    }
    return NULL;
}