Chapter Contents

Previous

Next
Using the indep Option for Interlanguage Communication

Execution Frameworks

In general, successful execution of code written in a high-level language requires the accessibility of an appropriate execution framework. An execution framework (also called an environment) is a collection of data and routines supporting the execution of code. (For example, memory allocation tables and error-handling routines are frequently components of an execution framework.) Note that for code to execute successfully, it is not sufficient for the execution framework to exist; it also must be accessible and available to the program. This means, in general, that machine registers must be set up to address components of the framework.

Since each language has its own conventions for access to its framework, it is usually impossible for more than one framework to be accessible at once. Therefore, a call from one language to another must switch frameworks, that is, make the new language's framework accessible (or active) before performing the call and restore the calling framework after the call is complete.


The C Execution Framework

The C execution framework includes the stack from which save areas and auto storage are allocated, the pseudoregister vector that contains extern and static data for reentrant programs, and the C Run-Time Anchor Block (CRAB). The CRAB contains constants and other information used by both compiled code and the library. The C framework also includes the default signal handlers set up by the library. When the C framework is active, register 12 addresses the CRAB. C functions compiled without the indep option expect register 12 to address the CRAB on entry; if it does not, the results are unpredictable.

When a C program compiled without the indep option is executed, the C framework is created by the L$CMAIN library routine. The execution of this routine precedes execution of the main function. L$CMAIN obtains storage for the CRAB, the pseudoregister vector, and the initial stack and heap and sets register 12 to address the CRAB.


C Execution Framework Creation with indep

The C framework is created when the first (or initial) C function is called. (This function is not necessarily named main .) Because this function is called before the C framework is created, it must be compiled with indep . (See main Function Considerations for one exception.)

When a C source file is compiled with the indep option, all the functions in the resulting object file have the following properties:

Therefore, a function compiled by indep can be called directly from outside of the C execution framework (for example, with another high-level language's framework active).

The primary characteristic of the object code generated when the indep compiler option is used is that the L$UPREP routine is invoked whenever a function compiled with the indep option is called. L$UPREP determines whether the C execution framework has been created. If the C framework has been created, the CRAB address is loaded into register 12 and execution of the called function proceeds normally. If not, L$UPREP invokes L$UMAIN, an initialization routine in the run-time library, to create the C framework. After the C framework is created (and the CRAB address is stored in register 12), execution of the initial function proceeds normally.

L$UPREP is provided in source code on the SAS/C installation tape. Therefore, you can modify its check for the existence of the C execution framework as necessary to suit your application. L$UPREP uses an assembler macro named L$UCENV to locate a word in which the CRAB pointer is to be saved for future reference. The L$UCENV macro sets R12 to the address of this word. As provided, L$UCENV defines a CSECT named L$UCENV to be used to hold the CRAB address.

Because all functions compiled with indep invoke L$UPREP, it does not matter which of these functions is called first. Whichever function is called first creates the C framework.


Specifying Run-Time Library Options

Normally, when a C program is invoked by the operating system, run-time library options are specified as part of the argument list passed by the operating system. However, when the initial function is compiled with the indep option, the arguments can have any type and therefore cannot be modified, or even inspected, by the library. For this reason, another mechanism must be used in such an application to specify run-time options.

One method is the normal technique of initializing external int variables named _options and _negopts and the external char variable named _linkage to specify the options required. (Refer to Run-Time Argument Processing for more details.) However, this technique can be used only when the options required are constant and known at compile time.

To support varying options (that is, options that can vary between executions), you can provide a routine named L$URTOP. This is an optional routine. If L$URTOP is not included in the load module, only default options (or those specified by external variables) are used. If L$URTOP is present in the load module, it is called during the initialization of the C framework, using standard linkage. No arguments are passed to it, and it should return the address of a run-time options string in register 15. The string should contain a halfword length field, followed by the required options. Note that the length contains the number of characters in the string, not the number of characters plus two. During later initialization processing, the string is tokenized exactly as if it came from a normal command line. However, if any of the tokens in the string are not run-time library options, diagnostic messages are generated.

Because SPE does not support run-time options, L$URTOP is not used with the SPE framework.

The following example shows a typical L$URTOP routine:


Sample L$URTOP Routine
********************************************************************** * * * L$URTOP is an optional routine to provide runtime arguments to * * Indep applications. * * * * In this example, the normal action is to specify a minimal set of * * run-time options. However by zapping the location DEBUGOPT, two * * completely different sets of options can be provided. * * * * When DEBUGOPT is set to 1 a different set options more suitable * * for limited debugging is specified. This set of options also * * define environment variables (APL1) meaningful to the application. * * Additionally, the runtime options at label ALTOPTST can be zapped * * to provide an entirely different set of runtime options when * * DEBUGOPT is set to 1. * * * * When DEBUGOPT is set to 2 a different set of options provide the * * information necessary to start the SAS/C Remote Debugger. * * * ********************************************************************** L$URTOP CSECT SPACE ********************************************************************** * Ensure AMODE/RMODE match those of the SAS/C Library Default * ********************************************************************** L$URTOP RMODE ANY L$URTOP AMODE 31 SPACE USING *,15 Tell Assembler B SETARGS Branch around eye-catcher DC AL1(L'EYECATCH) EYECATCH DC C' L$URTOP - Sample' DC XL1'00' Filler SPACE * Switch to determine which set of runtime options will be used SPACE DEBUGOPT DC XL1'00' SPACE SETARGS DS 0H STM 14,12,12(13) Save entry regs in callers area SPACE LA 1,STDOPTS Default to standard runtime CLI DEBUGOPT,0 Has switch been set for alternate? BE RETARGS No, return standard runtime SPACE * Alternate has been requested, set as indicated or take the default CHKALT DS 0H Check for Alternate runtime CLI DEBUGOPT,1 Has switch been set for alternate? BNE CHKRMT No, check for Remote Debugger LA 1,ALTOPTS Yes, return optional runtime B RETARGS CHKRMT DS 0H Check for Remote Debugger Setup CLI DEBUGOPT,2 Has switch been set for Debug Rmt? BNE RETARGS No, return standard runtime LA 1,DBGRMT Yes, return Debugger Remote runtime SPACE RETARGS LR 15,1 Point R15 at runtime arguments DROP 15 SPACE L 14,12(,13) Restore R14 LM 0,12,20(13) Restore other registers BR 14 Return to caller LTORG , ********************************************************************** * Minimal Options * ********************************************************************** STDOPTS DC AL2(L'STDOPTST) STDOPTST DC C'=VERSION' Standard - runtime SPACE ********************************************************************** * Alternate options providing additional information * ********************************************************************** ALTOPTS DC AL2(L'ALTOPTST) Alternate- runtime ALTOPTST DC CL80'=BTRACE =WARNING =FDUMP =APL1=DEBUG =STORAGE' DC 0D'0' Filler SPACE ********************************************************************** * Alternate options which provide setup information for the SAS/C * * Remote Debugger. * ********************************************************************** DBGRMT DC AL2(DBGLEN) RmtDebug - runtime RMTOPTS DC C'=_DB_COMM=TCPIP ' DC C'=_DB_HOST=124.383.1.2 ' DC C'=_DB_PORT=3123 ' DC CL80'=DEBUG =VERSION' DC 0D'0' Filler DBGLEN EQU *-RMTOPTS SPACE END


C Execution Framework Access

Once L$UMAIN has created the C execution framework, it is necessary to ensure that it is accessible when any C function executes. For a function compiled with indep , L$UPREP is responsible for making the C framework accessible by loading the CRAB address into register 12. Functions compiled with indep can thus be invoked from outside the C framework (for example, from another high-level language).

Functions compiled with indep can also be invoked from other C functions. In this case, the C framework is already accessible. L$UPREP is responsible for determining whether a function compiled with the indep option was called from C or from a non-C routine and for avoiding unnecessary or incorrect processing if the call is from C. If you modify the supplied L$UPREP routine only by replacing the L$UCENV macro, this check is performed automatically, and the code to find the C framework generated by L$UCENV is executed only for a call from non-C code.

C functions compiled without indep also can be used in a multilanguage environment. Because such functions do not invoke L$UPREP, they can be called only from other C functions. Calls to these functions execute slightly faster because L$UPREP is not invoked, so you may want to compile only functions that are called from C without using the indep option.


C Execution Framework Termination

After all C functions have completed execution and before the current task or command returns to the operating system, the C framework should be terminated. This enables memory to be freed, output buffers to be flushed, files to be closed, operating system exits such as ABNEXITs and ESTAEs to be cleared, and so on. When a C program that was compiled without indep terminates, the C framework is terminated automatically. When you use indep for calling C from another language, it usually is your responsibility to terminate the C framework after all calls to C functions have completed.

Unless the initial C function is named main , the C framework created by the initial call to C exists indefinitely. (See main Function Considerations for information on this special case.) Therefore, subsequent C functions can access external variables set by previous functions, read and write opened files, and so on. In this case, you should ensure that the C execution framework is terminated when all C functions have completed.

To terminate the C execution framework, call the termination routine L$UEXIT. Be sure to call L$UEXIT only after all non-C routines called from C have returned; premature termination of the C framework causes errors on return from such routines. Failure to call L$UEXIT can cause incomplete file output (if files have not been closed) or can waste system resources or both. Note that you can avoid the problem of incomplete file output by closing all files yourself, including the standard files.

The execution framework may also be terminated by calling the standard exit function, but exit can be called only by a C routine, while L$UEXIT can be called by either C or non-C code.

Note that both L$UEXIT and exit return to the program that called the first currently active C function. Since L$UEXIT is a C function, L$UEXIT returns to the routine that called it, assuming no other C routine was active at the time of the call. Because exit must be called by a C function, exit never returns to its caller.

The name L$UEXIT cannot be referenced in FORTRAN and COBOL because of restrictions in these languages. For the convenience of users of these languages, the name CEXIT can be used instead of L$UEXIT.


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.