ibm-information-center/dist/eclipse/plugins/i5OS.ic.apis_5.4.0.1/concep31.htm

424 lines
16 KiB
HTML
Raw Normal View History

2024-04-02 14:02:31 +00:00
<!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 &lt;stdio.h&gt;
#include &lt;qp0z1170.h&gt;
#include &lt;time.h&gt;
#include &lt;signal.h&gt;
#include &lt;pthread.h&gt;
#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 &amp; 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(&amp;actions, 0, sizeof(actions));
sigemptyset(&amp;actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = fpViolationHldr;
rc = sigaction(SIGFPE,&amp;actions,NULL);
checkResults("sigaction for SIGFPE\n", rc);
actions.sa_handler = segFaultHdlr;
rc = sigaction(SIGSEGV,&amp;actions,NULL);
checkResults("sigaction for SIGSEGV\n", rc);
printf("----------- Start memory fault thread -------------\n");
printf("Create a thread\n");
rc = pthread_create(&amp;threadid, NULL, threadfunc1, NULL);
checkResults("pthread_create()\n", rc);
rc = pthread_join(threadid, &amp;status);
checkResults("pthread_join()\n", rc);
printf("----------- Start divide by 0 thread -------------\n");
printf("Create a thread\n");
rc = pthread_create(&amp;threadid, NULL, threadfunc2, NULL);
checkResults("pthread_create()\n", rc);
rc = pthread_join(threadid, &amp;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 &amp; 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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;qp0z1170.h&gt;
#include &lt;time.h&gt;
#include &lt;signal.h&gt;
#include &lt;except.h&gt;
#include &lt;qusec.h&gt; /* System API error Code structure */
#include &lt;qmh.h&gt; /* Message Hanlder common defs */
#include &lt;qmhchgem.h&gt; /* Change exception message */
#include &lt;pthread.h&gt;
#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-&gt;Msg_Id, "MCH3601", 7)) {
sigNumber = SIGSEGV;
}
else if (!memcmp(exInfo-&gt;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(&amp;exInfo-&gt;Target, 0, &amp;exInfo-&gt;Msg_Ref_Key, QMH_MOD_HANDLE,
(char *)NULL, 0, &amp;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-&gt;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(&amp;actions, 0, sizeof(actions));
sigemptyset(&amp;actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = fpViolationHldr;
rc = sigaction(SIGFPE,&amp;actions,NULL);
checkResults("sigaction for SIGFPE\n", rc);
actions.sa_handler = segFaultHdlr;
rc = sigaction(SIGSEGV,&amp;actions,NULL);
checkResults("sigaction for SIGSEGV\n", rc);
printf("----------- Start memory fault thread -------------\n");
printf("Create a thread\n");
rc = pthread_create(&amp;threadid, NULL, threadfunc1, NULL);
checkResults("pthread_create()\n", rc);
rc = pthread_join(threadid, &amp;status);
checkResults("pthread_join()\n", rc);
printf("----------- Start divide by 0 thread -------------\n");
printf("Create a thread\n");
rc = pthread_create(&amp;threadid, NULL, threadfunc2, NULL);
checkResults("pthread_create()\n", rc);
rc = pthread_join(threadid, &amp;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>