Unhandled exceptions terminate the thread (not the process)

On a UNIX system, when an invalid or illegal software condition is encountered (such as dividing by zero or using an invalid pointer), a signal is generated. If the signal is not handled, the process is terminated.

The operating system does not generate a signal for these events, but instead, generates an exception message. The exception message moves up the call stack, allowing each stack frame (function on the stack or invocation entry) a chance to handle the exception. Each function invocation may choose to handle or not to handle the exception. If the exception is not handled, the message continues to the next stack frame.

When the exception message reaches certain boundaries on the call stack (like a main() entry point, usually called control boundaries) certain events take place. These events include changing the exception to a different type, terminating the process, terminating the activation group, or terminating the thread. If an unhandled exception condition happens in a secondary thread and moves all the way to the first invocation in the thread without being handled, the resulting action will be to terminate the thread. During this percolation, if the exception hits a control boundary and is not handled, it may terminate the process.

A signal is never automatically generated for an exception message. When an unhandled exception terminates the thread, Pthread cancellation cleanup handlers and Pthread data destructors do not run and the thread is terminated immediately with a return status of PTHREAD_EXCEPTION_NP. PTHREAD_EXCEPTION_NP is a macro similar to the PTHREAD_CANCELED macro, and is not NULL or a valid pointer.

On a UNIX system, this same activity may terminate the process due to the signal that is generated.

In order to have your application terminate the process, when the exception occurs, you must handle it and explicitly terminate the process. The following example handles all hardware exceptions using the ANSI C signal model and uses the Pthread signal SIGABRT to terminate the process.

You can also turn the exception message into a Posix signal and it may be handled. See Exceptions vs. Asynchronous signals vs. ANSI C signals for more information.


Example

See Code disclaimer information for information pertaining to code examples.

#define _MULTI_THREADED
#include <stdio.h>
#include <qp0z1170.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include "check.h"


void abortTheProcessWhenAnExceptionOccurs(int sigNumber);
void *threadfunc1(void *parm);

void *threadfunc1(void *parm)
{
  char *p=NULL;
  printf("Thread1: Unhandled exception (pointer fault) about to happen\n");
  *p = `!';
  printf("Thread1: After exception\n");
  return NULL;
}


void abortTheProcessWhenAnExceptionOccurs(int sigNumber) {
  /* In a multithreaded environment this is a little difficult. We have to  */
  /* re-enable the ANSI C handler immediately, because that is the way it   */
  /* is defined. (A better alternative may be direct monitor exception      */
  /* handlers that are always valid in the function which they are          */
  /* registered, and with direct monitors, we can catch the hardware        */
  /* exception before it is converted to an ANSI C signal                   */
  signal(SIGALL, abortTheProcessWhenAnExceptionOccurs);
  /* Since ANSI C signals and hardware exceptions are only handled in       */
  /* the same thread that caused them, we send the Posix signal to          */
  /* the calling thread (The signal is delivered before returning from      */
  /* pthread_kill().                                                        */
  printf("Mapping ANSI signal %d to posix signal SIGABRT. "
         "Aborting the process\n", sigNumber);

  /* If we want to do some debug processing, we can put it here.            */
  pthread_kill(pthread_self(), SIGABRT);
  return;
}

int main(int argc, char **argv)
{
  int                   rc=0;
  pthread_t             threadid;
  void                 *status;

  printf("----------- Setup Signal Mapping/Handling -------------\n");
  printf("- Register ANSI C signal handler to map ALL\n"
         "  ANSI C signals & hardware exceptions to Posix signals\n");
  /* If we want to do debug, or determine what when wrong a little more easily,  
*/
  /* we could use the abortTheProcessWhenAnExceptionOccurs function to delay  
the thread, or   */
  /* dump failure data of some sort. 
*/
  signal(SIGALL, abortTheProcessWhenAnExceptionOccurs);

  printf("----------- Start memory fault thread -------------\n");
  printf("Create a thread\n");
  rc = pthread_create(&threadid, NULL, threadfunc1, NULL);
  checkResults("pthread_create()\n", rc);

  rc = pthread_join(threadid, &status);
  checkResults("pthread_join()\n", rc);

  printf("Main completed\n");
  return 0;
}

Output:

----------- Setup Signal Mapping/Handling -------------
- Register ANSI C signal handler to map ALL
  ANSI C signals & hardware exceptions to Posix signals
----------- Start memory fault thread -------------
Create a thread
Thread1: Unhandled exception (pointer fault) about to happen
Mapping ANSI signal 5 to posix signal SIGABRT. Aborting the process

Top | Pthread APIs | APIs by category