Chapter Contents

Previous

Next
Code Generation Conventions

Reentrant and Non-reentrant Identifiers

This section describes reentrant and non-reentrant identifiers and explains how to use the rent , rentext , and norent compiler options as well as the __rent and __norent keywords to control whether an identifier is reentrant or non-reentrant.

The reentrant and non-reentrant attributes apply only to extern or static data. All functions, parameters, and automatic data are automatically reentrant.


Non-reentrant Identifiers

Non-reentrant data reside in a CSECT and are thus a part of the load module at execution time. If the program modifies non-reentrant data, it is modifying its own load module, thus rendering itself non-reentrant (that is, the same copy cannot be executed by multiple users or in multiple tasks simultaneously).

The compiler places non-reentrant data in the static CSECT. Wherever possible, non-reentrant data are initialized at compile time and are referenced using address constants (ACONs).


Reentrant Identifiers

Reentrant data are placed in the PRV (pseudoregister vector). The PRV is an area of memory allocated by the run-time library when the C program is executed. Thus, reentrant data can be freely modified without affecting the reentrancy of the program.

Reentrant data are referenced using Q-type address constants (QCONs). The QCON for a reentrant identifier contains the offset of the identifier from the start of the PRV. The offset is added to the address of the PRV to obtain the address of the data.


Placement of Data

In general, static and extern identifiers can be placed in either the non-reentrant section or the reentrant section (PRV). A number of rules control where a particular identifier is placed.

First, if you code an explicit __rent or __norent keyword, then the identifier is always placed in the section specified. With __rent and __norent you can control which section is used.

If you do not provide an explicit keyword, then generally the rent , rentext or norent compiler option determines the section into which the identifier is placed. rent places both externs and statics (without a __rent or __norent keyword) in the reentrant section. norent places them both in the non-reentrant section. rentext places externs in the reentrant section and statics in the non-reentrant section.

There are two exceptions (cases where the compiler option is overridden). The first exception occurs with extern identifiers whose names start with an underscore. These are always placed in the reentrant section. (The ISO/ANSI C Standard reserves such names for use by the compiler implementor).

The second exception occurs if the const keyword is used. const declares constant data. Since the data are not expected to change during program execution, the compiler tries to promote const identifiers into the non-reentrant section. The rules for this are fairly complicated. An identifier is promoted to the non-reentrant section if all of the following are true:

The const type qualifier is ignored (not used to place the data object in the string literal CSECT) in the following situations:

The last exception is a situation in which the pointer value cannot be determined until execution time; therefore, a value in the CSECT cannot be initialized without violating reentrancy.


Initialization and Reentrancy

If you plan for your program to be reentrant, you should not modify any data in the non-reentrant section when the program executes. You may also need to be careful when initializing non-reentrant data. Most initializations are done at compile time, which preserves reentrancy, but there are a couple of exceptions:

To help you in such situations, the compiler produces a warning diagnostic if all of the following conditions are true:

For a reentrant program, a simple way to avoid problems is to use only reentrant data. If your program is not intended to be reentrant, none of these considerations need concern you.


Declarations Must Agree

If you declare an identifier reentrant in one place and non-reentrant in another, you can end up with two different identifiers in the same compilation. Each of these identifiers will reference a location that is different from the other. The compiler will produce an error message in this situation.

This applies not only to explicit use of the __rent and __norent keywords, but to the implicit assignment of data to the reentrant and non-reentrant section using compiler options and the const keyword, as described above.

All declarations of an identifier must agree. Use the same rent , rentext , and norent settings for all compilations, or use the __rent or __norent keywords.


Cross-reference

The cross-reference tells you whether an identifier is reentrant ( rent is listed) or non-reentrant ( norent is listed). This information is produced regardless of how the reentrancy was determined (keywords, compilation options, etc). This may be helpful to you in cases where the rules above are not clear.


Sharing External Variables with Assembler Language Programs

External variables stored in the static CSECT can be accessed from assembler language programs via a V-type address constant (VCON). Accessing an external variable stored in a pseudoregister must be done indirectly by computing the offset of the variable in the pseudoregister vector. The address of the pseudoregister vector is stored at decimal offset 12 from the address in general register 12. (This area is known as CRABPRV.) Sample Assembler Language Routine for Accessing an External Variable Stored as a Pseudoregister sketches an assembler language routine that accesses an external variable stored as a pseudoregister.


Sample Assembler Language Routine for Accessing an External Variable Stored as a Pseudoregister
LRX,12(,R12) Set RX to point to CRABPRV. This assumes that register 12 has the CRAB address. ALRX,=Q(ZZZ) RX now contains the address of the external variable USING ZZZ,RX ZZZ. ZZZ is the name of the variable as defined in the C program. MVCZZZ1,=F'2' Set integer variable to 2. . . . ZZZ DSECT Identify the dummy section ZZZ. ZZZ1 DSF


Sharing External Variables with FORTRAN Programs

It is possible for a C program that has been compiled with rent or rentext to share data with FORTRAN programs. The values to be shared are in one or more FORTRAN COMMON blocks, where FORTRAN code can access them directly. C code accesses the COMMON blocks through function pointers. Each COMMON block is described by a C structure, with the structure tag the same as the name of the COMMON. Each COMMON block code is declared as a function of the same name. For example, the following code declares the COMMONs named comona and comonb :

extern comona();
extern comonb();

C code accesses the COMMONs through pointers. Each pointer is set up by invoking a macro, called COMPTR , in the example below. The complete definition for the comona structure is assumed to be elsewhere in the program:

#define comptr(block) (*(struct block**)&block)
.
.
.
struct comona *aptr;   /* Declare aptr as pointer to comona struct. */

aptr = comptr(comona);
aptr->field1 = 1;
.
.
.

Note that the structure tag, comona , is the same as the name of the COMMON. This is not required, but it simplifies the macro and makes the data sharing more obvious.

The technique is readily adaptable to other languages that implement shared data as CSECTs or COMMONs. However, this technique renders an otherwise reentrant program non-reentrant, by the nature of such implementations. See Chapter 16, "Implementing ILC with a User-Supported Language," in the for more details.


Chapter Contents

Previous

Next

Top of Page

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