Go to the previous, next section.
This document is for the C programmer who wishes to use ILU. (By C, we mean the language defined in the ISO/ANSI standard, not `K&R C', or `Portable C'.) The following sections will show how ILU is mapped into C constructs and how both C clients and servers are generated and built.
Using ILU with C is intended to be compatible with the OMG CORBA specification. That is, all of the naming and stub generation comply with the Common Object Request Broker Architecture, revision 2.0. (6)
Note that ILU does not support non-ANSI variants of the C language. In particular, it relies on having prototypes, all C library functions, and the capabilities of the C pre-processor.
When functions are described in this section, they are sometimes accompanied by locking comments, which describe the locking invariants maintained by ILU on a threaded system. See the file `ILUHOME/include/iluxport.h' for more information on this locking scheme, and the types of locking comments used.
A number of macros are used in function descriptions, to indicated optional arguments, and ownership of potentially
malloc'ed objects. The macro OPTIONAL(type)
means that the value
is either of the type indicated by type, or the value NULL
. This macro
may only be used with pointer types. The macro RETAIN(type)
indicates, when used on a parameter, that the caller retains ownership of the value,
and when used in the result position, that the called function retains ownership of the
value. The macro PASS(type)
indicates, when used on a parameter,
that the caller is passing ownership of the storage to the called function, and when
used in the result position, that the called function is passing ownership of the called
value to the caller. The macro GLOBAL(type)
means that neither
the caller nor the calling function owns the storage.
In general, ILU constructs C names from
ISL names by replacing hyphens with underscores. Type names and class
names are prepended with their interface name. For example, for
the ISL type T-1
in interface I
,
the generated name of the C type would be I_T_1
.
Method name prefixes are specified by CORBA to be
module-name_interface-name
.
C function names for ISL methods are composed of the generated class name prepended to
the method name. For example, if the interface name is X
and the
class type name is Y
and the ISL method name is Z
then the
C callable method name will be X_Y_Z
.
ILU C servers for this method must implement a function called server_X_Y_Z
.
For field names within records and unions, hyphens are replaced with underscores.
The ISL interface
is mapped to a prefix for all generated
type names, constant names, and exception names, by replacing all hyphens
in the interface name with underscore characters.
The following basic ISL types have the corresponding mappings in C, as specified by the CORBA 2.0 standard mapping for C:
BOOLEAN
maps to C CORBA_boolean
BYTE
maps to C CORBA_octet
CHARACTER
maps to C CORBA_wchar
SHORT CHARACTER
maps to C CORBA_char
CARDINAL
maps to C CORBA_unsigned_long
SHORT CARDINAL
maps to C CORBA_unsigned_short
LONG CARDINAL
maps to C CORBA_unsigned_long_long
INTEGER
maps to C CORBA_long
SHORT INTEGER
maps to C CORBA_short
LONG INTEGER
maps to C CORBA_long_long
REAL
maps to C CORBA_double
SHORT REAL
maps to C CORBA_float
LONG REAL
maps to C CORBA_long_double
ISL constants are translated to C const
expressions
initialized to the specified value. Constant names are prepended with their interface name,
separated from the name of the constant with a hyphen character.
ISL character
and short character
types are represented
with the ILU types ilu_character
, which hold values of 16-bit Unicode,
and ilu_shortcharacter
, which hold values of 8-bit ISO Latin-1.
String sequences (SEQUENCE OF SHORT CHARACTER
or SEQUENCE OF CHARACTER
)
are just arrays of the character codes for the characters, using either Latin-1 codes (for
SEQUENCE OF SHORT CHARACTER
), or ISO 10646 Unicode codes (for SEQUENCE OF CHARACTER
).
These sequences are terminated with a character code of zero. The terminating code is not
counted in the length of the sequence.
ILU pickles are mapped to opaque structures of the type CORBA_any
, as per the CORBA specification
for the type any
. However, in ILU, the fields of the pickle are not directly accessible. Instead, the following utility functions are provided to manipulate pickles:
Function: PASS(CORBA_any *) ILU_C_Any_Create (RETAIN(CORBA_TypeCode) typecode, RETAIN(void *) value, RETAIN(CORBA_Environment *) env)
Locking: n/a
Create a new pickle from a C value and typecode. The return value is heap-allocated.
Function: PASS(CORBA_any *) ILU_C_Any_Init (RETAIN(CORBA_any *) uninitialized-any, RETAIN(CORBA_TypeCode) typecode, RETAIN(void *) value, RETAIN(CORBA_Environment *) env)
Locking: n/a
Given a pointer to an uninitialized
value uninitialized-any, sets the typecode and value of the any to the specified typecode and value.
CORBA_any
Function: PASS(CORBA_any *) ILU_C_Any_ResetValue (RETAIN(CORBA_any *) initialized-any, RETAIN(CORBA_TypeCode) typecode, RETAIN(void *) value, RETAIN(CORBA_Environment *) env)
Locking: n/a
Given a pointer to a previously used
value initialized-any, frees the current value and sets the typecode and value of the any to the specified typecode and value.
CORBA_any
Function: PASS(void *) ILU_C_Any_Value ({RETAIN(CORBA_any *)} pickle, {RETAIN(CORBA_Environment *)} env)
Locking: n/a
Returns the C value from the pickle. Returns NIL if the type of the value contained in the pickle is not `known' to the ILU C runtime. Relatively expensive, as it involves several malloc's.
Function: CORBA_TypeCode ILU_C_Any_TypeCode ({RETAIN(CORBA_any *)} pickle, {RETAIN(CORBA_Environment *)} env)
Locking: n/a
Retrieve the CORBA typecode of the value in the pickle. Returns NIL if the type of the value in the pickle is not registered with the ILU C runtime.
Function: PASS(CORBA_any *) ILU_C_Any_Duplicate (RETAIN(CORBA_any *) pickle, RETAIN(CORBA_Environment *) env)
Locking: n/a
Make a copy of an existing pickle without `looking inside'. This call will work even with pickle values that are of types not known to the ILU C runtime.
ISL enumeration types are mapped C enum types, in an exception to the CORBA
specification. Each element of the enumeration is named as <interface>_<element-name>
.
The C enum
type is typedef
'ed to the specified name for the type. For example, the ISL
definition
INTERFACE Foo; ... TYPE Color = ENUMERATION Red, Green, Blue END; ...would produce the following C definition:
typedef enum { Foo_Red, Foo_Green, Foo_Blue } Foo_Color;
Arrays are represented as C arrays.
INTERFACE I;
TYPE T2 = SEQUENCE OF T1;
Sequence Method: PASS(I_T2*) I_T2_Create ( OPTIONAL(unsigned long) length
, OPTIONAL(T1 *) initial-values
)
This function creates and returns a pointer to a newly allocated
instance of T2. If length is specified,
but initial-values is not specified, enough space for length values of type T1
is allocated in the sequence. If initial-values is specified, length is assumed
to be the number of values pointed to by initial-values, and must be specified.
Note that if type T1 is a character
or short character
type, a pointer
to a NIL-terminated sequence will be returned; otherwise, a normal CORBA sequence structure
will be returned by reference.
Sequence Method: CORBA_unsigned_long I_T2_Length ( I_T2 * s )
Returns the length of s.
Sequence Method: void I_T2_Append ( I_T2 * s, T1 value )
Appends value to the end of s. This function will reallocate space and copy, if necessary.
Sequence Method: void I_T2_Push ( I_T2 * s, T1 value )
Pushes value on to the beginning of the sequence. This function will reallocate space and copy, if necessary.
Sequence Method: void I_T2_Pop ( I_T2 * s, T1 * value-ptr )
Removes the first value from the sequence s, and places it in the location pointed to by value-ptr.
Sequence Method: void I_T2_Every ( I_T2 * s, void (*func)(T1, void *), void * data )
Calls the function func on each element of s in sequence, passing data as the second argument to func.
Sequence Method: RETAIN(I_T1*) I_T2_Nth ( I_T2 * s
, CORBA_unsigned_long n
)
Returns the address of the nth element of the sequence s. Returns ILU_NIL
if n is out of range.
Sequence Method: void I_T2_Init ( I_T2 * s, OPTIONAL(CORBA_unsigned_long) length, OPTIONAL(T1 *) initial-values )
This function works like T2_Create
, except that it takes
a the address of an already-existing T2 to initialize. This can be used
to initialize instances of T2 that have been stack-allocated.
Sequence Method: void I_T2__Free ( I_T2 * s )
Frees allocated storage used internally by s. Does not free s itself.
String sequences (SEQUENCE OF SHORT CHARACTER
or SEQUENCE OF CHARACTER
)
are just arrays of the character codes for the characters, using either Latin-1 codes (for
SEQUENCE OF SHORT CHARACTER
), or ISO 10646 Unicode codes (for SEQUENCE OF CHARACTER
).
These sequences are terminated with a character code of zero. The terminating code is not
counted in the length of the sequence. All other sequence types have a record structure, mandated by CORBA:
typedef struct I_T2 { unsigned long _maximum; unsigned long _length; I_T1 *_buffer; } I_T2;
The field _maximum
contains the number of elements pointed to by
_buffer
. The field _length
indicates the number of valid or
useful elements pointed to by _buffer
.
For example, the ISL specification
INTERFACE I; TYPE iseq = SEQUENCE OF INTEGER;would have in its C mapping the type
typedef struct I_iseq { unsigned long _maximum; unsigned long _length; ilu_integer *_buffer; } I_iseq;In a client program, a pointer to this type would be instantiated and initialized by calling the type specific sequence creation function generated for the sequence, e.g.
... I_O h; ILU_C_ENVIRONMENT s; I_iseq sq; ... sq = I_iseq_Create (0, NULL); I_iseq_Append (&sq, 4); ...
Generally, ILU unions in C consist of a struct with two members: the type discriminator
(a member named "_d
"),
and a union (a member named "_u
") of the possible values. In a simple ISL union that does not
name the elements, the union member names are derived from the
ISL data types which compose the union. For example, if the
ISL type in interface I
is TYPE u1 = UNION INTEGER, SHORT REAL END;
the generated C struct would be
struct _I_u1_union { CORBA_short _d; union { CORBA_long integer; /* 0 */ CORBA_float shortreal; /* 1 */ } _u; }; typedef struct _I_u1_union I_u1;
Note the discriminator _d
may take on the values of 0
, for the integer
field,
or 1
, for the shortreal
field.
In more complex union forms, the user may specify the type of the discriminator as well as the member names and which member corresponds to which discriminator value. Consider the following ISL example:
INTERFACE I; TYPE e1 = ENUMERATION red, blue, green, yellow, orange END; TYPE u1 = e1 UNION a : INTEGER = red, green END, b : SHORT REAL = blue END, c : REAL = DEFAULT END;
The generated union is:
typedef struct _I_u1_union I_u1; typedef enum { I_red = 0, I_blue = 1, I_green = 2, I_yellow = 3, I_orange = 4 } I_e1; struct _I_u1_union { I_e1 _d; union { CORBA_long a; /* I_red, I_green */ CORBA_float b; /* I_blue */ CORBA_double c; /* DEFAULT */ } _u; };
This example shows that the discriminator type is to be I_e1
and that
the member names are to be a
, b
, and c
. When the discriminator
has the value I_red
or I_green
the member a
has a valid value
and the type is interpreted to be CORBA_long
. When the discriminator has
the value I_green
the member b
has a valid value and the type is
interpreted to be CORBA_float
. If the discriminator has any other value,
the member c
is expected to have a valid value and the type is interpreted
to be CORBA_double
.
Discriminator types may be INTEGER
, CARDINAL
, ENUMERATION
, SHORT CARDINAL
, or SHORT INTEGER
.
The default for an unspecified discriminator is SHORT INTEGER
.
An ISL OPTIONAL
type maps either to the same C type as its base
type, if that base type is represented with an C pointer type, or to a pointer to that base type,
if it is not represented with a C pointer type.
ILU uses an object system embedded into C.
The C type of objects in this system is ILU_C_Object*
;
the identifiers ILU_C_OBJECT
and CORBA_Object
can also be used for this type.
We recommend the use of ILU_C_OBJECT
, as it is a macro that expands to the
identifier for the C object type
specified by the version of CORBA being used (currently 2.0).
Since C has no subtyping relationship isomorphic to that of
ISL object types, a more liberal approximation is used:
all ISL object types map to the same C type,
CORBA_Object
. However, a typedef
is emitted for each
ISL object type, so an object-type-specific C
type name may be used to express intent.
For conformance with CORBA, the C name
for ISL type I.T is I_T
.
The C mapping of an object type includes a set of generic
functions for the methods introduced at that object type. The name of
the generic function for the method M introduced at object
type I.T is I_T_M
. This
generic function is used to invoke method M on objects of type
I.T (naturally including objects that also have types that are
subtypes of I.T).
The first argument to a generic function is an object instance (ILU_C_Object *
)
that should have type I.T (among possibly others).
An implementation of an ISL object type is commonly
referred to as a class.
Classes are represented in the ILU C runtime as the C type ILU_C_Class
.
To create an ILU_C_Class
, the application calls an
object-type-specific function that is part of the stubs. The
class-creation procedure named I_T__MakeClass
,
which is declared in generated file `I.h', makes a class
for objects that implement object type I.T (and thus all its
supertypes). This procedure takes as arguments a set of C
procedures that are the implementations of the methods of that class,
plus a finalization procedure. The finalization procedure is given
access to the private data of the object after the object is destroyed.
For each object type I.T, the generated server-side stub
module for I creates a default true class, unless the true code
has been generated with the -nodefaulttrueclass
or -nodefaulttrueclassfor
command-line switches. Linking with this
server-side stub requires the application to supply the procedures that
implement the methods of this default class. Those procedures are named
server_I_T_M
, for each method
M of I.T.
A finalization procedure can be associated with the default class by invoking I_T__SetDefaultClassFinalization
.
Implementations of true objects
typically just use this default class, since the methods for this
class have to be provided in any case. The function I_T__CreateTrue
will create an true instance using the default true class for
the object type I_T. I_T__CreateTrue
methods
take an instance handle, a server on which
to maintain the object, and arbitrary user data, and create and return
the true instance of the object. An alternate version of
I_T__CreateTrue
, called I_T__OTCreateTrue
,
is provided for use inside the scope of an object table's incarnation
procedure. Also, a generic creation procedure,
ILU_C_CreateTrueObject
, is declared in `iluchdrs.h' for
application use. The default true class can be registered or changed
with the function
, which returns the previous setting of the default true class.
I_T__SetDefaultClass
Surrogate instances generally use another automatically-constructed
class, though custom surrogate classes may be registered with the
procedure ILU_C_RegisterCustomSurrogateType
. Surrogate instances
are typically either received as reply values from calls or parameters to calls, or
reified from one or more strings with a binding procedure.
(A binding procedure is a procedure that takes some name for an
object instance, and returns the actual instance.) There are a number
of binding procedures available. The simple binding interface to C
offers the function ILU_C_LookupObject
, which takes an object ID and a
type, and returns the registered object with that ID, if any.
The function CORBA_ORB_string_to_object
will take a URL for an instance, in any
of the supported URL forms, and return an ILU_C_OBJECT
instance.
The function ILU_C_SBHToObject
is similar to CORBA_ORB_string_to_object
,
except that an expected object type may also be specified, to constrain
the process.
In addition, the ILU-generated stubs will provide a function
called I_T__CreateFromSBH
, which will either find or create
an instance of the specified type, with the specified parameters.
In general, for any object type T, the following C functions are defined:
C Procedure Type: ILU_C_FinalizationProc
Locking: caller may have any locks -- this means that this finalization procedure can do almost nothing ILU-related without potentially violating locking constraints
The finalization procedure for a class of objects. It takes a single parameter,
the
"instance data" pointer provided at the creation of the
object being finalized. Ownership of (instanceData) is passed to
this procedure. It has a return type of void *
.
void
Function: ILU_C_Class T__MakeClass ( method-1-type method-1-proc, ... method-N-type method-N-proc, ILU_C_FinalizationProc _finalize )
Locking: Main Invariant holds
Creates a C class of objects that export object type T (and all its supertypes), given implementations for all the methods of that type. ILU_C_CreateTrueObject
can then be called to create instances of this class.
Function: ILU_C_Class T__SetDefaultClass ( ILU_C_Class c )
Locking: Main Invariant holds
Sets the default true class of the type T to be c, and returns the previous default true class setting.
Function: void T__SetDefaultClassFinalization ( ILU_C_FinalizationProc f )
Locking: Main Invariant holds
Sets the finalization method of the default class for object type T.
Function: OPTIONAL(T) T__CreateTrue ( OPTIONAL(RETAIN(char *)) instance-id, OPTIONAL(GLOBAL(ilu_Server)) server, OPTIONAL(PASS(void *)) user-data )
Locking: Main Invariant holds
Creates an instance of the default class for type T, exporting it with instance-id instance-id, exporting it via server server, associating the value user-data with it. If instance-id is not specified, a server-relative instance-id will be assigned automatically. If server is not specified, a default server will be created automatically.
Function: OPTIONAL(T) T__OTCreateTrue ( RETAIN(char *) instance-id, GLOBAL(ilu_Server) server, OPTIONAL(PASS(void *)) user-data )
Locking: Inside(server, T)
Similar to T__CreateTrue()
, but designed to be used
within the ot_object_of_ih
function of an object table
(section Servers and Ports). Requires kernel server locks to be
held before invocation.
Creates an instance of the default class for type T, exporting it with instance-id instance-id, exporting it via server server, associating the value user-data with it.
Function: OPTIONAL(T) T__CreateFromSBH ( RETAIN(char *) sbh, RETAIN(CORBA_Environment *) Env)
Locking: Main Invariant holds
Finds or creates an instance of T, using the given object reference.
Class Var: extern ilu_Class
T__MSType
A value, of type ilu_Class
(which, despite its poorly-chosen name, identifies an object type, not a class), that identifies the object type T.
In the following example, the ILU definition is:
INTERFACE I; TYPE T = OBJECT METHODS M ( r : REAL ) : INTEGER END;
This definition defines an interface I
, an object type T
, and a
method M
. The method M
takes a REAL
as an
argument and returns an INTEGER
result. The generated
C header file would include the following statements:
typedef ILU_C_OBJECT I_T; ILU_C_Class I_T__MakeClass( ilu_integer (*I_T_M__Impl) (I_T _handle, ilu_real r, ILU_C_ENVIRONMENT *_status), ILU_C_FinalizationProc _finalize); I_T I_T__CreateFromSBH (char *sbh, ILU_C_ENVIRONMENT *Env); I_T I_T__CreateTrue (ilu_string ih, ilu_Server server, void *user_data); I_T I_T__OTCreateTrue (ilu_string ih, ilu_Server server, void *user_data); ilu_integer I_T_M (I_T, ilu_real, ILU_C_ENVIRONMENT *); ilu_integer server_I_T_M (I_T, ilu_real, ILU_C_ENVIRONMENT *);
The functions I_T__CreateFromSBH
, I_T__CreateTrue
,
and I_T__OTCreateTrue
are used to create instances
of the class I_T
. I_T__CreateFromSBH
is used by clients.
I_T__CreateTrue
is used by servers for normal circumstances,
and I_T__OTCreateTrue
is used in object table implementations;
both return objects whose M
method is implemented by server_I_T_M
.
Alternatively, servers and/or object tables could use I_T__MakeClass
and
ILU_C_CreateTrueObject
.
The pointer
returned in each case is the object instance and must be
passed with each method invocation.
Through interface inheritance, an object type may participate in the behaviors of several different types that it inherits from. These types are called ancestors of the object type. In C, an object type supplies all methods either defined directly on that type, or on any of its ancestor types.
Consider the following example:
INTERFACE I2; EXCEPTION E1; TYPE T1 = OBJECT METHODS M1 (a : ilu.CString) : REAL RAISES E1 END END; TYPE T2 = OBJECT METHODS M2 ( a : INTEGER, Out b : INTEGER ) END; TYPE T3 = OBJECT SUPERTYPES T1, T2 END METHODS M3 ( a : INTEGER ) END;
The object type T3
inherits from the object types T1
and T2
. Thus,
eight C procedures are relevant to the interface
I2
: the three generic functions I2_T1_M1
, I2_T2_M2
, and I2_T3_M3
,
and the five default method implementations server_I2_T1_M1
, server_I2_T2_M2
,
server_I2_T3_M1
, server_I2_T3_M2
, and server_I2_T3_M3
. A
module that implements true instances of T3
using the default class would
define the last three procedures (the other two default method implementations, for messy reasons described in the next paragraph). A client uses only the three generic
functions.
Sadly, the current state of the C-stubber causes an additional
complexity for server implementors. `I2-true.c' contains the
server-side stubs ("skeletons", in OMG parlance) needed in any
program that implements any object type that is a subtype of any
object type defined in `I2.isl'. `I2-true.c' also contains
the code that creates the default classes for all the object types defined in `I2.isl';
this code makes external references to the default implementation procedures,
thus requiring any program that links with `I2-true.o' to
supply those default implementation procedures ---
even if those default classes are not used. A simple
workaround is to supply dummy procedures to satisfy the linker.
The stubs can also be generated with the command-line options -nodefaulttrueclass
or -nodefaulttrueclassfor
, which will prevent generation of the code that creates the default true classes. However, if this technique is used, be aware that either a default true class must be registered manually, or true instances must be created with
.
ILU_C_CreateTrueObject
Several functions are provided to give access to various identifiers
of an instance. The function ILU_C_SBHOfObject
will return the
ILU URL for an instance; the function ILU_C_IOROfObject
will return the CORBA URL for an object, if support for IIOP
is configured into ILU; the function CORBA_ORB_object_to_string
will return either the IOR, if IIOP
support has been configured
in, or the SBH, if not; the two parts of the object ID, the server id and
the instance handle, may be obtained with a call on ILU_C_IDOfObject
.
See the API reference section of this chapter for more information on these
functions.
It is occasionally useful to distinguish between local and remote instances. There are three cases here: the case where the instance is a true object, the case where the instance is a surrogate for a true instance implemented in another language in the same address space, and the case where the instance is a surrogate for a true instance in a different address space. There is currently no good way to distinguish these cases in the C runtime.
This information is provided for those interested in the implementation of the C object system. It is not guaranteed to remain the same from release to release.
The interface `ILUSRC/runtime/c/ilucstub.h' contains the C declarations relevant to the material here.
A C class is represented by a pointer to a struct that holds a finalization procedure and a dispatch table. The dispatch table is an array of sections, one from each object type implemented by the class. Each section is a struct containing the ilu_Class
(remember, this identifies a type, not a class) that this section is for, and an array of procedure pointers, one per method introduced at that object type.
For each method directly defined in the type, a generic function is
defined in the common code for its interface, which dispatches to the
appropriate method. It does this by walking down the dispatch table for the
object's class, until it finds a section that contains the appropriate
ilu_Class
value (that is, the value of ilu_Class
that matches the
ilu_Class
at which this method was introduced), then calling the
method pointer which is indexed in the section's array of method
pointers by the index of the method. The generic functions have the
correct type signature for the method. They can be referenced with the &
operator.
All ISL methods of an object type map to C functions
which operate on instances of the C object system as described
above. IN
, OUT
, and INOUT
parameters appear in the
C function in the same order as they appear in the ISL
definition of the function.
ASYNCHRONOUS
methods have no return values and raise no user-specified exceptions.
They may return before the completion of the true method. FUNCTIONAL
methods
are not cached by the C ILU runtime.
In addition to its specified arguments,
the methods I_T_M
and server_I_T_M
take an
instance of the type I_T
and a reference to a variable of type
ILU_C_ENVIRONMENT *
, which is a macro defined to be the
appropriate CORBA environment type, and is used to return
exception codes. The environment struct pointed to by the environment
argument must be instantiated in a client; its address is passed as
the last argument to each method. True procedures must expect a
pointer to this structure as the last argument.
For instance, the C client calling the method for M
might be as follows:
#include "I.h" int main (int ac, char **av) { double atof( ); I_T inst; CORBA_long result; CORBA_double f; ILU_C_ENVIRONMENT ev; I__Initialize( ); f = atof (av[1]); inst = I_T__CreateFromSBH (av[2], &ev); if (!ILU_C_SUCCESSFUL(&ev)) { printf( "CreateFromSBH raised exception <%s>\n", ILU_C_EXCEPTION_ID(&ev)); return(1); } result = I_T_M (inst, f, &ev); if (!ILU_C_SUCCESSFUL(&ev)) { printf( "exception <%s> signalled on call to I_T_M\n", ILU_C_EXCEPTION_ID(&ev)); return(2); } printf( "result is %d\n", result ); return(0); }
Note the call on the interface-specific client initialization
procdedure I__Initialize
; these are described in a later section.
The
string binding handle is obtained from standard input along
with some floating-point value.
The class specific function I_T__CreateFromSBH
is then called to
obtain the object instance. This function was passed
the string binding handle,
and a CORBA_Environment
in which to report exceptions.
The returned object instance is then passed as the first argument
to the method I_T_M
, along with the environment ev
,
and the single actual CORBA_double
argument f
. I_T_M
returns
an CORBA_long
value which is placed in result
.
The true implementation of the method M
might use the default class,
supplying the implementation of the one method as follows:
ilu_integer server_I_T_M ( I_T h, ilu_real u, ILU_C_ENVIRONMENT *s ) { return( (ilu_integer) (u + 1) ); }
In this simple example, the corresponding server, or true, method computes
some value to be returned. In this case it adds one
to its ilu_real
argument u
, converts the value to an integer,
and returns that value. Note that the server method, if not signalling
any exceptions, may ignore the environment parameter.
Here is ILU's version of table 20 from the CORBA 2.0 spec.
T
is the C mapping of the type in question.
The Exn
column describes how exception parameters appear in the parameter-conveying member of a status struct.
DataType In InOut Out Return Exn -------- -- ----- -- ------ --- scalar T T* T* T T* optional T T* T* T T* object T T* T* T T* record, fixed T* T* T* T T* record, var T* T* T** T* T* union, fixed T* T* T* T T* union, var T* T* T** T* T* string T T* T* T T* other sequence T* T* T** T* T* array, fixed T T T T_slice* T* array, var T T T_slice** T_slice* T*
An exception parameter is conveyed in the status argument as a C pointer; the parameter-conveying member is declared to be a void *
. In particular, this pointer is a pointer to a value of the type that is the C mapping of the exception's ISL parameter. For an exception that has no parameter, the parameter-conveying member is not meaningful.
In the following example, the div
method can raise the exception
DivideByZero
:
INTERFACE calc; TYPE numerator = INTEGER; EXCEPTION DivideByZero : numerator; TYPE self = OBJECT METHODS Div( v1 : INTEGER, v2 : INTEGER ) : INTEGER RAISES DivideByZero END END;
The generated include file `calc.h' contains the exception definitions:
#ifndef __calc_h_ #define __calc_h_ /* ** this file was automatically generated for C ** from the interface spec calc.isl. */ #ifndef __ilu_c_h_ #include "ilu-c.h" #endif extern ILU_C_ExceptionCode _calc__Exception_DivideByZero; #define ex_calc_DivideByZero _calc__Exception_DivideByZero typedef ilu_integer calc_numerator; typedef calc_numerator calc_DivideByZero; typedef ILU_C_OBJECT calc_self; calc_self calc_self__CreateTrue ( char *id, ilu_Server server, void * user_data); calc_self calc_self__CreateFromSBH ( char * sbh, ILU_C_ENVIRONMENT *Env ); ilu_integer calc_self_Div( calc_self, ilu_integer, ilu_integer, ILU_C_ENVIRONMENT *Env ); extern void calc__BindExceptionValue (ILU_C_ENVIRONMENT *, ilu_Exception, ...); #endif
The method implementation for Div
in the true module must detect the
divide-by-zero condition and raise the exception:
long server_calc_self_Div (calc_self h, ilu_integer u, ilu_integer v, ILU_C_ENVIRONMENT *s) { calc_numerator n = 9; if ( v == 0 ) { s->_major = ILU_C_USER_EXCEPTION; s->returnCode = ex_calc_DivideByZero; s->ptr = (void *) malloc(sizeof(calc_numerator)); *((calc_numerator *) (s->ptr)) = n; s->freeRoutine = (void (*) (void *)) 0; return( u ); } else return( u / v ); }
When freeing the parameter requires more than just freeing s->ptr
, a non-NULL s->freeRoutine
is provided that does the additional freeing; s->freeRoutine
is given one argument, s->ptr
, and returns void
.
The generated stubs offer as a convenience a variadic procedure (calc__BindExceptionValue
) that can be used to raise any exception declared in the interface. For an exception that has no parameter, this procedure takes just two actual arguments. For an exception with a parameter, the parameter value is given as the third actual argument, using the usual calling convention for passing IN
arguments of its type. Using this procedure, the above code would be:
long server_calc_self_Div (calc_self h, ilu_integer u, ilu_integer v, ILU_C_ENVIRONMENT *s) { calc_numerator n = 9; if ( v == 0 ) { calc__BindExceptionValue(s, ex_calc_DivideByZero, n); return( u ); } else return( u / v ); }
The exception is sent back to the client, which can detect it thusly:
... calc_self instance; ILU_C_ENVIRONMENT s; ilu_integer i, j; ilu_integer val; ... instance = calc_self__CreateFromSBH (sbh, &s); if (! ILU_C_SUCCESSFUL(&s)) { fprintf (stderr, "CreateFromSBH(%s) raised %s\n", sbh, ILU_C_EXCEPTION_ID (&s) ); exit(1); } val = calc_self_Div (instance, i, j, &s); /* check to see if an exception occured */ if (! ILU_C_SUCCESSFUL(&s)) { /* report exception to user */ char *p; p = ILU_C_EXCEPTION_ID (&s); if (p == ex_calc_DivideByZero) { calc_numerator *ip; ip = (calc_numerator *) ILU_C_EXCEPTION_VALUE (&s); fprintf (stderr, "%s signaled: numerator = %d\n", p, *ip); } else { /* odd exception at this point */ fprintf (stderr, "Unexpected <%s> on call to Div.\n", p); } /* free up any transient exception data */ ILU_C_EXCEPTION_FREE (&s); } else { /* no exception - print the result */ printf( "result is %d \n", val ); } ...
For more complex exception types, it is often helpful to define a procedure in C specifically to raise them.
Both true and surrogate instances of ILU_C_OBJECT
are reference-counted; that is,
each instance contains a counter which indicates how many uses are
currently being made of that object. When you wish to use an
object for another purpose, you should increment the reference count
by calling the procedure CORBA_Object_duplicate
, which will
return a copy of the instance that you can use for the new purpose.
When you are finished with an instance, you should call
CORBA_Object_release
to release your claim on the object's
resources. When the reference count of the object returns
to zero, the object is finalized.
For COLLECTIBLE true instances, the ILU kernel will maintain a distributed reference count on the instance automatically. That is, so long as any client of the server has a reference to the object, the true instance will not be finalized.
The ILU system does not support the OMG IDL type fixed
,
which is a representation of binary-coded-decimal, or BCD. We have
no immediate plans to support it in the future.
The C type which represents an ILU kernel server
is ILU_C_Server
. True servers can be created with the
function ILU_C_InitializeServer
.
Instances of ILU_C_Server
are reference-counted, in the same way that instances of ILU_C_OBJECT
are. Call ILU_C_Server_duplicate
and ILU_C_Server_release
to keep track of your usage of ILU_C_Server
values. ILU_C_CloseServer
and its relatives perform functions orthogonal to ILU_C_Server_release
. The actual server will be destroyed only when there is no reason to maintain it; in addition to the reference counting introduced here, the existence of ILU_C_OBJECT
values in that server count as another reason to maintain the server.
A kernel server can export itself via multiple ports. ILU_C_InitializeServer
may create one, and ILU_C_AddPort
can be called to create more.
It is sometimes useful to have a server create true objects only when they are
mentioned by a client's actual invocation of a method on them. This is allowed
in ILU by an interface called an object table, associated with a server. An object table
contains two functions, one of which creates a new true instance when called with an instance
handle, and the other of which frees the object table when the server is destroyed.
Object tables are associated with servers when the server is created. A value of type ILU_C_ObjectTable
may be created by a call on ILU_C_CreateObjectTable
; see the API reference for
more information about this function.
The server relocation functionality (see section Server Relocation) is accessed by ILU_C_SetServerRelocationProc
(see section Server Manipulation).
See section Exception Information in C.
The ILU C runtime allows the use of several different kernel threads packages, application-specific threads packages, or various kinds of event loops. See section Threads and Event Loops for a general discussion of threads and event loops in ILU.
The two macros ILU_C_USE_OS_THREADS
and ILU_C_FINISH_MAIN_THREAD
(see section Server Manipulation) are provided
to allow use of standard Win32 threads, POSIX threads, or Solaris
threads. Application-specific threads packages can also be used by explicitly setting the
wait tech, lock tech, and main loop via calls on the ILU kernel (see @ref{}
for more information on these functions), then instructing the C runtime on
how to fork a new thread by calling ILU_C_SetFork
.
If no thread technology is specified, ILU's C runtime
will operate in a single-threaded (i.e., event loop) manner, using the default ILU main loop.
That main loop can also be replaced with an application-specific event loop
system if desired; this is often useful when using a toolkit like Xt
or Tk. This replacement works by calling the kernel procedure
ilu_SetMainLoop
. In the case of the C runtime, moreover,
several examples of how to set the event loop are provided in the directory
`ILUSRC/runtime/mainloop/'. They will have been automatically
built into a library and installed into `ILUHOME/lib/' if
configured in during the build process. They are useful examples of how to
set the event loop to override the ILU default event loop.
For single-threaded operation, the main loop must be invoked. This can be done with either ILU_C_Stoppable_Run
, ILU_C_Run
, ILU_C_StoppableRun
, or ILU_C_FINISH_MAIN_THREAD
(see section Server Manipulation -- which is woefully incomplete and out of date).
For multi-threaded operation, no main loop need -- or even really can -- be invoked. Some of the aforementioned "main loop" procedures also "work" in multi-threaded runtimes -- they simply block the calling thread.
Custom record support in the ILU C runtime
provides support for replacing the default generated record type R
with a different struct type S
.
S
must have a field of type R
as its first field.
Custom record support for a particular ISL record type can be
specified by calling
on the ILU_C_RegisterCustomRecord()
CORBA_TypeCode
value for the type. Note that this allows you to register a function to be called
just before marshalling the value to another address space (among other functions).
This `pre-output' function may be called more than once on the same call, if the
protocol selected requires sizing of arguments. It should be written so that
repeated calls on the same value have no effect.
Custom surrogates allow the user to specify custom surrogate object types
which may have additional functionality in terms of caching or other
side effects, and have them created instead of the default ILU
surrogate object type when an instance is received.
This functionality is provided in the C runtime with the function
ILU_C_RegisterCustomSurrogateType
.
When a client program is making a call on an object which is provided via an object table,
it is often convenient to allow the client to form an appropriate string binding handle
for the object, then instantiate a surrogate instance from that string binding handle.
The function ILU_C_FormSBH
is provided to aid client programs in forming string binding handles.
The ILU C runtime provides the standard interface to ILU's simple binding mechanism.
The function ILU_C_PublishObject
publishes a true instance; ILU_C_WithdrawObject
allows it to be withdrawn
from the registry. The function ILU_C_LookupObject
finds and returns an instance with the
specified object ID.
See ILU_C_CreatePassport
, ILU_C_AddIdentity
, and ILU_C_DestroyPassport
for managing ilu_Passport
s.
To pass/receive an ilu_Passport
in a call, the caller calls ILU_C_SetPassportContext(pp)
to store pp in a special hidden per-thread slot, and ILU_C_SetPassportContext()
to retrieve it. pp will remain in that slot until another call to ILU_C_SetPassportContext
overwrites it. The callee calls ILU_C_CallerIdentity()
in a true method to fetch pp from the slot. If the caller and callee are both written in C, and the true method has been invoked directly from the same thread, the returned value will be whatever passport has been set with ILU_C_SetPassportContext()
; otherwise it will be the passport passed by the caller.
A pipeline (see section Pipelining) is represented in C by an ILU_C_Pipeline
, and is created by calling ILU_C_CreatePipeline
. A pipeline is associated with calls via a special hidden per-thread slot; this slot is accessed with ILU_C_SetPipelineContext
and ILU_C_GetPipelineContext
. When the ILU_C_Pipeline
is no longer needed, the client calls ILU_C_ReleasePipeline
.
A serializer (see section Call Order Preservation) is represented in C by an ILU_C_Serializer
, and is created by calling ILU_C_CreateSerializationContext
. A serializer is associated with calls via a special hidden per-thread slot; this slot is accessed with ILU_C_SetSerializationContext
and ILU_C_GetSerializationContext
. When the ILU_C_Serializer
is no longer needed, the client calls ILU_C_ReleaseSerializer
.
A batcher (see section Batching) is represented in C by an ILU_C_Batcher
, and is created by calling ILU_C_CreateBatcher
. A batcher is associated with calls via a special hidden per-thread slot; this slot is accessed with ILU_C_SetBatcherContext
and ILU_C_GetBatcherContext
. The application can call _C_PushBatcher
to initiate delivery all of all call messages buffered for a given batcher. When the ILU_C_Batcher
is no longer needed, the client calls ILU_C_ReleaseBatcher
.
To generate C stubs from an ISL file, use the program c-stubber. Four files are generated from the `.isl' file:
% c-stubber foo.isl header file for interface foo to ./foo.h... common code for interface foo to ./foo-common.c... code for surrogate stubs of interface foo to ./foo-surrogate.c... code for true stubs of interface foo to ./foo-true.c... %
The program c-stubber
supports the following options:
-I directory
-- add directory to the list of directories to search for interface definition files. Note that the directory must be separated from the -I
with whitespace, unlike the convention for C compilers.
-dir directory
-- put output files in directory. Will attempt to create directory with "mkdir directory"
if not already present.
-true
-- generate true code.
-tname filename
-- put true code in file called filename.
-common
-- generate common code.
-cname filename
-- put common code in file called filename.
-surrogate
-- generate surrogate code.
-sname filename
-- put surrogate code in file called filename.
-headers
-- generate header code.
-hname filename
-- put header code in file called filename.
-removefirst
-- for generated files, remove file before generating a new version of the file.
-nodefaulttrueclass
-- for true code, don't generate the commands which create default true classes for each class in the interface. This avoids pulling in references to possibly unused default true methods.
-nodefaulttrueclassfor classname
-- for true code, don't generate the commands which creates a default true class for the class classname. This avoids pulling in references to possibly unused default true methods. classname is specified as INTERFACENAME.TYPENAME
, using the ISL interface name and type name.
-renames filename
-- use the specified renaming file renames-file. See the following section on "Tailoring Identifier Names" for more information on this.
If none of -true
, -surrogate
, -common
, -headers
is specified, the default action is to produce all of them. However, if any of those switches is explicitly specified, only those specified will be produced.
The option -renames renames-filename
may be used with
c-stubber
to specify particular C names for
ISL types.
It is sometimes necessary to have the C names of an ILU interface match some other naming scheme. A mechanism is provided to allow the programmer to specify the names of C language artifacts directly, and thus override the automatic ISL to C name mappings.
To do this, you place a set of synonyms for ISL names in a
renames-file, and invoke the c-stubber
program with the switch -renames
,
specifying the name of the renames-file. The lines in the file are of the form
construct ISL-name C-namewhere construct is one of
method
, exception
,
type
, interface
,
or constant
; ISL-name is the name of the
construct, expressed either
as the simple name, for interface names, the concatenation
interface-name.construct-name
for exceptions,
types, and constants,
or interface-name.type-name.method-name
for methods;
and C-name is the name the construct should have
in the generated
C code. For example:
# change "foo_r1" to plain "R1" type foo_r1 r1 # change name of method "m1" to "method1" method foo_o1_m1 method1
Lines beginning with the `sharp' character `#' are treated as comment lines, and ignored, in the renames-file.
This feature of the c-stubber
should be used as little and as carefully
as possible, as it can cause confusion for readers of the ISL interface,
in trying to follow the C code. It can also create name conflicts
between different modules, unless names are carefully chosen.
Before manipulating surrogate objects, a client module must first call a runtime initialization procedure Foo__Initialize
for each ISL interface Foo that declares object types whose surrogates are to be manipulated. Additionally, server modules must also call server initialization procedures (see previous section). These initialization calls may be made in any order, and each procedure may be called more than once. However, no two calls may be done concurrently (this is an issue only for those using some sort of multi-threading package).
A client of an exported module may obtain an object instance
either by calling a method which returns the instance,
or by calling TYPE__CreateFromSBH()
on the string
binding handle of an instance. Once the object instance,
which is typically a surrogate instance, but may in fact
be a true instance, is held by the client, it can be used
simply by making method calls on it, as shown above.
This section will outline the construction of a true module exported by an address space. For the example, we will demonstrate the calculator interface described above. We will also use the CORBA 2.0 names for standard types and exceptions, to show that it can be done.
First, some runtime initialization of the server stubs must be done.
Call Foo__InitializeServer
for every ISL
interface Foo containing an object type implemented by the
address space. Due to a misfeature in the current C support,
also call Bar__InitializeServer
for every ISL
interface Bar containing an object type that is a supertype of
one defined in Foo (if you don't, the server will get a
runtime fault -- due to calling through a NULL procedure pointer ---
when serving a call on an inherited method); this may cause you to have
to supply dummy procedures, as explained in section Interface Inheritance.
Also call any client initialization procedures needed (see next
section). These server and client initialization calls can be made in
any order, and each initialization procedure can be called more than
once. However, no two calls may be done concurrently (this is an issue
only for those using some sort of multi-threading package).
Then we create an instance of calc_self
.
We then make the string binding handle of the object available by printing it to stdout.
Finally the ILU_C_Run
procedure is called. This procedure listens for connections
and dispatches server methods.
The main program for the server is as follows:
#include "I2.h" CORBA_long server_calc_self_Div (calc_self h, CORBA_long u, CORBA_long v, CORBA_Environment *s) { calc_numerator n = 9; if ( v == 0 ) { calc__BindExceptionValue(s, ex_calc_DivideByZero, n); return( u ); } else return( u / v ); } main (int ac, char **av) { calc_self s; char * sbh; CORBA_Object the_orb; CORBA_Environment ev; the_orb = CORBA_ORB_init (&ac, av, "ilu", &ev); if (!ILU_C_SUCCESSFUL(&ev)) { fprintf (stderr, "Can't initialize ORB; exception <%s>\n", CORBA_exception_id(&ev)); CORBA_exception_free(&ev); exit(1); }; calc__InitializeServer( ); s = calc_self__CreateTrue (NULL, NULL, NULL); if (s == NULL) { fprintf (stderr, "Unable to create instance of calc_self.\n"); exit(1); } else { sbh = CORBA_ORB_object_to_string (the_orb, s, &ev); if (ev._major == CORBA_NO_EXCEPTION) { printf ("%s\n", sbh); ILU_C_Run (); /* enter main loop; hang processing requests */ } else { fprintf (stderr, "Attempt to obtain sbh of object %p signalled <%s>.\n", s, CORBA_exception_id(&ev)); CORBA_exception_free(&ev); exit(1); } } }
For clients of an ILU module, it is only necessary to link with the `interface-name-surrogate.o' and `interface-name-common.o' files generated from the C files generated for the interface or interfaces being used, and with the two libraries `ILUHOME/lib/libilu-c.a' and `ILUHOME/lib/libilu.a' (in this order, as `libilu-c.a' uses functions in `libilu.a').
For implementors of servers, the code for the server-side stubs, in the file `interface-name-true.o' compiled from `interface-name-true.c', and in the file `interface-name-common.o' compiled from `interface-name-common.c', should be included along with the other files and libraries.
In addition to the functions defined by the CORBA mapping, the ILU C mapping provides some other functions, chiefly for type manipulation, object manipulation, and server manipulation. There are also a number of macros provided for compatibility with both versions of CORBA (revision 2.0).
Exception: CORBA_string ex_CORBA_InvalidName
Raised by
to indicate that no binding for the specified service_name is known. The associated value is the service name. Note that this differs from the strict CORBA definition of this exception, which has no associated value.
CORBA_ORB_resolve_initial_references
Function: CORBA_Object CORBA_ORB_init ( {int *} argc, {char **} argv, CORBA_string orb_id, {CORBA_Environment *} env)
Locking: Main Invariant holds
Called to initialize the ILU runtime, and acquire the "orb" object. The return value of this call is used in subsequent calls to other CORBA utility functions.
If the environment variable ILU_COS_NAMING_IOR
is bound to a string binding handle for a CosNaming
service, this call will bind the service name "NameService"
to the object specified by that string binding handle.
Function: CORBA_ORB_ObjectIdList CORBA_ORB_list_initial_services ( CORBA_Object the_orb, {CORBA_Environment *} env)
Locking: Main Invariant holds
Returns a list of service names which can be usefully used in calls to
. The type CORBA_ORB_resolve_initial_references()
is a normal CORBA sequence of strings.
CORBA_ORB_ObjectIdList
Function: OPTIONAL(ilu_Class) ILU_C_FindILUClassByTypeName ( RETAIN(ilu_string) type-name )
Locking: L1_sup < otmu, L2, Main unconstrained.
Given the type-name of an ILU object type, of the form "Interface.Typename"
,
returns the ilu_Class
value for it. This value can be used to compare
types for equality.
Function: OPTIONAL(ilu_Class) ILU_C_FindILUClassByTypeID ( RETAIN(ilu_string) type-id)
Locking: L1_sup < otmu; L2, Main unconstrained.
Given the type-id of an ILU object type, of the form "ilu:gfbSCM7tsK9vVYjKfLole1HOBDc"
,
returns the ilu_Class
value for it. This value can be used to compare
types for equality.
Function: GLOBAL(OPTIONAL(ilu_string)) ILU_C_ClassName ( RETAIN(CORBA_Object) )
Locking: unconstrained.
Returns the ILU name for the most specific type of an object instance.
Function: GLOBAL(OPTIONAL(ilu_string)) ILU_C_ClassID ( RETAIN(CORBA_Object) )
Locking: unconstrained.
Returns the ILU type ID for the most specific type of an object instance.
Function: ilu_Class ILU_C_ClassRecordOfInstance (CORBA_Object)
Locking: unconstrained.
Returns the ilu_Class
value for the most specific type of an object instance.
Function: ILU_C_Class ILU_C_RegisterCustomSurrogateType (ilu_Class kernel-type, ILU_C_Class C-type)
Locking: unconstrained.
This function registers C-type as the kind of class to create an instance of
when unmarshalling a surrogate instance of most specific type kernel-type. This
should be used in conjunction with the automatically generated function
(to create
an instance of ObjectType__MakeClass()
ILU_C_Class
), and the automatically generated constant
(the appropriate value for kernel-type).
This functionality can be used to implement application-specific surrogate types with caching and
other extensions to the basic ILUmodel. The value returned is the previously
registered surrogate class for this type.
ObjectType__MSType
Function: void ILU_C_RegisterCustomRecord (CORBA_TypeCode record_type, OPTIONAL(ILU_C_CRCreateFn) cfn, OPTIONAL(ILU_C_CRFreeFn) ffn, OPTIONAL(ILU_C_CRPreOutputFn) preoutfn, OPTIONAL(ILU_C_CRPostOutputFn) postoutfn, OPTIONAL(ILU_C_CRPostInputFn) postinfn, CORBA_Environment * env)
Locking: L1 < otmu
Registers a set of functions to be called for a particular record type record_type.
The function cfn should create, initialize, and return a value of the desired type;
it is called when the kernel is about to unmarshall a value of the type and needs storage
for it.
The function freefn should perform any clean-up operations necessary for the desired
value; they are called before the standard free functions are called on the standard slots
of the record type.
The function preoutfn should prepare the value to be marshalled to another
address space. It may be called repeatedly before the value is actually marshalled,
due to sizing requirements imposed by various RPC protocols.
The function postoutfn should perform any necessary
cleanup after a value has been marshalled; it is expected that this
will typically be a NIL function.
The function postinfn should perform any initial setup needed
after the standard slots of the value have been unmarshalled. This function
may raise BAD_PARAM
(if the type is not a record type),
NO_MEMORY
, and INTERNAL
.
Function: ILU_C_Object * ILU_C_CreateTrueObject ( ILU_C_Class c, OPTIONAL(ilu_string) instance_handle, OPTIONAL(ILU_C_Server) server, void * instanceData, ilu_boolean inside_server )
Locking: inside_server ? Inside(server, most specific type implemented by c) : Main Invariant.
Instantiates a true object of class c, in server server. If the instance_handle is NIL
, one will be invented. If the server is NIL
, the default server will be used. The instanceData is for the private use of the methods of the class. inside_server is FALSE
for normal cases, but TRUE
for use in the implementation of an object table.
Function: (OPTIONAL(ILU_C_Object *)) ILU_C_FindObject ( ilu_string server-id, ilu_string instance-handle )
Locking: Main invariant holds.
Given the server-id and instance-handle of an object, returns the object if
it exists in the current address space, or ILU_NIL
if it doesn't exist. Unlike
and ILU_C_SBHToObject()
, this function will
not create a surrogate for an instance if does not exist -- but if the server-id indicates a
server with an object table, the server may create the object dynamically.
ILU_C_LookupObject()
Function: ilu_boolean ILU_C_IDOfObject ( CORBA_Object instance, PASS(char **) server-id, PASS(char **) instance-handle )
Locking: Main invariant holds.
Given an instance, returns the server ID and instance handle of that instance.
The strings returned are copies; the user must free them with ilu_free
when finished
with them.
Function: ilu_string ILU_C_SBHOfObject ( CORBA_Object instance )
Locking: Main invariant holds.
Given an instance, returns a reference to that instance. The CORBA-specified
routine CORBA_ORB_object_to_string()
should typically be used instead.
Function: OPTIONAL(CORBA_Object) ILU_C_SBHToObject (char * sbh, ilu_Class static_type, RETAIN(CORBA_Environment *) Env)
Locking: Main invariant holds.
Takes an object reference and returns the object. static_type is a type the caller knows the object to have.
Function: OPTIONAL(PASS(char *)) ILU_C_FormSBH (RETAIN(char *) server-id, RETAIN(char *) instance-handle, ilu_Class most-specific-type, RETAIN(ilu_ProtocolInfo) pinfo, RETAIN(ilu_TransportInfo) tinfo, RETAIN(CORBA_Environment *) Env)
Locking: Main invariant holds.
Takes necessary information about an object reference, and returns a well-formed ILU string binding handle for that information. This SBH can then be used to create a surrogate instance, using
.
ILU_C_SBHToObject
Function: OPTIONAL(PASS(char*)) ILU_C_PublishObject ( CORBA_Object instance )
Locking: Main invariant holds.
Publishes the OID of the instance in a domain-wide registry. This is an experimental interface, and may change in the future.
Function: ilu_boolean ILU_C_WithdrawObject ( CORBA_Object instance, PASS(char *) proof)
Locking: Main invariant holds.
Removes the OID of the instance from the domain-wide registry.
proof is the string returned from the call to ILU_C_PublishObject()
.
Function: OPTIONAL(GLOBAL(CORBA_Object)) ILU_C_LookupObject ( RETAIN(char *) sid, RETAIN(char *) ih, ilu_Class static-class )
Locking: Main invariant holds.
Using the local registry, find and return the object specified by the given Server ID and server-relative Instance Handle. static_type is one you know the actual object must have; it may also have more refined types. For an already-reified surrogate this procedure will reconsider what contact info to use for reaching the server.
Function: OPTIONAL(GLOBAL(CORBA_Object)) ILU_C_CreateSurrogateObject ( ilu_Class type, RETAIN(char *) ih, ilu_Server server, ILU_C_ENVIRONMENT *env )
Locking: Main invariant holds.
Create a new object instance of the specified type
on the specified server, with the specified ih.
If unable to create such an object, return ILU_NIL
, and signal
the error in env.
This procedure can be used to create new client-side objects for which no true object yet exists. This is the way a client using a server with an object table causes the server to create new instances `on the fly'. When used in this way, the ih must contain all information necessary to allow the server to create the proper true object, as it is the only information passed to the object table's object creation procedure.
Function: CORBA_Object CORBA_Object_duplicate ( CORBA_Object instance, CORBA_Environment * env)
Locking: Main invariant holds.
Increments the reference count of the instance, and returns the instance.
Function: void CORBA_Object_release ( CORBA_Object instance, CORBA_Environment * env)
Locking: Main invariant holds.
Decrements the reference count of the instance. The instance may be destroyed as a result of this operation.
Function: CORBA_unsigned_long CORBA_Object_hash ( CORBA_Object instance, CORBA_unsigned_long max_value, CORBA_Environment * env)
Locking: Main invariant holds.
Returns a hash value for the instance, less than or equal to max_value. Mandated by the CORBA spec.
Function: CORBA_boolean CORBA_Object_is_equivalent ( CORBA_Object instance1, CORBA_Object instance2, CORBA_Environment * env)
Locking: Main invariant holds.
Returns ilu_TRUE
if ILU believes the two instances to be the same object, ilu_FALSE
otherwise. Compares the servers and kernel objects of the two instances.
Function: void ILU_C_PingObject ( ILU_C_Object instance, ILU_C_ENVIRONMENT * env)
Locking: Main invariant holds.
Attempts round-trip effectless call on object. May raise system exception to indicate failure.
Function: CORBA_boolean CORBA_Object_non_existent ( CORBA_Object instance, CORBA_Environment * env)
Locking: Main invariant holds.
Returns ilu_TRUE
if object cannot be successfully pinged. May cause instance to be destroyed.
Function: CORBA_boolean CORBA_Object_is_a ( CORBA_Object instance, CORBA_string repository_id, CORBA_Environment * env )
Locking: Main invariant holds.
Returns ilu_TRUE
if the instance supports the interface identified by repository_id. May involve a network round trip.
Function: CORBA_boolean CORBA_Object_is_nil ( CORBA_Object instance, CORBA_Environment * env )
Locking: Main invariant holds.
Returns ilu_TRUE
if the instance is the NIL
object reference.
Function: CORBA_string CORBA_ORB_object_to_string ( CORBA_Object the_orb, CORBA_Object instance, CORBA_Environment * env )
Locking: Main invariant holds.
Returns a string binding handle for the instance. The argument the_orb is the result of a call to
.
CORBA_ORB_init()
Function: CORBA_Object CORBA_ORB_string_to_object ( CORBA_Object the_orb, CORBA_String string_binding_handle, CORBA_Environment * env )
Locking: Main invariant holds.
Returns a
instance for the specified string_binding_handle. The argument the_orb is the result of a call to CORBA_Object
.
CORBA_ORB_init()
Function: OPTIONAL(CORBA_Object) CORBA_ORB_resolve_initial_references ( CORBA_Object the_orb, CORBA_String service_name, CORBA_Environment * env )
Locking: Main invariant holds.
Returns an instance for the service named by service_name, if the system knows of one. The argument the_orb is the result of a call to
. Raises CORBA_ORB_init()
ex_CORBA_InvalidName
if the service_name doesn't name a known service.
Function: ilu_integer ILU_C_SetObjectGCTimeout ( {ILU_C_Object *} the_obj, ilu_integer timeout, {ILU_C_ENVIRONMENT *} env)
Locking: Main invariant holds.
Sets the GC timeout of the_obj to timeout. Returns the previous timeout when successful. The GC timeout of an instance is the amount of time ILU will wait before collecting an object without references. This timeout accommodates references to the object that are in transit on the network, and its value should be related to typical maximum network delays on the network being used. Setting the timeout to a value less than the network delay may result in objects being prematurely collected.
Function: ilu_Passport ILU_C_CreatePassport (OPTIONAL(PASS(ilu_IdentityInfo)) info, ILU_ERRS((no_memory)) *err)
Create and return a new passport object. If an identity info is passed in, will put that identity in the new passport.
Function: ilu_IdentityInfo ILU_C_CopyIdentity (RETAIN(ilu_IdentityInfo) info
, ILU_ERRS((no_memory)) *err
)
Creates and returns a copy of the identity in info.
Function: ilu_boolean ILU_C_AddIdentity (RETAIN(ilu_Passport) pp
, PASS(ilu_IdentityInfo) info
, ILU_ERRS((no_memory)) *err
)
Adds the specified identity to the specified passport, which now owns the identity storage.
Function: OPTIONAL(RETAIN(ilu_IdentityInfo)) ILU_C_FindIdentity (RETAIN(ilu_Passport) pp
, RETAIN(ilu_IdentityType) ident_type
)
If the passport pp contains an identity of the specified type, returns a pointer to it, otherwise returns ILU_NIL
. The passport retains ownership of the identities storage; the caller may make a copy of the identity by calling
.
ILU_C_CopyIdentity
Several identity types are pre-defined. The identity type ilu_ConnectionIdentity
is always defined; it consists of a string which describes the connection used by the caller to communicate with the server in a colloquial fashion. The identity type ilu_SunRPCAuthUnixIdentity
is defined if the Sun RPC
protocol has been configured in; it provides a struct containing the various pieces of information specified by the protocol specification. The identity type ilu_GSSIdentity
is available if support for the secure transport has been configured in; it supports a variety of identity schemes under the GSS umbrella. See section Security and the file `ILUSRC/runtime/kernel/iluxport.h' for more information on identities and identity schemes.
Function: ilu_cardinal ILU_C_DisplayIdentity ( RETAIN(ilu_IdentityInfo) identity, RETAIN(char *) buf, ilu_cardinal bufsize, {ILU_C_ENVIRONMENT *} env)
Formats a textual display of the identity into buf, respecting bufsize. Returns the actual length of the string (the amount of the buffer that was actually used). May raise an exception through env.
Function: ilu_boolean ILU_C_DecodeGSSIdentity ( RETAIN(ilu_IdentityInfo) identity, OPTIONAL(gss_name_t *) name, OPTIONAL(ilu_FineTime *) good_till, OPTIONAL(gss_OID) mech, OPTIONAL(ilu_boolean) localp, OPTIONAL(OM_uint32 *) flags, {ILU_C_ENVIRONMENT *} env)
Only available if ILU has been configured with support for the GSS security transport.
Returns various aspects of the GSS identity in the output parameters name, good_till, mech, localp, and flags. If no return value is specified for an output parameter, that output
parameter is not returned. May raise an exception through env, in which case the return value is ilu_FALSE
.
If no exception is signalled, the return value is ilu_TRUE
.
The meaning of the output parameters are as follows:
ilu_TRUE
if the identity is local, ilu_FALSE
if the identity has been established for a remote principal.
ilu_FALSE
). These are the context flags returned from gss_inquire_context
in the ctx_flags parameter. See `ILUSRC/GSS/doc/draft-ietf-cat-gssv2-cbind-01.txt' for a complete description.
See `ILUSRC/GSS/kernel/gssapi.h' for a definition of the GSS types gss_name_t
, gss_OID
, and OM_uint32
.
Function: OPTIONAL(PASS(ilu_string)) ILU_C_GSSNameToString ( RETAIN(gss_name_t) gss_name, {ILU_C_ENVIRONMENT *} env)
Returns a newly-malloced string containing a textual representation of the principal name in gss_name.
May raise an exception through env, in which case returns ILU_NIL
.
See `ILUSRC/GSS/kernel/gssapi.h' for a definition of the GSS type gss_name_t
.
Function: ilu_IdentityInfo ILU_C_AcquireGSSIdentity (gss_cred_id_t c, {ILU_C_ENVIRONMENT *} err)
Available only if the security transport filter has been configured in. Returns an ilu_IdentityInfo
corresponding to the given GSS credentials. May raise an exception through err, in which case returns ILU_NIL
.
See `ILUSRC/GSS/kernel/gssapi.h' for a definition of the GSS type gss_cred_id_t
.
Function: OPTIONAL(gss_cred_id_t) ILU_C_AcquireGSSCredForName (char *name, ilu_cardinal lifetime, gss_OID secmech, ilu_boolean accept_only, {ILU_C_ENVIRONMENT *} err)
Available only if the security transport filter has been configured in. Returns GSS credentials given the cannonical inputs, which are
<namespace-identifier>:<principal-name>
, where the namespace-identifier is a stringified gss_OID
, and the principal-name is a name in that namespace's string formulation. An example would be "1.2.840.113550.9.1.4:someone@parc.xerox.com"
. The namespace-identifier identifies the iso.member-body.US.Xerox.ILU.GSS.rfc822-namespace namespace, which supports RFC 822 style mail addresses for principal names. See section Security for a discussion of available namespaces.
GSS_C_INDEFINITE
may be specified for an infinite period.
ilu_TRUE
, the returned credentials may only be used to accept security contexts. When specified as ilu_FALSE
, they may only be used to initiate security contexts.
May raise an exception through err, in which case a value of ILU_NIL
is returned.
See `ILUSRC/GSS/kernel/gssapi.h' for a definition of the GSS types gss_OID
and gss_cred_id_t
.
Function: ilu_IdentityInfo ILU_C_AcquireSunRPCAuthUnixIdentity (ilu_string hostname, ilu_shortcardinal uid, ilu_shortcardinal gid, ilu_shortcardinal ngroups, ilu_shortcardinal* groups, ILU_C_ENVIRONMENT * env)
Available only if SunRPC UNIX Authorization has been configured in. Returns an ilu_IdentityInfo
corresponding to the given UNIX credentials.
Function: ilu_boolean ILU_C_SetPassportContext (ilu_Passport pp)
Sets the special hidden per-thread slot for passports to contain pp. The slot retains that value until explicitly changed later.
Function: ilu_Passport ILU_C_GetPassportContext (void)
Returns the value in the special hidden per-thread slot for ilu_Passport
s.
Function: ilu_boolean ILU_C_DestroyPassport (PASS(ilu_Passport) pp, ilu_Error * err)
Deallocates the storage associated with the passport, and any associated identities.
Function: OPTIONAL(ilu_Passport) ILU_C_CallerIdentity (void)
Returns the passport associated with the caller, or possibly ILU_NIL
if being
invoked directly in a thread with no passport set. This procedure should only be
invoked inside the scope of a true method.
Function: ILU_C_Serializer ILU_C_CreateSerializationContext (ILU_C_Server S, ILU_C_ENVIRONMENT *env)
Creates a new instance of the serialization guarantee; this instance is applicable only to calls on objects of S.
Function: ilu_boolean ILU_C_ReleaseSerializer (ILU_C_Serializer si, ILU_C_ENVIRONMENT *env)
A client calls this after it is done using the given ilu_Serializer
.
Function: ilu_boolean ILU_C_SetSerializationContext (ILU_C_Serializer x)
Sets the special hidden per-thread slot for ILU_C_Serializer
s to contain x. The slot retains that value until explicitly changed later.
Function: ILU_C_Serializer ILU_C_GetSerializationContext (void)
Returns the value in the special hidden per-thread slot for ILU_C_Serializer
s.
Function: ILU_C_Batcher ILU_C_CreateBatcher (ilu_FineTime timeout, ilu_boolean pushable, ILU_C_ENVIRONMENT *env)
Creates a new batcher.
Function: ilu_boolean ILU_C_ReleaseBatcher (ILU_C_Batcher val, ILU_C_ENVIRONMENT *env)
A client calls this after it is done using the given ILU_C_Batcher
.
Function: ilu_boolean ILU_C_SetBatcherContext (ILU_C_Batcher x)
Sets the special hidden per-thread slot for ILU_C_Batcher
s to contain x. The slot retains that value until explicitly changed later.
Function: ILU_C_Batcher ILU_C_GetBatcherContext (void)
Returns the value in the special hidden per-thread slot for ILU_C_Batcher
s.
Function: ilu_boolean ILU_C_PushBatcher (ILU_C_Batcher b, ILU_C_ENVIRONMENT * env)
Initiates delivery of all buffered call messages associated with b.
Function: ILU_C_Pipeline ILU_C_CreatePipeline (ILU_C_ENVIRONMENT *env)
Creates a new pipeline.
Function: ilu_boolean ILU_C_ReleasePipeline (ILU_C_Pipeline pl, ILU_C_ENVIRONMENT *env)
A client calls this after it is done using the given ILU_C_Pipeline
.
Function: ilu_boolean ILU_C_SetPipelineContext (ILU_C_Pipeline x)
Sets the special hidden per-thread slot for ILU_C_Pipeline
s to contain x. The slot retains that value until explicitly changed later.
Function: ILU_C_Pipeline ILU_C_GetPipelineContext (void)
Returns the value in the special hidden per-thread slot for ILU_C_Pipeline
s.
Function: GLOBAL(const char *) ILU_C_SysExnMinorDescr ( CORBA_Environment * Env )
Locking: Main Invariant holds.
If Env indicates a system exception has been raised, and the system exception's minor code is ILU-specific, returns a string that describes the minor code. Otherwise returns nil.
Function: GLOBAL(const char *) ILU_C_Exception_SrcFile ( CORBA_Environment * Env )
Locking: Main Invariant holds.
If Env indicates a system exception has been raised, and it was raised locally in the ILU runtime support, returns the name of the source file in which the raise statically occurs. Otherwise returns nil.
Function: int ILU_C_Exception_SrcLine ( CORBA_Environment * Env )
Locking: Main Invariant holds.
If Env indicates a system exception has been raised, and it was raised locally in the ILU runtime support, returns the line number where the raise statically occurs. Otherwise returns 0.
Macro Function: ilu_boolean ILU_C_USE_OS_THREADS
Locking: Main invariant holds.
This macro expands to a function call.
If ILU has been configured with os-level thread support, calling this
routine will `turn on' that thread support for use with C. This
means that a new thread will be forked to handle each incoming connection,
in servers, and if the wire protocol being used permits it, a thread will
be forked to handle each incoming request. This routine returns FALSE,
and emits an error message, if something goes wrong with enabling thread
support. It must be called before making any other ILU calls, and before
initializing any interfaces via calls to interface__Initialize
or interface__InitializeServer
.
Macro Function: void ILU_C_FINISH_MAIN_THREAD ( int returnvalue )
Locking: Main invariant holds.
This routine will return from the `main' thread with the specified value. In some
thread systems, the program will be terminated when the main thread returns from main()
,
regardless of whether other threads are running. For these thread systems, this call
will simply cause the main thread to idle forever, instead of returning.
Function: void ILU_C_Run (void)
Locking: Main invariant holds.
Called to animate a server and/or other parts of the program. Used only in single-threaded mode. Invokes the event handling loop. Never returns.
Function: OPTIONAL(ILU_C_Server) ILU_C_FullInitializeServer (OPTIONAL(RETAIN(char *)) serverID, OPTIONAL(GLOBAL(ILU_C_ObjectTable)) obj_tab, OPTIONAL(RETAIN(ilu_ProtocolInfo)) protocol, OPTIONAL(RETAIN(ilu_TransportInfo)) transport, OPTIONAL(RETAIN(ilu_Passport)) identity, ilu_boolean createPortAnyway, ilu_boolean port_public)
Locking: Main invariant holds.
Creates and returns an ilu_Server
with ID serverID, object mapping table obj_tab, using protocol protocol over a transport stack specified by transport. If serverID is specified as NULL
, a unique string is generated automatically for the server ID. If obj_tab is specified as NULL
, the default hash table object table is used.
If either protocol or transport is specified, or
if createPortAnyway, an ilu_Port
will automatically be
created and added to the ilu_Server
. protocol, if not
NULL
, is a string that specifies which RPC protocol to use on the
port; NULL
causes use of the default protocol.
transport, if not NULL
, is a sequence of strings that
specifies the transport stack to use below the RPC protocol; NULL
signifies use of the default transport to/from one of the IP addresses
of this host. See section Protocols and Transports for details on
protocols and transports. If an identity is specified, it
may be used for communications security purposes. If an ilu_Port
is called for, it will become the default port of the ilu_Server
,
and will be public iff requested.
Function: ilu_boolean ILU_C_FullAddPort (ILU_C_Server server, OPTIONAL(RETAIN(ilu_ProtocolInfo)) protocol, OPTIONAL(RETAIN(ilu_TransportInfo)) transport, OPTIONAL(RETAIN(ilu_Passport)) identity, ilu_boolean makeDefault, ilu_boolean port_public, ILU_C_ENVIRONMENT * env)
Locking: Main invariant holds.
Creates a new ilu_Port
for the server. protocol, transport, identity, and port_public parameterize the ilu_Port
as for ILU_C_InitializeServer
.
Function: ilu_boolean ILU_C_AddCInfo (ILU_C_Server server, OPTIONAL(RETAIN(ilu_ProtocolInfo)) protocol, OPTIONAL(RETAIN(ilu_TransportInfo)) transport, ILU_C_ENVIRONMENT * env)
Locking: Main invariant holds.
Adds the given contact info to the given kernel server; used for contact info for ports on other kernel servers of the same server.
Function: ilu_boolean ILU_C_Server_CInfo (ILU_C_Server server, ilu_boolean want_public, char ** protocol, ilu_TransportInfo * transport, ILU_C_ENVIRONMENT * env)
Locking: Main invariant holds.
Obtains the first (if any) public or private (as requsted) contact
info sequence of the given server. Caller owns storage pointed to by
protocol and transport. On success: callee
returns TRUE; callee allocates new storage for string and
ilu_TransportInfo
and returns ownership to caller by storing
pointers through protocol and transport. On
failure: callee returns FALSE.
Function: (RETAIN(ilu_string)) ILU_C_IDOfServer ( ILU_C_Server server )
Locking: Main invariant holds.
Returns a pointer to the server id of the specified server.
Function: ILU_C_ObjectTable ILU_C_CreateObjectTable (CORBA_Object (*object_of_ih)(ilu_string instance-handle, ilu_private user-data), void (*free_user_data)(ilu_private user-data), ilu_private user-data )
Locking: Main invariant holds.
Locking for object_of_ih: L1 >= {server}, L1 >= {gcmu} if result is true and collectible; L2, Main unconstrained.
Locking for free_user_data: L1 >= {server}; L2, Main unconstrained.
Creates and returns a value of type ILU_C_ObjectTable
encapsulating the two procedures object_of_ih and free_user_data, and the user-specified data element user-data. When object_of_ih is called, it should create an appropriate CORBA_Object
with the specified instance handle, and return it. When free_user_data is called, it indicates the end of the object table, and free_user_data should free up any storage associated with user-data.
An object table is associated with a kernel server by passing the object table as
a parameter to the function ILU_C_InitializeServer
. A single object
table may be used with multiple different ilu_Server
instances.
C Procedure Type: ILU_C_ServerRelocateProc
Locking: L1 >= {ilu_Server}; L2 unconstrained
typedef ilu_boolean (*ILU_C_ServerRelocateProc) (ILU_C_Server server, ilu_private argument, OPTIONAL(ilu_ProtocolInfo *) new_pinfo, OPTIONAL(ilu_TransportInfo *) new_tinfo);This function should return TRUE if new pinfo and tinfo have been stored into the out parameters; otherwise it should return FALSE. It has no mechanism for signalling errors. It is called by a protocol implementation to see if the server wants the caller to be redirected to another location or cinfo stack.
Function: OPTIONAL(void *) ILU_C_SetServerRelocationProc (ILU_C_Server server, ILU_C_ServerRelocateProc relocation_fn, {void *} relocation_arg, ILU_C_ENVIRONMENT * metavar{env})
Locking: Main invariant holds
Ensures that the function relocation_fn will be called with relocation_arg as an argument
whenever a request comes in for an object maintained by server, on any connection which uses
a relocating protocol (currently only w3ng
is a relocating protocol). See the definition
of
for a description of how it is used. The returned value is
the previous value of relocation_arg, if any.
ILU_C_ServerRelocateProc
Function: ilu_cardinal ilu_tcp_SetDefaultBuffersize (ilu_cardinal new-buffer-size)
Locking: Main invariant holds.
Sets the default buffersize, in bytes, for TCP transports to new-buffer-size. This default can be overridded by explicitly specifying a buffersize in the tinfo for the port or object. Returns the previous default value. This function is only available if ILU has been configured with support for the TCP/IP transport.
Function: void ilu_tcp_GetStats ( ilu_cardinal * bytes-sent, ilu_cardinal * bytes-read, ilu_cardinal * moorings-created, ilu_cardinal * connections-accepted, ilu_cardinal * connections-opened, ilu_cardinal * currently-open-connections, ilu_cardinal * max-simultaneously-open-connections )
Locking: Main invariant holds.
Returns various statistics about the TCP/IP tranports use of various resources for this process.
The values returned are the values since the process was started, or since the reset function
was last called, except for currently-open-connections,
which is unaffected by the reset function.
This function is only available if ILU has been configured with support
for the TCP/IP transport.
ilu_tcp_InitializeStats()
Function: void ilu_tcp_InitializeStats ()
Locking: Main invariant holds.
Resets the statistics counters for this process. This function is only available if ILU has been configured with support for the TCP/IP transport.
Function: ilu_FineTime ILU_C_SetDefaultGCPingPeriod ( ilu_FineTime new_period, {ILU_C_ENVIRONMENT *} env)
Locking: L1 < gcmu
The ILU distributed garbage collection protocol detects defunct clients by periodically pinging their GC callback objects. If a client's callback object cannot be successfully pinged, it is removed from the list of clients which have references to any objects on the server. This call sets the ping period to new_period. Only GC callback objects registered after this call will use the new period. Returns the previous ping period upon success.
ILU supports CORBA 2.0, and formerly supported either 1.1 or 1.2, depending on how it was installed at your site. A number of macros are defined to make programs less dependent on which version they use.
Expands to CORBA_Object
.
Expands to CORBA_Environment
.
Expands to CORBA_NO_EXCEPTION
.
Expands to CORBA_USER_EXCEPTION
.
Expands to CORBA_SYSTEM_EXCEPTION
.
Macro: ILU_C_SUCCESSFUL ( ILU_C_ENVIRONMENT * ev )
Evaluates to true if no exception has been raised.
Macro: ILU_C_SET_SUCCESSFUL ( ILU_C_ENVIRONMENT * ev )
Sets ev to a successful result.
Macro: ILU_C_EXCEPTION_ID ( ILU_C_ENVIRONMENT * ev )
Returns the char *
value that is the exception's ID.
Macro: ILU_C_EXCEPTION_VALUE ( ILU_C_ENVIRONMENT * ev )
Expands to CORBA_exception_value(ev)
.
Macro: ILU_C_EXCEPTION_FREE ( ILU_C_ENVIRONMENT * ev )
Expands to CORBA_exception_free(ev)
.
Go to the previous, next section.