• Keine Ergebnisse gefunden

The FatalError Procedure and the fDevelopement Flag

Im Dokument Standards Programming (Seite 75-80)

FatalError allows the program to control its mode of termination. Most standard object modules distributed with CTaS call FatalError or CheckErc when they encounter errors. CheckErc also calls FatalError when it detects an error.

Normally, FatalError just calls ErrorExit with the encountered error code, but you can substitute your own procedure for it. For example, a system service might include a FatalError routine that causes the service to deinstall itself. This allows system services to call object module procedures without concern for the error handling within those procedures.

The FatalError procedure also checks a flag, fDevelopement (misspelled for historical reasons), before it terminates the program. If this flag is set to any value other than zero, FatalError enters the Debugger instead of calling Error Exit.

To use the fDevelopement flag, just declare it as an external unsigned byte variable in your program and set it to TRUE. All calls to FatalError will then enter the Debugger instead of exiting.

Program Exit Modes: Exit, ErrorExit, ErrorExitString, and Crash

Each program must choose the appropriate exit mode when it encounters a severe error. In general, Exit should only be used after successful completion of a program's execution. When a program must exit on error, it should usually call FatalError, but can call ErrorExit or ErrorExitString directly if it needs to.

ErrorExitString works like ErrorExit, except that it allows the program to supply an information string along with the error code. The information string can be displayed or examined by the exit run file.

Crash should be used only when absolutely necessary. For example, after a system service is installed, it may need to call Crash if it detects an error which may affect other programs, and from which it cannot recover.

This prevents the system from spreading the effect of the error to other

3-2 eTOS/Open Programming Practices and Standards - Part I

applications. Crash should only be used in those rare cases when not crashing the system could result in consequences worse than crashing.

For example, if a system service that filters calls to the file system encounters a severe error, the consequences could affect any program that opens a file. In this case, the service should probably call Crash.

Trapping Protection Faults

Under some circumstances, an application may need to trap any protection faults it causes. For example, a system service may want to enter diagnostic information in the system error log, then deinstall itself whenever it encounters a protection fault.

Also, an application program might want to trap protection faults and ensure that any critical information is written to disk before it exits. For example, the Editor traps faults in order to write its recovery typescript file to disk before exiting.

Listing 3-2 shows a procedure to set up a protection fault handler, and the procedure called by the fault handler. Note that any procedure called by a fault handler must exit in some manner. It can never return to the main program, or to the procedure that caused the fault.

Listing 3-3 shows the fault handler itself, which is written in Assembly language. Because they are trap handlers, all protection fault handlers must be written in Assembly language. For more information about trap handlers, see Chapter 19, "Interrupt Handlers" in Part II of this guide.

Error Handling Conventions 3-3

typedef void (*PF)()i /* pointer to function */

if(erc=SetTrapHandler(13, (Pointer)_fault_handler) != 0) exit(erc)i

erc

=

LogMessage(&logmsg, strlen(logmsg) )i if(erc

==

290) /* buffer full erc */

Delay(l)i /* delay then retry */

) while(erc == 290)i ErrorExit(80)i

}

Listing 3-2. Setting a Protection Fault Handler

3-4 eTOS/Open Programming Practices and Standards - Part I

; FaultHandler.asm -- generic GP fault handler extrn ErrorExit:far

DGroup group Data assume ds: DGroup

Data segment word public 'Data'

;tell the Assembler about p_fault_handler extrn p fault handler:WORD

FaultHandler segment word 'code' assume cs: FaultHandler

movax, ds:word ptr p_fault_handler movdx, ds:word ptr p_fault_handler + 2

Listing 3-3. Assembly Routine for Generic Trap Handler

Error Handling Conventions 3-5

Error Logging: WriteLog

Listing 3-4 shows a procedure that receives a text string as its parameter, then enters that string in the system error log. Because the error log buffer can become full, the calling procedure should check for that condition and take appropriate action. For example, the HandleFault routine in Listing 3-2 uses a delay loop to ensure that the message is always logged.

Error logging should be used for any situation in which an error may be difficult to trace. For example, if a system service encounters a severe error, and deinstalls itself as a result, it should log the occurrence. It should also log any additional information the user may need to determine the source of the error.

A program's entry in the system log must have a record type of OFFF7h.

This record type tells the system that the log entry is a text message.

Using any other record type may result in an unreadable entry in the system log. WriteLog does not check for invalid user entries.

/* LogMessage - Routine that correctly logs a text string

*/

Word LogMessage(Pointer pbMessage, Word cbMessage) (

ErcType ere;

struct (

Word TextCode; /* value to indicate msg to Plog */

Word cbText;

Byte rgbText[120];

) LogMsg;

LogMsg.TextCode

=

OxFFF7; /* must always be OxFFF7 */

LogMsg.cbText

=

cbMessage;

/* copy the message to the LogMsg structure */

memcpy(&(LogMsg.rgbText), pbMessage, cbMessage);

/* write the entry and return the erc */

return(WriteLog(&LogMsg, cbMessage + 4»;

}

Listing 3-4. Procedure to Create a System Error Log Entry

3-6 eTOS/Open Programming Practices and Standards - Part I

4

Im Dokument Standards Programming (Seite 75-80)