/* * i n i t i a . h */ /*)LIBRARY */ #ifdef DOCUMENTATION title initial Specify Initializers and Finalizers index Specify initializers and finalizers synopsis #include INITIAL { initial-code-block }; FINAL { final-code-block }; description The macros defined in this module provide a facility for module-specific initialization and finalization code. The code in the initial-code-block is called as a normal C function before main() is called; the final-code-block is called on exit, just after wrapup(). Neither call passes any arguments. Any number of modules in an image may independently declare initializers or finalizers; all of them will be called at startup or exit. However, it is impossible to predict what order the calls will be made in, and programs should not rely on any particular ordering. A typical use of initializers and finalizers is the following: Suppose you have a package that supports access to some on-disk data base; a user of the package will call a lookup and an update function. The file containing the data base must be opened before any operations on it can take place, and it should be closed when the program is finished. (Assume that the package maintains some sort of resident buffer which it must flush.) There are two conventional approaches to solving this problem: Have the lookup and update functions check the file on each call, and open it if necessary - which could be quite expensive if they are very small functions, and in any case does not solve the problem of properly closing the file - or have the main program call an initialization and finalization function at the proper time. The problem with this latter approach is lack of modularity - the main program ought not to have to know that the module needs initialization or finalization. The solution using these macros is straightforward. The defining module includes the calls: INITIAL { open-the-data-base }; FINAL { flush-buffers-and-close-the-data-base }; The wrapup() function is treated like a built-in finalizer; however, it is guaranteed to execute before any other finalizers. (The module defining wrapup() may declare an initializer or finalizer if it wishes; it will be treated just like all other initializers and finalizers.) If any finalizer (or wrapup()) calls exit(), the program exits immediately. Notes: Using INITIAL will declare a static function named $init$(), and a (char *) named $init_; similarly, FINAL will declare $finl$() and $finl_. Also, both INITIAL and FINAL generate dsect commands. Since C provides no way to "remember" the current dsect, both macros issue a dsect "" command when they are done, restoring the C default dsect. While it is a poor idea to write code that depends on the order in which initializers and finalizers are executed, this can be useful information to have for debugging. Execution is always in the order that the modules involved were examined by the task builder or linker. When the modules are named explicitly, this will just be the order in which they were named. When the modules come from a library, it will be extremely difficult to predict the order in which they will be extracted and linked in. Warning: While initializers and finalizers provide some modularity to package initialization and finalization, they are not a panacea. For example, if package A calls routines in package B from within its initializers, and package B also declares initializers, the correct functioning of a program that includes both - hence, of any program using package A - will be problematical. internal The macros operate by leaving a list of (pointers to) functions to be called in psects $INIT$ and $FINL$. In order to be able to determine the beginning and end of these psects, the psects $INIT, $FINL, $INIT., and $FINL., are also reserved. These psects must not actually contain any data; they exist solely to provide well-defined endpoints to the initialization and finalization list. The names are consecutive in alphabetical sequence, so the Task Builder will place them in order. The RT11 Linker, however - and the Task Builder with the /SQ switch - place psects in the order they are encountered. Since it impossible to predict what order the various modules will be seen by the linking program, it is essential that EVERY module that refers to any of these psects refer to the two related ones as well, and in the correct order. bugs Requires the DECUS C dsect commands; hence, very non-portable. It may be possible to provide the same functionality using different techniques; if not, what's wrong with your implementation? author Jerry Leichter #endif /* )EDITLEVEL=05 * Edit history * 0.0 19-Jul-82 JSL Invention * 0.1 22-Nov-82 JSL Documentation cleanups only; much of the documentation * gets duplicated in initia.mac. */ #define INITIAL dsect"$init ";dsect"$init$";static char *$init_ = &$init$;dsect"$init.";dsect"";static $init$() #define FINAL dsect"$finl ";dsect"$finl$";static char *$finl_ = &$finl$;dsect"$finl.";dsect"";static $finl$() /* * Sorry about the scrunched code; DECUS C has some size limits on #define * lines that are a pain. Here's the code "in the clear": * * #define INITIAL dsect "$init "; \ -- Declare the dsects in the * dsect"$init$"; \ right order * static char *$init_ = &$init$; \ -- Pointer to the function * dsect"$init."; \ -- Another dsect in order * dsect""; \ -- Back to the default * static $init$() -- Declare the function * * The code for FINAL is essentially the same. */