[Prev] [Contents] [Next]

Unhandled exceptions terminate the thread (Not the process)

On a Unix system, when an invalid or illegal software condition is encountered (such as divide by zero, or dereferencing an invalid pointer), a signal is generated. If unhandled, this will result in process termination.

OS/400 doesn't generate a signal for these events, but instead, generates an AS/400 exception message. The exception message is percolated 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 different 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 percolates 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 cancelation cleanup handlers and pthread data destructors do NOT run. 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 nor 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 an unhandled exception occurs, you must handle the exception message and convert it to a process termination action. 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 choose to turn the exception message into a Posix signal and possibly be handled. See "Exceptions vs. Asynchronous signals vs. ANSI C signals" on page 44 for more information.

Example

#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 multi-threaded environment this is kind of tricky. We have to     */
  /* re-enable the ANSI C handler immediately, because that's the way its   */
  /* defined. (A better alternative may be direct monitor exception         */
  /* handlers which are always valid in the function which they are         */
  /* registered, and with direct monitors, we can catch the hardware        */
  /* exception before its converted to an ANSI C signal                     */
  signal(SIGALL, abortTheProcessWhenAnExceptionOccurs);
  /* Since ANSI C signals and hardware exceptions will only be handled in   */
  /* the same thread that caused them, we'll send the Posix signal to       */
  /* the calling thread (The signal will be 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 could 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;
}


Example 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




[Prev] [Contents] [Next]
Copyright © 1998, IBM Corporation. All rights reserved.
Comments? Contact
rchthrds@us.ibm.com