Developer Guide and Reference

ID 767251
Date 10/31/2024
Public
Document Table of Contents

Use SIGNALQQ

For lightweight exception handling requirements, a handler established with SIGNALQQ may meet your needs. This section describes how signal handling with SIGNALQQ works in detail and also how the Fortran runtime routine GETEXCEPTIONPTRSQQ works.

Reference is made to C runtime sources provided with Microsoft* Visual C++*. The discussion is worth reviewing even if you do not have Visual C++* available.

C-Style Signal Handling Overview

Many Fortran applications were developed on UNIX* systems where C-style signal handling was the usual way of dealing with exceptions. When ported to Windows*, these applications can continue to use the C signal interface. SIGNALQQ will work with any application type using pure Fortran or mixed Fortran and C code.

SIGNALQQ is just a Fortran jacket to the C runtime signal() function. When you call SIGNALQQ, you are actually registering your signal handler (or action) for a particular signal with the C runtime system. The C runtime system simply stores your handler (or action) in an internal exception action table or variable where it associates your handler with the desired signal. The operating system has no knowledge of this association.

If you have Visual C++* available, you can look at the code for the C runtime signal routine in ...\MICROSOFT VISUAL STUDIO .NET\VC7\CRT\SRC\WINSIG.C and see how the table is managed. The table itself is defined and initialized in source file WINXFLTR.C, available in the same folder. When a signal occurs, the C runtime system checks its internal table to see if you have registered a handler for the particular signal. It calls your routine if you have assigned a handler.

Signal is Really SEH Again

Notice that it is the C runtime system that calls your handler when a signal occurs, not the operating system. So how did the C runtime get the exception delivered to it? Recall that the entry point of your image is either mainCRTStartup or WinMainCRTStartup, depending on the application type. Refer to Handlers for the Application (Project) Types and look at these entry points (or look at source file Crt0.c in the C runtime sources). Notice that they wrap a try-except construct around a call to either main() or WinMain() and that the filter expression associated with the __except construct calls a function _XcptFilter. _XcptFilter is passed two arguments that are the operating system supplied exception information.

When an exception occurs, the operating system looks at the list of exception filters and, starting with the inner-most nested try-except construct, evaluates except filter expressions until it finds one which does not return EXCEPTION_CONTINUE_SEARCH. If your application type includes main from the Fortran runtime system and thus the except construct associated with main, the Fortran runtime filter will be evaluated before the C runtime filter. The Fortran filter expression will check to see if you have established your own handler with SIGNALQQ. If it finds there is such a handler, or if you have set the environment variable FOR_IGNORE_EXCEPTIONS, it will return EXCEPTION_CONTINUE_SEARCH to allow the C runtime exception filter the opportunity to deal with the exception and find your handler. If you have not established your own handler or set the environment variable, the Fortran runtime will perform its default exception handling processing.

The C filter function, _XcptFilter, compares the exception code from the operating system with its mapping of operating system exceptions to C signal codes. If it finds a match in the table, it uses the exception action entry in the table corresponding to the signal code. This is the same table where your SIGNALQQ handler is recorded as the action for the requested signal code. If you have established a handler, it will be called from _XcptFilter. Before your handler is called, _XcptFilter resets the specified action for the signal to SIG_DFL in the exception action table. If you try to continue from the exception and you want your handler invoked on the next occurrence of the signal, you must call SIGNALQQ again to reestablish your handler as the action for that signal. When your handler routine is finished executing and returns to _XcptFilter, the value EXCEPTION_CONTINUE_EXECUTION is returned to the operating system by _XcptFilter. The operating system will then resume execution at the point of the exception. If you do not want to continue execution, your handler should take appropriate action to shut down the application.

Not every operating system exception code maps to a C signal code. You can see the mapping in source WINXFLTR.C if you have it. Here is the list if you do not have WINXFLTR.C:

Operating System Exception Code

C Signal Number

STATUS_ACCESS_VIOLATION

SIGSEGV

STATUS_ILLEGAL_INSTRUCTION

SIGILL

STATUS_PRIVILEGED_INSTRUCTION

SIGILL

STATUS_FLOAT_DENORMAL_OPERAND

SIGFPE

STATUS_FLOAT_DIVIDE_BY_ZERO

SIGFPE

STATUS_FLOAT_INEXACT_RESULT

SIGFPE

STATUS_FLOAT_INVALID_OPERATION

SIGFPE

STATUS_FLOAT_OVERFLOW

SIGFPE

STATUS_FLOAT_STACK_CHECK

SIGFPE

STATUS_FLOAT_UNDERFLOW

SIGFPE

How GETEXCEPTIONPTRSQQ Works

When the C runtime exception filter function _XcptFilter calls your handler that you established with SIGNALQQ, the only argument passed to your handler is the C signal number. The C runtime system also saves a pointer to the exception information supplied by the operating system. This pointer is named _pxcptinfoptrs and you can retrieve it through the Fortran runtime routine GETEXCEPTIONPTRSQQ. See C header file signal.h for the public definition of _pxcptinfoptrs.

The value returned by GETEXCEPTIONPTRSQQ can be used in your handler routine to generate a traceback with TRACEBACKQQ. GETEXCEPTIONPTRSQQ just returns _pxcptinfoptrs. This pointer is only valid while you are executing within the evaluation of the C runtime filter function _XcptFilter because the exception information is on the program stack, so do not use GETEXCEPTIONPTRSQQ in any other context.