text: /*
   *                         Vortex OpenSplice
   *
   *   This software and documentation are Copyright 2006 to TO_YEAR ADLINK
   *   Technology Limited, its affiliated companies and licensors. All rights
   *   reserved.
   *
   *   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.
   *
   */
  
  #include "os_signalHandler.h"
  #include "../common/include/os_signalHandlerCallback.h"
  
  #include "os_errno.h"
  #include "os_heap.h"
  #include "os_stdlib.h"
  
  #include <sys/types.h>
  #include <sys/mman.h>
  #include <sys/wait.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <string.h>
  #include <assert.h>
  #include <sched.h>
  #ifndef __Lynx__
  #include <ucontext.h>
  #endif
  #ifndef INTEGRITY
  #include <signal.h>
  #endif
  #include <stdio.h>
  #ifndef VXWORKS_RTP
  #include <pthread.h>
  #endif
  
  #include "os_report.h"
  #include "os_thread.h"
  #include "os_abstract.h"
  #include "os_init.h"
  #include "os_mutex.h"
  
  
  
  #define SIGNAL_THREAD_STOP (-1)
  #define lengthof(a) ((int)(sizeof(a) / sizeof(*a)))
  
  /* These are the signals for which the User shall detach from the Domain.
   * For these signals a handler is set to unregister the user from the domain.
   */
  static const int exceptions[] = {
      SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGSYS
  };
  
  static const int quits[] = {
      SIGQUIT, SIGPIPE, SIGINT, SIGTERM, SIGHUP
  };
  
  static unsigned quits_len = lengthof(quits);
  
  /* If any of the SIGFPE, SIGILL, SIGSEGV, or SIGBUS signals are generated while
   * they are blocked, the result is undefined, unless the signal was generated
   * by the kill() function, the sigqueue() function, or the raise() function. */
  static const int excludes[] = {
      SIGFPE, SIGILL, SIGSEGV, SIGBUS
  };
  
  static sigset_t exceptionsMask;
  static sigset_t quitsMask;
  
  
  struct os_signalHandler_s {
      os_threadId threadId;   /* The thread id of the signalHandlerThread. */
      int pipeIn[2]; /* a pipe to send a signal to the signal handler thread. */
      int pipeOut[2]; /* a pipe to receive a result from the signal handler thread. */
      os_signalHandlerCallbackInfo callbackInfo;
      os_sigaction action;
      os_boolean handleExceptions;
  };
  
  #ifdef NSIG
  #define OS_NSIG (NSIG)
  #elif defined(_NSIG)
  #define OS_NSIG (_NSIG)
  #elif defined(SIGRTMAX)
  #define OS_NSIG (SIGRTMAX)
  #else
  #define OS_NSIG (65)  /* 64+1; allows indexing of potential signal 64  (typical value of NSIG/_NSIG/SIGRTMAX) in array */
  #endif
  
  
  static os_sigaction old_signalHandler[OS_NSIG];
  
  static os_signalHandler signalHandlerObj = NULL;
  
  static int installSignalHandler = 1;
  
  static void os__signalHandlerThreadStop(os_signalHandler _this);
  
  struct sig_context {
      siginfo_t info;
      os_ulong_int ThreadIdSignalRaised;
      os_int32 domainId;
  #ifdef OS_HAS_UCONTEXT_T
      ucontext_t uc;
  #endif
  };
  
  /* Include the common implementation for callback handling */
  #include "../common/code/os_signalHandlerCallback.c"
  
  void
  os_signalHandlerIgnoreJavaSignals (void)
  {
      /* Ignore the SIGHUP, SIGINT and SIGTERM on POSIX platforms for JAVA see OSPL-6588
       * so only first 2 signals in the quits array count
       */
      quits_len = 2;
  }
  
  /* private functions */
  static int
  isSignallingSafe(
      int reportReason)
  {
  #ifndef JAVA_IS_PERC
      if(!installSignalHandler && reportReason){
          OS_REPORT(OS_WARNING, "OS abstraction layer", 0,
                    "Did not install signal handlers to cleanup resources.\n"\
                    "              To ensure cleanup for Java applications, the path to the 'jsig' library\n"\
                    "              (libjsig.so) must be set in the LD_PRELOAD environment variable.\n"\
                    "              This library is part of your Java distribution.\n"\
                    "              To ensure proper cleanup set this before starting your application.");
      }
  #else
      OS_UNUSED_ARG(reportReason);
  #endif
      return installSignalHandler;
  }
  
  /**
   * This call causes an immediate forced ABRT of the current process.
   * It is a forced ABRT because any potentially chained signal-handlers for
   * SIG_ABRT are ignored. The handler is explicitly reset to SIG_DFL. This call
   * will never return execution to the caller.
   * The first count characters found in panicmsg will be printed to
   * STDERR_FILENO, after which the ABRT will be performed.
   * @param panicmsg The message to be printed
   * @param count The length of the message to be printed
   */
  static void
  panic(
      const char * const panicmsg,
      const size_t count)
  {
      sigset_t abort_set;
      os_write (STDERR_FILENO, panicmsg, count);
      sigemptyset (&abort_set);
      sigaddset (&abort_set, SIGABRT);
      /* Forcedly set SIG_DFL handler; there is no possibility anymore for a
       * a graceful exit. */
      signal (SIGABRT, SIG_DFL);
      sigprocmask (SIG_UNBLOCK, &abort_set, NULL);
      raise (SIGABRT);
      /* This line will not be reached anymore... */
  }
  
  /**
   * Returns if the current thread is the signalHandlerThread.
   *
   * @remarks Do not perform any signal-handling context unsafe operations in this
   * function.
   *
   * @return OS_TRUE if the current thread is the signalHandlerThread, or
   *         OS_FALSE if it's not.
   */
  static os_boolean
  inSignalHandlerThread (void)
  {
      os_int match;
      os_signalHandler _this = signalHandlerObj;
  
  #ifndef NDEBUG
      /* Assert preconditions (regular assert may trigger this action, so it
       * is not used here). */
      if (_this == NULL) {
          const char panicmsg[] = "Assertion failed: _this != NULL in " __FILE__ ":inSignalHandlerThread\n";
          panic(panicmsg, sizeof(panicmsg) - 1);
          /* This line will not be reached anymore */
      }
  #endif
  
      match = os_threadIdToInteger (_this->threadId) ==
          os_threadIdToInteger (os_threadIdSelf ());
  
      return match ? OS_TRUE : OS_FALSE;
  }
  
  /**
   * This call runs in signalhandler context and notifies the signalHandlerThread
   * of a signal. This function will write the os_signalHandlerPipe through a pipe to the
   * signalHandlerThread in one atomic write and optionally synchronizes on the
   * result of the signalHandlerThread, (which will be written to a pipe by the
   * signalHandlerThread in case of a synchronous exception). If sigInfo
   * != NULL, this function will wait for this input, so the caller must assure
   * that sync is only set for exceptions, otherwise this call may block
   * indefinitely.
   * The call returns nothing on success/fail; any failure will cause a panic
   * (immediate forced ABRT), causing the function not to return. So if the call
   * returns, the post-conditions hold.
   *
   * @remarks Do not perform any signal-handling context unsafe operations in this
   * function.
   *
   * @param sigInfo Information and context of the signal that was caught
   * @param sync A pointer to storage for the signal-context on which was
   * synchronised
   * @post If this call returns, the signal-context in info was successfully
   * and atomically written to the pipe of the signalHandlerThread and if sigInfo
   * != NULL sizeof(struct sig_context) bytes were successfully read from the pipe. Any
   * error will cause a panic (immediate forced ABRT).
   */
  static void
  signalHandlerThreadNotify(
      struct sig_context sigInfo,
      struct sig_context *sync)
  {
      ssize_t r;
      os_signalHandler _this = signalHandlerObj;
  
  #ifndef NDEBUG
      /* Assert preconditions (regular assert may trigger this action, so it
       * is not used here). */
      if(_this == NULL) {
          const char panicmsg[] = "Assertion failed: _this != NULL in " __FILE__ ":signalHandlerThreadNotify\n";
          panic(panicmsg, sizeof(panicmsg) - 1);
          /* This line will not be reached anymore */
      }
      if(sync && sigismember(&exceptionsMask, sigInfo.info.si_signo) == 0){
          /* In this case signalHandlerThreadNotify may wait indefinately, since
           * the signalHandlerThread will not notify when it is done handling the
           * signal. */
          const char panicmsg[] = "Assertion failed: sync != NULL && sigInfo.info.si_signo is not an exception in " __FILE__ ":signalHandlerThreadNotify\n";
          panic(panicmsg, sizeof(panicmsg) - 1);
          /* This line will not be reached anymore */
      }
      if(sync && sigInfo.info.si_code == SI_USER){
          /* An asynchronously received exception may not be handled synchronously. */
          const char panicmsg[] = "Assertion failed: sync != NULL && sigInfo.info.si_code is SI_USER, meaning the signal was asynchronously delivered in " __FILE__ ":signalHandlerThreadNotify\n";
          panic(panicmsg, sizeof(panicmsg) - 1);
          /* This line will not be reached anymore */
      }
  #endif
     /* The following write and read statement implement a synchronous call
      * to the signalHandlerThread; the signalHandlerThread will detach the
      * user-layer from the Domain. If sync is !NULL, this operation will
      * block until the signalHandlerThread has finished.
      * NOTE: The signalHandlerThread will ONLY signal that it has finished for
      * exceptions; calling signalHandlerThreadDetach with sync == NULL for
      * quits will cause starvation!
      * Due to the compile-time constraint enforced through the
      * struct atomic_write_constraint, the write of info is ensured to be atomic. */
      do {
  	assert(_this->pipeIn[1]);
          r = write(_this->pipeIn[1], &sigInfo, sizeof(sigInfo));
          if (r == -1 && os_getErrno() != EINTR){
              /* We understand that EINTR may have occurred, the rest of the
               * possible errors are reason for serious panic; the only means we
               * had of handling this cleanly is this piece of code :s, so panic
               * it is. */
              const char panicmsg[] = "FATAL ERROR: Atomic write to pipe in signalHandlerThreadNotify failed\n";
              panic(panicmsg, sizeof(panicmsg) - 1);
              /* This line will not be reached anymore */
          }
      } while(r == -1);
  
      if(sync){ /* If caller wants to wait for the signal-handler thread to finish */
          size_t nread = 0;
  
          /* There is no guarantee that read will return all available data/all
           * data that is atomically written will be available for an atomic read
           * (just that writes of size < PIPE_BUF will not be interleaved). So en-
           * sure we get the entire struct. */
          do{
              r = read(_this->pipeOut[0], sync + nread, sizeof(*sync) - nread);
              if (r == -1 && os_getErrno() != EINTR){
                  /* We understand that EINTR may have occurred, the rest of the
                   * possible errors are reason for serious panic; the only means we
                   * had of handling this cleanly is this piece of code :s, so panic
                   * it is. */
                  const char panicmsg[] = "FATAL ERROR: Read from pipe in signalHandlerThreadNotify failed\n";
                  panic(panicmsg, sizeof(panicmsg) - 1);
                  /* This line will not be reached anymore */
              }
              if (r > 0) {
                  nread += (size_t) r;
              }
          } while(nread < sizeof(*sync));
      }
      return;
  }
  
  
  
  /* In order to prevent interleaved writes on the pipe or the need to introduce
   * logic to recover from them, we do a compile-time assertion here. It is
   * expected to always pass on POSIX.1-2001 compliant platforms, since
   * POSIX.1-2001 requires PIPE_BUF to be at least 512. On Linux PIPE_BUF is 4096.
   * The size of struct sigcontext is approximately 476 bytes. */
  
  struct atomic_write_constraint {
      char require_sizeof_os_signalHandlerPipe_lte_PIPE_BUF [sizeof(struct sig_context) <= PIPE_BUF];
      char non_empty_dummy_last_member[1];
  };
  
  /**
   * 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);
      }
  }
  
  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;
  }
  
  #include <ucontext.h>
  #ifdef __APPLE__
  #include <sys/ucontext.h>
  #endif
  
  static void *pc_from_ucontext(const ucontext_t *uc)
  {
  #if defined REG_PC /* SPARC, must precede REG_RIP cos it has that one too */
   return (void*) uc->uc_mcontext.gregs[REG_PC];
  #elif defined REG_RIP
   return (void*) uc->uc_mcontext.gregs[REG_RIP];
  #elif defined REG_EIP
   return (void*) uc->uc_mcontext.gregs[REG_EIP];
  #elif defined PT_NIP
   return (void*) uc->uc_mcontext.uc_regs->gregs[PT_NIP];
  #elif defined __APPLE__ && defined _LP64
   return (void*) uc->uc_mcontext->__ss.__rip;
  #else
   (void)uc;
   return 0;
  #endif
  }
  
  
  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;
  }
  
  static os_result
  os_signalHandlerInit(
      os_signalHandler _this);
  
  os_result
  os_signalHandlerNew(
      void)
  {
      os_signalHandler _this;
      os_result result = os_resultFail;
  
  #if !defined INTEGRITY && !defined VXWORKS_RTP
      _this = os_malloc(sizeof(*_this));
      if (_this == NULL) {
          OS_REPORT(OS_ERROR, "os_signalHandlerNew", 0, "os_malloc(%"PA_PRIuSIZE") failed.", sizeof(*_this));
          goto err_malloc;
      }
      signalHandlerObj = _this;
      if((result = os_signalHandlerInit(_this)) != os_resultSuccess){
          goto err_init;
      }
  #endif
      return result;
  
  err_init:
      signalHandlerObj = NULL;
      os_free(_this);
  err_malloc:
      return os_resultFail;
  }
  
  static os_result
  os_signalHandlerEnableExitSignals (
      void);
  
  static os_result
  os_signalHandlerInit(
      os_signalHandler _this)
  {
      os_result result = os_resultSuccess;
      os_sigset block_all_sigset, old_sigset;
      unsigned i;
      int r;
      os_threadAttr thrAttr;
  
      assert(_this);
  
      _this->handleExceptions = OS_FALSE;
  
      if(os__signalHandlerCallbackInit(&_this->callbackInfo) != os_resultSuccess) {
          goto err_callbackInfoInit;
      }
  
      if(!isSignallingSafe(1)){
          return os_resultSuccess;
      }
  
      /* 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 < quits_len; i++){
          sigaddset(&quitsMask, quits[i]);
      }
  
      /* create signal handling pipes */
      r = pipe(_this->pipeIn);
      if (r < 0) {
          OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0, "pipe(_this->pipeIn) failed, result = %d", r);
          goto err_pipeIn;
      }
  
      r = fcntl(_this->pipeIn[0], F_SETFD, 1);
      if (r < 0) {
          OS_REPORT(OS_WARNING, "os_signalHandlerInit", 0, "fcntl(_this->pipeIn[0]) failed, result = %d", r);
          goto err_pipeInFcntl;
      }
  
      r = fcntl(_this->pipeIn[1], F_SETFD, 1);
      if (r < 0) {
          OS_REPORT(OS_WARNING, "os_signalHandlerInit", 0, "fcntl(_this->pipeIn[1]) failed, result = %d", r);
          goto err_pipeInFcntl;
      }
  
      r = pipe(_this->pipeOut);
      if (r < 0) {
          OS_REPORT(OS_ERROR, "os_signalHandlerInit", 1, "pipe(_this->pipeOut) failed, result = %d", r);
          goto err_pipeOut;
      }
  
      r = fcntl(_this->pipeOut[0], F_SETFD, 1);
      if (r < 0) {
          OS_REPORT(OS_WARNING, "os_signalHandlerInit", 0, "fcntl(_this->pipeOut[0]) failed, result = %d", r);
          goto err_pipeOutFcntl;
      }
  
      r = fcntl(_this->pipeOut[1], F_SETFD, 1);
      if (r < 0) {
          OS_REPORT(OS_WARNING, "os_signalHandlerInit", 0, "fcntl(_this->pipeOut[1]) failed, result = %d", r);
          goto err_pipeOutFcntl;
      }
  
      /* Block all signals in order to start the signalHandlerThread with all
       * signals blocked. */
      result = os_sigsetFill(&block_all_sigset);
      if (result != os_resultSuccess) {
          OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                  "os_sigsetFill(&block_all_sigset) failed: %s", os_resultImage(result));
          goto err_sigsetMask;
      }
  
      /* Remove signals that cannot be blocked. */
      for (i = 0; i < lengthof(excludes); i++) {
          const int sig = excludes[i];
          if (os_sigsetDel(&block_all_sigset, sig) != 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_sigsetMask;
          }
      }
  
      result = os_sigThreadSetMask(&block_all_sigset, &old_sigset);
      if (result != os_resultSuccess) {
          OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0, "os_sigThreadSetMask(0x%"PA_PRIxADDR", 0x%"PA_PRIxADDR") failed: %s",
                      (os_address)&block_all_sigset, (os_address)&old_sigset, os_resultImage(result));
          goto err_sigsetMask;
      }
  
      /* Setup signal handler thread. */
      os_threadAttrInit(&thrAttr);
      thrAttr.stackSize = 4*1024*1024; /* 4 MB */
      result = os_threadCreate(&_this->threadId,
                               "signalHandler",
                               &thrAttr,
                               signalHandlerThread,
                               (void*)_this);
  
      if (result != os_resultSuccess) {
          OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                      "os_threadCreate(0x%"PA_PRIxADDR", 0x%"PA_PRIxADDR",0x%"PA_PRIxADDR",0) failed: %s",
                      (os_address)&_this->threadId,
                      (os_address)&thrAttr,
                      (os_address)signalHandlerThread,
                      os_resultImage(result));
          goto err_threadCreate;
      }
  
      /* Reset signal mask to original value. */
      result = os_sigThreadSetMask(&old_sigset, NULL);
      if (result != os_resultSuccess) {
          OS_REPORT(OS_ERROR, "os_signalHandlerInit", 0,
                      "os_sigThreadSetMask(0x%"PA_PRIxADDR", NULL) failed: %s",
                      (os_address)&old_sigset, os_resultImage(result));
          goto err_sigResetMask;
      }
  
      /* install signal handlers */
      _this->action = os_sigactionNew(signalHandler, &block_all_sigset, SA_SIGINFO);
  
      if (os_signalHandlerEnableExitSignals() != os_resultSuccess) {
          goto err_enableExitHandling;
      }
  
      return os_resultSuccess;
  
  /* Error handling */
  err_enableExitHandling:
  err_sigResetMask:
      os__signalHandlerThreadStop(_this);
  err_threadCreate:
      (void) os_sigThreadSetMask(&old_sigset, NULL);
  err_sigsetMask:
      /* No undo needed for fcntl's/sigsetFill */
  err_pipeOutFcntl:
      (void) close(_this->pipeOut[0]);
      (void) close(_this->pipeOut[1]);
  err_pipeOut:
      /* No undo needed for fcntl's */
  err_pipeInFcntl:
      (void) close(_this->pipeIn[0]);
      (void) close(_this->pipeIn[1]);
  err_pipeIn:
      os__signalHandlerCallbackDeinit(&_this->callbackInfo);
  err_callbackInfoInit:
      return os_resultFail;
  }
  
  
  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;
  }
  
  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;
  }
  
  
  static void
  os__signalHandlerThreadStop(
          os_signalHandler _this)
  {
      struct sig_context info;
      void *thread_result;
  
      assert(_this);
  
      memset (&info, 0, sizeof(info));
      info.info.si_signo = SIGNAL_THREAD_STOP;
      if (write(_this->pipeIn[1], &info, sizeof(info)) < 0) {
          /* ignore result */
      }
      /* When the signalHandlerThread itself is the exiting thread (this can happen
       * when an exit call is done in a signalHandler installed by a customer for
       * example), we should not invoke os_threadWaitExit but just let this call
       * return immediately. */
      if (os_threadIdSelf() != _this->threadId ) {
          (void) os_threadWaitExit(_this->threadId, &thread_result);
      }
  }
  
  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_signalHandlerSetEnabled(
      os_uint enabled)
  {
      if(enabled == 0){
          installSignalHandler = 0;
      } else {
          installSignalHandler = 1;
      }
      return os_resultSuccess;
  }
  
  static os_signalHandlerCallbackInfo*
  os__signalHandlerGetCallbackInfo(void)
  {
      os_signalHandler _this = signalHandlerObj;
  
      assert(_this);
  
      return &_this->callbackInfo;
  }
  