[ Next ] [ Previous ] | Chapter 7 |
When a synchronous exception occurs, the operating system sends an exception just to the thread causing the exception. If the operating system terminates the application, a XCPT_ASYNC_PROCESS_TERMINATE is sent to all the other threads in the process.
When an asynchronous exception occurs, the operating system sends an
exception just to the main thread.
/* Registers an exception handler for
the current thread. */
#define INCL_DOSEXCEPTIONS
#include <os2.h>
/* A pointer to the exception
registration record that describes the exception handler to be registered.
*/
PEXCEPTIONREGISTRATIONRECORD
pERegRec;
APIRET
ulrc; /* Return Code. */
ulrc = DosSetExceptionHandler(pERegRec);
Exception handlers can be "nested" as a chain of exception-handling functions. The operating system will call the last handler in the chain: after that function has completed, it may call the next-to-last handler, and so on. An exception handler will do its work and then rerun a value to the operating system that indicates whether to continue with the next exception handler registered in the chain or to dismiss the exception.
General use for exception handlers are to handle memory
faults, and Guard Page example will show the exception handler
working with a memory fault.
Memory exceptions can occur when an application attempts to access
a guard page, attempts to use memory that has been allocated but not committed
(a sparse memory object), or when an application attempts to
write to memory that has read-only access. Without an application-registered
exception
handler, some of these exceptions might cause the application
to terminate. If the application registers its own exception handler, it
can correct the cause
of the memory fault and continue to run.
Gotcha!
On the other hand, massive usage of memory exceptions for memory allocation
in application program has one, but very unpleasant drawback. Debugger
also use memory exception handlers for catching up memory violation errors
and programmer should think enough before using memory exceptions technique
for memory allocation.
|
The EXCEPTIONREGISTRATIONRECORD data structure forms a linked list of exception handlers. The first element in the structure is a pointer to either the next exception handler or an end-of-list marker, and is filled in by the operating system. The second is a pointer to the exception-handling function currently being registered and should be filled in by the developer. When registering an exception handler, this structure must be local to the procedure that contains DosSetExceptionHandler, as opposed to a global structure.
Gotcha!
Before exiting your program, make sure you call the function DosUnsetExeptionHandler. If you do not, you will probably see a stack overflow error. |
APIRET APIENTRY myHandler(PEXCEPTIONREPORTRECORD
pERepRec,
PEXCEPTIONREGISTRATIONRECORD pERegRec,
PCONTEXTRECORD pCtxRec,
PVOID p)
The EXCEPTIONREPORTRECORD structure is a data structure that describes the exception and includes the exception type and other exception information.
/*
This structure contains
machine-independent information about an exception or unwind. No system
exception will ever have more parameters than the value of EXCEPTION_MAXIMUM_PARAMETERS.
User exceptions are not bound to this limit.
*/
typedef STRUCT _EXCEPTIONREPORTRECORD
{
ULONG
ExceptionNum; /* Exception number. */
ULONG
fHandlerFlags; /* Handler flags. */
STRUCT _EXCEPTIONREPORTRECORD
*NestedExceptionReportRecord; /* Nested exception report
record structure. */
PVOID
ExceptionAddress; /* Address of the exception. */
ULONG
cParameters; /* Size of exception
specific information. */
ULONG
ExceptionInfo[EXCEPTION_MAXIMUM_PARAMETERS]; /* Exception
specific information. */
} EXCEPTIONREPORTRECORD;
typedef EXCEPTIONREPORTRECORD *PEXCEPTIONREPORTRECORD;
The EXCEPTIONREGISTRATIONRECORD structure is described in the last section. "How to Register an Exception Handler."
/* These structures are linked
together to form a chain of exception handlers that are dispatched upon
receipt of an exception. Exception handlers should not be registered
directly from a high level language such as "C". This is the responsibility
of the language runtime routine.
*/
typedef struct _EXCEPTIONREGISTRATIONRECORD
{
STRUCT _EXCEPTIONREGISTRATIONRECORD
*prev_structure; /* Nested exception registration
record structure. */
_ERR
*ExceptionHandler; /* Pointer to the ERR function. */
} EXCEPTIONREGISTRATIONRECORD;
typedef EXCEPTIONREGISTRATIONRECORD *PEXCEPTIONREGISTRATIONRECORD;
The CONTEXTRECORD structure (as it is described in \TOOLKIT\H\BSEXCPT.H)
struct _CONTEXT
{
/* The flags values
within this flag control the contents of a ContextRecord.
* If the ContextRecord
is used as an input parameter, then for each portion
* of the ContextRecord
controlled by a flag whose value is set, it is assumed that that
* portion of the
ContextRecord contains valid context. If the ContextRecord
* is being used
to modify a thread's context, then only that
* portion of the
thread's context will be modified.
* If the ContextRecord
is used as an Input/Output parameter to capture the context
* of a thread,
then only those portions of the thread's context corresponding
* to set flags
will be returned.
*/
ULONG ContextFlags;
/* This section is specified/returned
if the ContextFlags
* contains the
flag CONTEXT_FLOATING_POINT.
*/
ULONG ctx_env[7];
FPREG ctx_stack[8];
/* This section is specified/returned
if the ContextFlags
* contains the
flag CONTEXT_SEGMENTS.
*/
ULONG ctx_SegGs;
ULONG ctx_SegFs;
ULONG ctx_SegEs;
ULONG ctx_SegDs;
/* This section is specified/returned
if the ContextFlags
* contains the
flag CONTEXT_INTEGER.
*/
ULONG ctx_RegEdi;
ULONG ctx_RegEsi;
ULONG ctx_RegEax;
ULONG ctx_RegEbx;
ULONG ctx_RegEcx;
ULONG ctx_RegEdx;
/* This section is specified/returned
if the ContextFlags
* contains the
flag CONTEXT_CONTROL.
*/
ULONG ctx_RegEbp;
ULONG ctx_RegEip;
ULONG ctx_SegCs;
ULONG ctx_EFlags;
ULONG ctx_RegEsp;
ULONG ctx_SegSs;
};
typedef struct _CONTEXT CONTEXTRECORD;
typedef struct _CONTEXT *PCONTEXTRECORD;
is an input/output parameter that contains register
contents at the time of the exception. If the exception handler will return
XCPT_CONTINUE_EXECUTION, the structure can be modified. If it is modified
without XCPT_CONTINUE_EXECUTION being specified, very bad things will happen.
The last parameter, the DISPATCHERCONTEXT structure,
is undocumented because it should never be modified.
The 486 chip uses the address at FS:0 so point
to the address of the first exception registration record. Many compilers
implement exception handlers by modifying this value directly, rather than
using the OS/2 API, in order to improve performance.
In a order to receive the Ctrl+C and the Ctrl+Break exceptions, the thread must call DosSetSignalExeptionFocus. The kill process signal is sent whether this function is used or not.
GP.CWhen an exception occurs, information about the exception is placed in the EXCEPTIONREPORTRCORD structure, and a pointer to these structures is passed to the exception handler.
GP.MAK
GP.DEF
typedef STRUCT _EXCEPTIONREPORTRECORD
{
ULONG
ExceptionNum; /* Exception number. */
ULONG
fHandlerFlags; /* Handler flags. */
STRUCT _EXCEPTIONREPORTRECORD
*NestedExceptionReportRecord; /* Nested exception report
record structure. */
PVOID
ExceptionAddress; /* Address of the exception. */
ULONG
cParameters; /* Size of exception
specific information. */
ULONG
ExceptionInfo[EXCEPTION_MAXIMUM_PARAMETERS]; /* Exception
specific information. */
} EXCEPTIONREPORTRECORD;
ExceptionNum is the field that tells the type of
exception that
has occurred. In our case, we're looking for a
XCPT_GUARD_PAGE_VIOLATION.
If the exception is not a guard page, we pass it on through to the
system
exception handler by returning XCPT_CONTINUE_SEARCH. If a guard-page
exception
occurs, we check to see if we have enough memory to commit one more
page. If the memory is available, we commit another page and set it as
a guard
page. The last thing we do is return XCPT_CONTINUE_EXECUTION, which
tells
the system to bypass the other exception handler and continue executing
the program. The errant function statement will execute correctly, and
the program functions as if no problems had occurred.
[ Next ] [ Previous ] | Chapter 7 |