424 lines
16 KiB
HTML
424 lines
16 KiB
HTML
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<meta name="Copyright" content="Copyright (c) 2006 by IBM Corporation">
|
||
|
<title>Exceptions vs. Asynchronous signals vs. ANSI C signals</title>
|
||
|
<!-- Begin Header Records ========================================== -->
|
||
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
||
|
<!-- US Government Users Restricted Rights -->
|
||
|
<!-- Use, duplication or disclosure restricted by -->
|
||
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
||
|
<!-- Change History: -->
|
||
|
<!-- YYMMDD USERID Change description -->
|
||
|
<!-- NETMG2 SCRIPT A converted by B2H R4.1 (346) (CMS) by HOLTJM at -->
|
||
|
<!-- RCHVMW2 on 29 Jan 1999 at 10:01:37 -->
|
||
|
<!--File Edited November 2001 -->
|
||
|
<!--End Header Records -->
|
||
|
<link rel="stylesheet" type="text/css" href="../rzahg/ic.css">
|
||
|
</head>
|
||
|
<body>
|
||
|
<!-- Java sync-link -->
|
||
|
<script language="Javascript" src="../rzahg/synch.js" type="text/javascript">
|
||
|
</script>
|
||
|
|
||
|
<a name="Top_Of_Page"></a>
|
||
|
|
||
|
<h2>Exceptions vs. Asynchronous signals vs. ANSI C signals</h2>
|
||
|
|
||
|
<p>iSeries distinguishes between hardware exceptions, POSIX signals (sometimes
|
||
|
called asynchronous signals), and ANSI C signals. POSIX signals use the APIs
|
||
|
kill(), sigaction(), pthread_kill(), alarm(), pause(), and others for signal
|
||
|
interaction. ANSI C signals use the APIs raise(), signal(), and abort() for
|
||
|
signal interaction.</p>
|
||
|
|
||
|
<p>Many other systems, by default, generate a POSIX signal whenever a software
|
||
|
or hardware exception occurs (such as using a pointer that is not valid, or an
|
||
|
error caused by dividing by zero), and on those systems, a POSIX signal may be
|
||
|
equivalent and indistinguishable from an ANSI C signal. If the signal is not
|
||
|
handled, this results in the termination of the process.</p>
|
||
|
|
||
|
<p>The operating system does not generate a signal for these hardware or software problems,
|
||
|
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
|
||
|
whether or not to handle the exception. If the exception is not handled, the
|
||
|
message continues to the next stack frame.</p>
|
||
|
|
||
|
<p>When the exception message reaches certain boundaries on the call stack
|
||
|
(such as 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 exception that is not handled occurs in a secondary thread
|
||
|
and moves all the way to the first invocation in the thread without being
|
||
|
handled, the resulting action is to terminate the thread. During this movement,
|
||
|
if the exception hits a control boundary and is not handled, it may terminate
|
||
|
the process.</p>
|
||
|
|
||
|
<p>The integrated language environment (ILE) C was present on the system before
|
||
|
the POSIX signals implementation. Therefore, the ILE C uses the robust iSeries
|
||
|
exception model to implement ANSI C signals (raise(), signal(), abort()). The
|
||
|
ILE C also provides the generation of an ANSI C signal when it detects a
|
||
|
hardware exception. Thus, using the signal() API, you can monitor and handle
|
||
|
hardware exceptions.</p>
|
||
|
|
||
|
<p>A signal is never automatically generated for an exception message. iSeries
|
||
|
hardware and software exceptions cannot be detected using asynchronous signal
|
||
|
mechanisms. In other words, if you use sigaction() for the SIGSEGV signal, you
|
||
|
will not detect that signal when a pointer that is not valid is used. If you
|
||
|
use signal(), you will detect SIGSEGV when your code uses an invalid
|
||
|
pointer.</p>
|
||
|
|
||
|
<p>If the preferred signal model is the asynchronous signal model, you can use
|
||
|
iSeries exception handlers or ANSI C signal handlers to generate a asynchronous
|
||
|
signal when those events occur.</p>
|
||
|
|
||
|
<p>The following example shows how an error caused by dividing by zero and the
|
||
|
use of an invalid pointer might be changed into an asynchronous signal. The
|
||
|
following example uses ANSI C signal handlers to perform the signal
|
||
|
mapping.</p>
|
||
|
|
||
|
<br>
|
||
|
<h3>Example</h3>
|
||
|
|
||
|
<p>See <a href="../apiref/aboutapis.htm#codedisclaimer">Code disclaimer information</a>
|
||
|
for information pertaining to code examples.</p>
|
||
|
|
||
|
<pre>
|
||
|
#define _MULTI_THREADED
|
||
|
#include <stdio.h>
|
||
|
#include <qp0z1170.h>
|
||
|
#include <time.h>
|
||
|
#include <signal.h>
|
||
|
#include <pthread.h>
|
||
|
#include "check.h"
|
||
|
|
||
|
|
||
|
void myAnsiSignalMapperHdlr(int sigNumber);
|
||
|
void *threadfunc1(void *parm);
|
||
|
void *threadfunc2(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 *threadfunc2(void *parm)
|
||
|
{
|
||
|
int i1=0, i2=1, i3=0;
|
||
|
printf("Thread2: Unhandled exception (divide by zero) about to happen\n");
|
||
|
i1 = i2 / i3;
|
||
|
printf("Thread2: After exception\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void myAnsiSignalMapperHdlr(int sigNumber) {
|
||
|
/* In a multithreaded environment, this is slightly 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 which 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, myAnsiSignalMapperHdlr);
|
||
|
/* Since ANSI C signals and hardware exceptions will only be handled in */
|
||
|
/* the same thread that caused them, we will send the POSIX signal to */
|
||
|
/* the calling thread (The signal will be delivered before returning from */
|
||
|
/* pthread_kill(). */
|
||
|
printf("Mapping ANSI signal to POSIX signal %d\n", sigNumber);
|
||
|
pthread_kill(pthread_self(), sigNumber);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void fpViolationHldr(int sigNumber) {
|
||
|
printf("Thread 0x%.8x %.8x "
|
||
|
"Handled floating point failure SIGFPE (signal %d)\n",
|
||
|
pthread_getthreadid_np(), sigNumber);
|
||
|
/* By definition, returning from a POSIX signal handler handles the signal*/
|
||
|
}
|
||
|
|
||
|
void segFaultHdlr(int sigNumber) {
|
||
|
printf("Thread 0x%.8x %.8x "
|
||
|
"Handled segmentation violation SIGSEGV (signal %d)\n",
|
||
|
pthread_getthreadid_np(), sigNumber);
|
||
|
/* By definition, returning from a POSIX signal handler handles the signal*/
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
int rc=0;
|
||
|
pthread_t threadid;
|
||
|
struct sigaction actions;
|
||
|
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");
|
||
|
signal(SIGALL, myAnsiSignalMapperHdlr);
|
||
|
|
||
|
printf("- Register normal POSIX signal handling mechanisms\n"
|
||
|
" for floating point violations, and segmentation faults\n"
|
||
|
"- Other signals take the default action for asynchronous signals\n");
|
||
|
memset(&actions, 0, sizeof(actions));
|
||
|
sigemptyset(&actions.sa_mask);
|
||
|
actions.sa_flags = 0;
|
||
|
actions.sa_handler = fpViolationHldr;
|
||
|
|
||
|
rc = sigaction(SIGFPE,&actions,NULL);
|
||
|
checkResults("sigaction for SIGFPE\n", rc);
|
||
|
|
||
|
actions.sa_handler = segFaultHdlr;
|
||
|
rc = sigaction(SIGSEGV,&actions,NULL);
|
||
|
checkResults("sigaction for SIGSEGV\n", rc);
|
||
|
|
||
|
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("----------- Start divide by 0 thread -------------\n");
|
||
|
printf("Create a thread\n");
|
||
|
rc = pthread_create(&threadid, NULL, threadfunc2, NULL);
|
||
|
checkResults("pthread_create()\n", rc);
|
||
|
|
||
|
rc = pthread_join(threadid, &status);
|
||
|
checkResults("pthread_join()\n", rc);
|
||
|
|
||
|
printf("Main completed\n");
|
||
|
return 0;
|
||
|
}
|
||
|
</pre>
|
||
|
|
||
|
<br>
|
||
|
<h3>Example Output</h3>
|
||
|
|
||
|
<pre>
|
||
|
----------- Setup Signal Mapping/Handling -------------
|
||
|
- Register ANSI C signal handler to map ALL
|
||
|
ANSI C signals & hardware exceptions to POSIX signals
|
||
|
- Register normal POSIX signal handling mechanisms
|
||
|
for floating point violations, and segmentation faults
|
||
|
- Other signals take the default action for asynchronous signals
|
||
|
----------- Start memory fault thread -------------
|
||
|
Create a thread
|
||
|
Thread1: Unhandled exception (pointer fault) about to happen
|
||
|
Mapping ANSI signal to POSIX signal 5
|
||
|
Thread 0x00000000 00000022 Handled segmentation violation SIGSEGV (signal 5)
|
||
|
Thread1: After exception
|
||
|
----------- Start divide by 0 thread -------------
|
||
|
Create a thread
|
||
|
Thread2: Unhandled exception (divide by zero) about to happen
|
||
|
Mapping ANSI signal to POSIX signal 2
|
||
|
Thread 0x00000000 00000023 Handled floating point failure SIGFPE (signal 2)
|
||
|
Thread2: After exception
|
||
|
Main completed
|
||
|
</pre>
|
||
|
|
||
|
<br>
|
||
|
|
||
|
|
||
|
<h3>Example</h3>
|
||
|
|
||
|
<p>The following example shows how a divide by zero error, and a dereference of
|
||
|
a pointer that is not valid might be mapped to generate a POSIX (asynchronous)
|
||
|
signal. This example uses exception handlers to perform the signal mapping.</p>
|
||
|
|
||
|
<p>See <a href="../apiref/aboutapis.htm#codedisclaimer">Code disclaimer information</a>
|
||
|
for information pertaining to code examples.</p>
|
||
|
|
||
|
<pre>
|
||
|
#define _MULTI_THREADED
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <qp0z1170.h>
|
||
|
#include <time.h>
|
||
|
#include <signal.h>
|
||
|
#include <except.h>
|
||
|
#include <qusec.h> /* System API error Code structure */
|
||
|
#include <qmh.h> /* Message Hanlder common defs */
|
||
|
#include <qmhchgem.h> /* Change exception message */
|
||
|
#include <pthread.h>
|
||
|
#include "check.h"
|
||
|
|
||
|
void myHardwareExceptionMapper(_INTRPT_Hndlr_Parms_T *exception);
|
||
|
void *threadfunc1(void *parm);
|
||
|
void *threadfunc2(void *parm);
|
||
|
|
||
|
void *threadfunc1(void *parm)
|
||
|
{
|
||
|
char *p=NULL;
|
||
|
/* Watch for all ESCAPE type exceptions. Other types may be used for */
|
||
|
/* job log messages or C++ exceptions or other control flow in the process*/
|
||
|
/* Adjust the message type as required by your application. */
|
||
|
#pragma exception_handler (myHardwareExceptionMapper, 0, _C1_ALL, _C2_MH_ESCAPE)
|
||
|
printf("Thread1: Unhandled exception (pointer fault) about to happen\n");
|
||
|
*p = `!';
|
||
|
printf("Thread1: After exception\n");
|
||
|
#pragma disable_handler
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void *threadfunc2(void *parm)
|
||
|
{
|
||
|
int i1=0, i2=1, i3=0;
|
||
|
/* Watch for all ESCAPE type exceptions. Others types may be used for */
|
||
|
/* job log messages or C++ exceptions or other control flow in the process*/
|
||
|
/* Adjust the message type as required by your application. */
|
||
|
#pragma exception_handler (myHardwareExceptionMapper, 0, _C1_ALL, _C2_MH_ESCAPE)
|
||
|
printf("Thread2: Unhandled exception (divide by zero) about to happen\n");
|
||
|
i1 = i2 / i3;
|
||
|
printf("Thread2: After exception\n");
|
||
|
#pragma disable_handler
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void myHardwareExceptionMapper(_INTRPT_Hndlr_Parms_T *exInfo) {
|
||
|
int sigNumber;
|
||
|
Qus_EC_t errorCode = {0}; /* system API error structure */
|
||
|
|
||
|
printf("Handling system exception\n");
|
||
|
/* The exception information is available inside the exInfo structure */
|
||
|
/* for this example, we are going to handle all exceptions and then map */
|
||
|
/* them to an \Qappropriate' signal number. We are allowed to decide the */
|
||
|
/* signal mapping however is appropriate for our application. */
|
||
|
if (!memcmp(exInfo->Msg_Id, "MCH3601", 7)) {
|
||
|
sigNumber = SIGSEGV;
|
||
|
}
|
||
|
else if (!memcmp(exInfo->Msg_Id, "MCH1211", 7)) {
|
||
|
sigNumber = SIGFPE;
|
||
|
}
|
||
|
else {
|
||
|
printf("Unexpected exception! Not Handling!\n");
|
||
|
abort();
|
||
|
}
|
||
|
/* Even if the exception is \Qexpected', we are going to handle it and try */
|
||
|
/* to deliver it as a POSIX signal. Note that we SHOULD NOT HANDLE */
|
||
|
/* exceptions that are unexpected to us. Most code cannot tolerate */
|
||
|
/* getting back into it once the exception occured, and we could get into */
|
||
|
/* a nice exception loop. */
|
||
|
|
||
|
/* See the system API reference for a description of QMHCHGEM */
|
||
|
QMHCHGEM(&exInfo->Target, 0, &exInfo->Msg_Ref_Key, QMH_MOD_HANDLE,
|
||
|
(char *)NULL, 0, &errorCode);
|
||
|
if (errorCode.Bytes_Available != 0) {
|
||
|
printf("Failed to handle exception. Error Code = %7.7s\n",
|
||
|
errorCode.Exception_Id);
|
||
|
return;
|
||
|
}
|
||
|
printf("Mapping Exception %7.7s to POSIX signal %d\n",
|
||
|
exInfo->Msg_Id ,sigNumber);
|
||
|
/* At this point the exception is handled. If the POSIX signal handler */
|
||
|
/* returns, then the signal will be handled, and all will be complete */
|
||
|
pthread_kill(pthread_self(), sigNumber);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void fpViolationHldr(int sigNumber) {
|
||
|
printf("Thread 0x%.8x %.8x "
|
||
|
"Handled floating point failure SIGFPE (signal %d)\n",
|
||
|
pthread_getthreadid_np(), sigNumber);
|
||
|
/* By definition, return from a POSIX signal handler handles the signal */
|
||
|
}
|
||
|
|
||
|
void segFaultHdlr(int sigNumber) {
|
||
|
printf("Thread 0x%.8x %.8x "
|
||
|
"Handled segmentation violation SIGSEGV (signal %d)\n",
|
||
|
pthread_getthreadid_np(), sigNumber);
|
||
|
/* By definition, returning from a POSIX signal handler handles the signal*/
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
int rc=0;
|
||
|
pthread_t threadid;
|
||
|
struct sigaction actions;
|
||
|
void *status;
|
||
|
|
||
|
printf("----------- Setup Signal Mapping/Handling -------------\n");
|
||
|
printf("- The threads will register iSeries Exception handler to map\n"
|
||
|
" hardware exceptions to POSIX signals\n");
|
||
|
|
||
|
printf("- Register normal POSIX signal handling mechanisms\n"
|
||
|
" for floating point violations, and segmentation faults\n"
|
||
|
"- Other signals take the default action for asynchronous signals\n");
|
||
|
memset(&actions, 0, sizeof(actions));
|
||
|
sigemptyset(&actions.sa_mask);
|
||
|
actions.sa_flags = 0;
|
||
|
actions.sa_handler = fpViolationHldr;
|
||
|
|
||
|
rc = sigaction(SIGFPE,&actions,NULL);
|
||
|
checkResults("sigaction for SIGFPE\n", rc);
|
||
|
|
||
|
actions.sa_handler = segFaultHdlr;
|
||
|
rc = sigaction(SIGSEGV,&actions,NULL);
|
||
|
checkResults("sigaction for SIGSEGV\n", rc);
|
||
|
|
||
|
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("----------- Start divide by 0 thread -------------\n");
|
||
|
printf("Create a thread\n");
|
||
|
rc = pthread_create(&threadid, NULL, threadfunc2, NULL);
|
||
|
checkResults("pthread_create()\n", rc);
|
||
|
|
||
|
rc = pthread_join(threadid, &status);
|
||
|
checkResults("pthread_join()\n", rc);
|
||
|
|
||
|
printf("Main completed\n");
|
||
|
return 0;
|
||
|
}
|
||
|
</pre>
|
||
|
|
||
|
<p><strong>Output</strong></p>
|
||
|
|
||
|
<pre>
|
||
|
----------- Setup Signal Mapping/Handling -------------
|
||
|
- The threads will register iSeries Exception handler to map
|
||
|
hardware exceptions to POSIX signals
|
||
|
- Register normal POSIX signal handling mechanisms
|
||
|
for floating point violations, and segmentation faults
|
||
|
- Other signals take the default action for asynchronous signals
|
||
|
----------- Start memory fault thread -------------
|
||
|
Create a thread
|
||
|
Thread1: Unhandled exception (pointer fault) about to happen
|
||
|
|
||
|
Handling system exception
|
||
|
Mapping Exception MCH3601 to POSIX signal 5
|
||
|
Thread 0x00000000 00000024 Handled segmentation violation SIGSEGV (signal 5)
|
||
|
Thread1: After exception
|
||
|
----------- Start divide by 0 thread -------------
|
||
|
Create a thread
|
||
|
Thread2: Unhandled exception (divide by zero) about to happen
|
||
|
Handling system exception
|
||
|
Mapping Exception MCH1211 to POSIX signal 2
|
||
|
Thread 0x00000000 00000025 Handled floating point failure SIGFPE (signal 2)
|
||
|
Thread2: After exception
|
||
|
Main completed
|
||
|
|
||
|
</pre>
|
||
|
|
||
|
<hr>
|
||
|
<center>
|
||
|
<table cellpadding="2" cellspacing="2">
|
||
|
<tr align="center">
|
||
|
<td valign="middle" align="center"><a href="#Top_Of_Page">Top</a> | <a href=
|
||
|
"rzah4mst.htm">Pthread APIs</a> | <a href="aplist.htm">APIs by
|
||
|
category</a></td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</center>
|
||
|
</body>
|
||
|
</html>
|
||
|
|