Originale-mail to me for new edition

 

Exit procedures

 

Exit procedures ensure that specific actions such as updating and closing files are carried out before a program terminates. The ExitProc pointer variable allows you to install an exit procedure, so that it is always called as part of the program’s termination whether the termination is normal, forced by a call to Halt, or the result of a runtime error. An exit procedure takes no parameters.

Note:          It is recommended that finalization sections, rather than exit procedures, be used for all exit behavior. Exit procedures are available only for executables, shared objects (Linux) or .DLL (Windows) targets; for packages, exit behavior must be implemented in a finalization section. All exit procedures are called before execution of finalization sections.

Units as well as programs can install exit procedures. A unit can install an exit procedure as part of its initialization code, relying on the procedure to close files or perform other clean-up tasks.

When implemented properly, an exit procedure is part of a chain of exit procedures. The procedures are executed in reverse order of installation, ensuring that the exit code of one unit isn’t executed before the exit code of any units that depend on it. To keep the chain intact, you must save the current contents of ExitProc before pointing it to the address of your own exit procedure. Also, the first statement in your exit procedure must reinstall the saved value of ExitProc.

The following code shows a skeleton implementation of an exit procedure.

var

  ExitSave: Pointer;

procedure MyExit;

begin

  ExitProc := ExitSave;  // always restore old vector first

  ...

end;

begin

  ExitSave := ExitProc;

  ExitProc := @MyExit;

  ...

end.

On entry, the code saves the contents of ExitProc in ExitSave, then installs the MyExit procedure. When called as part of the termination process, the first thing MyExit does is reinstall the previous exit procedure.

The termination routine in the runtime library keeps calling exit procedures until ExitProc becomes nil. To avoid infinite loops, ExitProc is set to nil before every call, so the next exit procedure is called only if the current exit procedure assigns an address to ExitProc. If an error occurs in an exit procedure, it is not called again.

An exit procedure can learn the cause of termination by examining the ExitCode integer variable and the ErrorAddr pointer variable. In case of normal termination, ExitCode is zero and ErrorAddr is nil. In case of termination through a call to Halt, ExitCode contains the value passed to Halt and ErrorAddr is nil. In case of termination due to a runtime error, ExitCode contains the error code and ErrorAddr contains the address of the invalid statement.

The last exit procedure (the one installed by the runtime library) closes the Input and Output files. If ErrorAddr is not nil, it outputs a runtime error message. To output your own runtime error message, install an exit procedure that examines ErrorAddr and outputs a message if it’s not nil; before returning, set ErrorAddr to nil so that the error is not reported again by other exit procedures.

Once the runtime library has called all exit procedures, it returns to the operating system, passing the value stored in ExitCode as a return code.

 

Topic groups

 

See also

Library initialization code

Program control: Overview

 

 

译文

 

退出过程

 

退出过程(Exit procedures)确保指定的动作如更新和关闭文件等在程序终止之前被完成。指针变量ExitProc允许在程序中建立一个退出过程,因此它总是作为程序终止的一部分而被调用,不管终止是正常的,被强制调用Halt终止,还是由运行时错误导致的终止。退出过程不接受任何参数。

注意:       推荐利用结束节(finalization section),它用于所有的退出行为,并且优于退出过程。退出过程仅对可执行文件、共享对象(Linux)或.DLLWindows)是可用的;对于包,退出行为必须在结束节中实现。所有的退出过程在结束节执行之前被调用。

单元和程序一样可以建立退出过程。单元可以依靠关闭文件或执行其他清除任务的过程作为其结束节的一部分,以此来建立退出过程。

当实现适当时,一个退出过程就是一个退出过程链的一部分。所有退出过程的执行顺序与建立顺序相反,以确保一个单元的退出代码在其他依赖它的单元的退出代码执行之前不被执行。要完整无缺地保持退出过程链,必须在ExitProc被指向自定义退出过程之前保存其当前内容。而且,自定义退出过程中的第一条语句必须重新建立保存过的ExitProc变量的值。

下面的代码说明了一个退出过程的实现框架:

var

  ExitSave: Pointer;

procedure MyExit;

begin

  ExitProc := ExitSave;  //总是首先恢复旧的向量(退出过程的指针)

  ...

end;

begin

  ExitSave := ExitProc;

  ExitProc := @MyExit;

  ...

end.

在入口,代码保存了在ExitSaveExitProc的内容,然后建立MyExit作为退出过程。当MyExit作为终止处理的一部分被调用时,它所做的第一件事就是重新建立先前的退出过程。

运行时包中的终止例程保持对退出过程的调用,直到ExitProc成为nil。为避免无限循环,ExitProc在每次调用之前都被置为nil,因此仅当当前退出过程向ExitProc赋予一个非nil的地址时,下一个退出过程被调用。如果在一个退出过程中发生错误,那么退出过程不再被调用。

退出过程可以通过检查整型变量ExitCode和指针变量ErrorAddr来获悉导致终止的原因。正常终止时,ExitCode为零并且ErrorAddrnil。通过调用Halt终止时,ExitCode包含传给Halt的值且ErrorAddrnil。因运行时错误终止时,ExitCode包含一个错误代码且ErrorAddr包含了非法语句的地址。

最后的退出过程(被运行时包建立)关闭所有的输入(Input)和输出(Output)文件。如果ErrorAddr不是nil,那么将输出一个运行时错误消息。为输出自定义的运行时错误消息,应建立一个退出过程,该过程检查ErrorAddr并且如果该变量不是nil时输出一个消息;在返回前设置变量ErrorAddr的值为nil,以便错误不再被其他退出过程报告。

一旦运行时库调用了所有的退出过程,那么它将向操作系统返回一个值,即把存储在变量ExitCode中的值作为返回值传递。

 

相关主题

 

相关主题

库的初始化代码

程序控制:概述