Using SIGNALQQ and How SIGNALQQ Works

For light-weight 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 GETEXCEPTIONPTRSQQ works.

Reference is made to C run-time sources provided with Microsoft Visual C++. The discussion is worth reviewing even if you do not have Visual C++ available though. The following topics are discussed:

C-Style Signal Handling Overview

Many Fortran applications were developed on U*X 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. It does not work well, for example, in a VB-VF application.

SIGNALQQ is just a Fortran jacket to the C run-time signal() function. When you call SIGNALQQ, you are actually registering your signal handler (or action) for a particular signal with the C run-time system. The C run-time 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 run-time signal routine in ...\MICROSOFT VISUAL STUDIO\VC98\CRT\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 run-time 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 run-time system that calls your handler when a signal occurs, not the operating system. So how did the C run-time 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 back to the section Structure of a Visual Fortran Application and look at these entry points (or look at source file Crt0.c in the C run-time 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 which 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 run-time system and thus the except construct associated with main, the Fortran run-time filter will be evaluated before the C run-time 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 run-time 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 run-time 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 (as of Visual C++ version 6.0):

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 run-time 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 run-time 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 run-time 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 run-time filter function _XcptFilter because the exception information is on the program stack, so do not use GETEXCEPTIONPTRSQQ in any other context.

See the sample program ...\SAMPLES\EXCEPTIONHANDLING\GETEPTRS for a working example of using GETEXCEPTIONPTRSQQ.