DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
TOC PREV NEXT INDEX

Metalanguage-to-Environment Interface

28

28.1 Overview

The Metalanguage-to-Environment Interface (MEI) is a set of interfaces designed to allow for the creation of portable metalanguage libraries. This chapter defines the data structures, macros, and service calls that make up the UDI MEI services.

Metalanguage stubs are the pieces of code that implement metalanguage channel operations. In the UDI execution model each channel operation requires a front-end stub, a back-end stub, and a direct-call stub. The caller of the channel operation calls directly into the front end stub. If the target region at the other end of the channel is not currently busy, the operation will be invoked in that region immediately using the direct-call stub. If the target of the channel operation (at the other end of the channel) cannot be run immediately, then the operation is queued; when the operation can be scheduled to run, it is taken from the region queue and passed to the back end stub, which unmarshalls parameters and calls the target driver's entry point.

28.1.1 Versioning

All functions and structures defined in the MEI Services section of the UDI Core Specification are part of the "udi_mei" interface, currently at version "0x101". A library module that conforms to and uses the MEI Services of the UDI Core Specification, Version 1.01, must include the following declaration in its udiprops.txt file (see Chapter 30, "Static Driver Properties"):

requires udi_mei 0x101
 

28.2 Initialization Structures

Every metalanguage library must contain a global variable named udi_meta_info, of type udi_mei_init_t, declared as follows:

udi_mei_init_t udi_meta_info = { ... };
 

This structure contains information describing the metalanguage-specific properties of control blocks and ops vectors used with the particular metalanguage. The environment uses this information to initialize drivers that use each metalanguage, before executing any code in either driver or metalanguage library.

This section contains descriptions of the various components of the udi_meta_info structure.

NAME udi_meta_info

Metalanguage initialization structure

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_mei_ops_vec_template_t

			*ops_vec_template_list;

	udi_mei_enumeration_rank_func_t

			*mei_enumeration_rank;

} udi_mei_init_t;
 
udi_mei_init_t udi_meta_info;
 

MEMBERS ops_vec_template_list is a pointer to a list of structures containing information about each type of ops vector supported by this metalanguage.

mei_enumeration_rank is a pointer to a function called by the UDI Management Agent to obtain an enumeration ranking for the specified set of enumeration attributes in accordance with ranking information defined by the Metalanguage specification. The Management Agent will select the device instance with the highest ranking value as the most appropriate driver instance to instantiate to handle the enumerated child.

DESCRIPTION This structure contains information describing the metalanguage-specific properties of control blocks and ops vectors used with the particular metalanguage. The environment uses this information to initialize drivers that use each metalanguage, before executing any code in either driver or metalanguage library.

REFERENCES udi_init_info, udi_mei_ops_vec_template_t

NAME udi_mei_ops_vec_template_t

Metalanguage ops vector template

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_index_t meta_ops_num;

	udi_ubit8_t relationship;

	const udi_mei_op_template_t *op_template_list;

} udi_mei_ops_vec_template_t;
 
/* Flag values for relationship */
 
#define  UDI_MEI_REL_INITIATOR				(1U<<0)
 
#define  UDI_MEI_REL_BIND				(1U<<1)
 
#define  UDI_MEI_REL_EXTERNAL				(1U<<2)
 
#define  UDI_MEI_REL_INTERNAL				(1U<<3)
 
#define  UDI_MEI_REL_SINGLE				(1U<<4)
 

MEMBERS meta_ops_num is a number that identifies this ops vector type with respect to others in this metalanguage, or zero to terminate the ops_vec_template_list array to which this structure belongs (see udi_mei_init_t). If meta_ops_num is zero, all other members of this structure are ignored.

relationship defines the valid relationships between the regions on opposite ends of a channel when using an ops vector of this type.

Relationship must include at least one of UDI_MEI_REL_EXTERNAL or UDI_MEI_REL_INTERNAL. If and only if relationship includes UDI_MEI_REL_EXTERNAL, then this ops type can be used for an external (driver-to-driver) channel. If and only if relationship includes UDI_MEI_REL_INTERNAL, then this ops type can be used for an internal (within one driver instance) channel.

If and only if relationship includes UDI_MEI_REL_INITIATOR, then this ops type can be used for the initiator side of a channel (the side that sends the first operation). Otherwise, this ops type can only be used for the non-initiator (responder) side of a channel.

If and only if relationship includes UDI_MEI_REL_BIND, then this ops type can be used for a bind channel. Otherwise, this ops type can only be used for an auxiliary, non-bind, channel.

Both ends of a channel must be paired appropriately: both must have the same combination of UDI_MEI_REL_EXTERNAL, UDI_MEI_REL_INTERNAL, and UDI_MEI_REL_BIND; exactly one must have UDI_MEI_REL_INITIATOR set.

UDI_MEI_REL_SINGLE is legal only if both UDI_MEI_REL_EXTERNAL and UDI_MEI_REL_BIND are also set and UDI_MEI_REL_INITIATOR is not. If and only if relationship does not include UDI_MEI_REL_SINGLE, then a driver using this ops type for a child bind channel must be prepared to have multiple child instances bound to it for each enumerated child context.

op_template_list is a pointer to a list of structures containing information about each type of ops vector supported by this metalanguage. The udi_channel_event_ind_op_t at the beginning of every ops vector type is not included in this list; the first entry in the list corresponds to index one, rather than zero, in the ops vector.

DESCRIPTION This structure is used to describe the set of metalanguage operations that correspond to the specified meta_ops_num for the role indicated by the relationship parameter. The ops are described in terms of their parameters and the associated ownership and data transfer of those parameters as a result of performing the specified operation.

One structure of this type must be defined for each ops vector types. These will generally come in pairs: one for the ops at each end of the channel.

references udi_channel_event_ind, udi_mei_init_t, udi_mei_op_template_t

NAME udi_mei_op_template_t

Metalanguage channel op template

SYNOPSIS

#include <udi.h>

typedef const struct {

	const char *op_name;

	udi_ubit8_t op_category;

	udi_ubit8_t op_flags;

	udi_index_t meta_cb_num;

	udi_index_t completion_ops_num;

	udi_index_t completion_vec_idx;

	udi_index_t exception_ops_num;

	udi_index_t exception_vec_idx;

	udi_mei_direct_stub_t *direct_stub;

	udi_mei_backend_stub_t *backend_stub;

	udi_layout_t *visible_layout;

	udi_layout_t *marshal_layout;

} udi_mei_op_template_t;
 
/* Values for op_category */
 
#define  UDI_MEI_OPCAT_REQ				1
 
#define  UDI_MEI_OPCAT_ACK				2
 
#define  UDI_MEI_OPCAT_NAK				3
 
#define  UDI_MEI_OPCAT_IND				4
 
#define  UDI_MEI_OPCAT_RES				5
 
#define  UDI_MEI_OPCAT_RDY				6
 
/* Values for op_flags */
 
#define UDI_MEI_OP_ABORTABLE (1U<<0) #define UDI_MEI_OP_RECOVERABLE (1U<<1) #define UDI_MEI_OP_STATE_CHANGE (1U<<2)
/* Maximum Sizes For Control Block Layouts */
 
#define UDI_MEI_MAX_VISIBLE_SIZE 2000 #define UDI_MEI_MAX_MARSHAL_SIZE 4000

MEMBERS op_name is the name of the entry point for the channel operation (exactly as documented for that operation; e.g. "udi_gio_xfer_req" for udi_gio_xfer_req), or NULL to terminate the op_template_list list to which this structure belongs (see udi_mei_ops_vec_template_t). Some environments may use this information to selectively trace channel operations. If op_name is NULL, all other members of this structure are ignored.

op_category is a number that identifies the category of the channel op described by this template, as indicated by its suffix. Channel op suffixes are described in Section 23.3, "Channel Operation Suffixes". Some environments may use this information to selectively trace channel operations.

op_flags is a bitmask of optional flags for this template, described below.

meta_cb_num is a number that identifies the control block group used with this operation, with respect to others in this metalanguage. It must be greater than zero.

completion_ops_num is a number that identifies the ops vector type that contains the completion operation, if any, that is the normal response to this operation. If zero, then there is no such response operation; otherwise, completion_ops_num must match a meta_ops_num in a udi_mei_ops_vec_template_t for this metalanguage.

completion_vec_idx is a number that identifies the index within the above ops vector that contains the function pointer for the completion operation, if any, that is the normal response to this operation, starting from zero. This is used if and only if completion_ops_num is non-zero.

exception_ops_num is a number that identifies the ops vector type that contains the exception operation, if any, that is the error response to this operation. If zero, then there is no such response operation; otherwise, completion_ops_num must match a meta_ops_num in a udi_mei_ops_vec_template_t for this metalanguage.

exception_vec_idx is a number that identifies the index within the above ops vector that contains the function pointer for the exception operation, if any, that is the error response to this operation, starting from zero. This is used if and only if exception_ops_num is non-zero.

direct_stub is a pointer to the function that implements the direct-call stub for this operation.

backend_stub is a pointer to the function that implements the back-end stub for this operation.

visible_layout is a pointer to the layout specifier for the visible part of the control block type used with this operation, excluding the generic udi_cb_t header.

marshal_layout is a pointer to the layout specifier for any marshalling space used to marshal extra parameters for this operation.

DESCRIPTION The udi_mei_ops_template_t structure contains information describing the metalanguage-specific properties of a channel operation and its associated control block type.

The visible size of any control block, as indicated by visible_layout, including the udi_cb_t header, must not exceed UDI_MEI_MAX_VISIBLE_SIZE (2000 bytes).

The size, in bytes, needed to marshal call-dependent parameters for any operation, as indicated by marshal_layout, must not exceed UDI_MEI_MAX_MARSHAL_SIZE (4000 bytes).

The environment can compute the maximum visible and marshal sizes for a control block group by aggregating across all occurrences of the meta_cb_num in the ops_vec_template_list.

If and only if op_flags includes UDI_MEI_OP_ABORTABLE, the channel operation described by this structure is abortable, and drivers may use udi_channel_op_abort to abort control blocks previously passed to this operation. The udi_channel_op_abort service call will deliver a udi_channel_event_ind operation of type UDI_CHANNEL_OP_ABORTED to the target region if the corresponding completion operation (as indicated by completion_ops_num and completion_vec_idx) or exception operation (as indicated by exception_ops_num and exception_vec_idx) has not yet been invoked.

If and only if op_flags includes UDI_MEI_OP_RECOVERABLE, the channel operation described by this structure is recoverable; if an operation of this type has been sent to a region that is abruptly terminated ("region-killed"), and the target region has not yet responded with the corresponding completion or exception operation, then the environment will automatically construct an exception operation to inform the initiating region of the failure, passing it the special status code, UDI_STAT_TERMINATED. If this flag is set, exception_ops_num must be non-zero. and the exception operation must contain exactly one UDI_DL_STATUS_T in either its visible_layout or its marshal_layout.

If and only if op_flags includes UDI_MEI_OP_STATE_CHANGE, the channel operation is considered to cause a change in the metalanguage-related state of the driver. Environments can use this to trace state changes externally to the driver.

warnings If visible_layout includes an inline pointer element (UDI_DL_INLINE_UNTYPED, UDI_DL_INLINE_TYPED, or UDI_DL_INLINE_DRIVER_TYPED), there must be exactly one op_template for this meta_cb_num of this metalanguage.

The marshal_layout specifier must include no inline pointers.

references udi_mei_ops_vec_template_t, udi_cb_t, udi_layout_t, udi_mei_direct_stub_t, udi_mei_backend_stub_t

NAME udi_mei_direct_stub_t

Metalanguage direct-call stub type

SYNOPSIS

#include <udi.h>

typedef void udi_mei_direct_stub_t (

	udi_op_t *op,

	udi_cb_t *gcb,

	va_list arglist );
 

ARGUMENTS op is a pointer to the driver entry point function in the target region that will be called to handle this operation. This function was declared in a udi_ops_init_t structure by the driver for the corresponding ops vector.

gcb is the pointer to the control block that is to be used for this operation (as passed by the driver requesting the operation).

arglist is the list of arguments that are to be passed to the op function.

DESCRIPTION The udi_mei_direct_stub_t type is used for metalanguage "direct" stub functions. These are used by udi_mei_call when it makes a direct call to the target region, without marshalling parameters.

Direct-call stubs are automatically generated by the UDI_MEI_STUBS macro.

references udi_ops_init_t, udi_mei_call, UDI_MEI_STUBS

NAME udi_mei_backend_stub_t

Metalanguage back-end stub type

SYNOPSIS

#include <udi.h>

typedef void udi_mei_backend_stub_t (

	udi_op_t *op,

	udi_cb_t *gcb,

	void *marshal_space );
 

ARGUMENTS op is a pointer to the driver entry point function in the target region that will be called to handle this operation. This function was declared in a udi_ops_init_t structure by the driver for the corresponding ops vector.

gcb is the pointer to the control block that is to be used for this operation (as passed by the driver requesting the operation).

marshal_space is a pointer to the marshalling space containing the marshalled parameters to pass as arguments to the op function.

DESCRIPTION The udi_mei_backend_stub_t type is used for metalanguage "back-end" stub functions. These are used by udi_mei_call when it makes a call to the target region for an operation that has previously been marshalled.

Back-end stubs are automatically generated by the UDI_MEI_STUBS macro.

references udi_ops_init_t, udi_mei_call, UDI_MEI_STUBS

NAME udi_mei_enumeration_rank_func_t

Metalanguage library device enumeration ranking

SYNOPSIS

#include <udi.h>

typedef udi_ubit8_t udi_mei_enumeration_rank_func_t (

	udi_ubit32_t attr_device_match,

	void **attr_value_list );
 

ARGUMENTS attr_device_match is a bitmask value where each bit represents a specific enumeration attribute as defined by the associated metalanguage. If the bit is set then the value for that attribute appears in the attr_value_list at an index that is equal to the bit number.

attr_value_list specifies the value of the enumerated attribute indicated by a non-zero bit at the corresponding bit offset in the attr_device_match argument. The metalanguage must not access array_value_list entries whose corresponding bit is not set in the attr_device_match argument.

DESCRIPTION The Management Agent (MA) will call the udi_mei_enumeration_rank function provided by the Metalanguage Library for each "device" declaration (see Device Declaration) that is a potential candidate for binding to an enumerated device. In order to be a valid candidate, the metalanguage and all enumeration attribute values specified in the "device" declaration must match the values for the enumerated device instance (though there may be additional enumerated attributes besidesthose specified in the "device" line). The rank function will only be called for valid candidates.

This routine is responsible for determining the "ranking" of this match as defined by the Metalanguage specification and returning that numeric ranking value to the MA. The rankable enumeration attributes specified by the parent are indicated to this function by setting a bit in the attr_device_match bitmask along with the attribute's value via the attr_value_list array.

After calling the rank function for all candidates, the MA will choose the candidate with the highest ranking value. If more than one driver matches with the same ranking value, the one with the greatest number of matching attributes will be chosen. If this still leaves multiple candidates, the MA will choose one of these candidates, in an implementation-dependent fashion.

RETURN VALUES This function returns the numerical ranking value for the specifed attribute values. Higher ranking values indicate better matches. The ranking values and methods are defined by each Metalanguage's specification.

REFERENCES udi_instance_attr_list_t, udi_enumerate_ack

28.3 Marshalling

In order for channel operations to be queued or transferred between domains, call-dependent parameters must be marshalled into marshalling space associated with the control block. Since the layout of these parameters is known only to the metalanguage, the metalanguage library stubs are responsible for marshalling and unmarshalling these parameters.

However, the content of the marshalling space must be laid out in a well-defined order, in case the marshalled control block is passed to another domain and the metalanguage stubs on the other end are implemented by a different instance of the metalanguage library. Both ends need to agree on the layout. Therefore, this specification standardizes that layout.

Each additional parameter after the control block pointer, for a given channel operation, in left-to-right order, shall be marshalled into the marshalling space starting at offset zero and proceeding with successive offsets.

28.4 MEI Stubs

The following section describes the stubs used by metalanguage libraries and the implementation of their functions. Each invocation of UDI_MEI_STUBS generates 3 stubs functions for a channel operation: front-end, direct-call, and back-end, with the following pseudo-code.

The front-end stub implements the exported interface for the caller side of a channel operation:

void

<<meta>>_<<op>> (

	<<meta>>_<cbtype>>_cb_t *cb,

	...<<call-dependent parms>>... )

{

	udi_mei_call(UDI_GCB(cb), &udi_meta_info, \

		ZZZ_OPS_NUM, ZZZ_VEC_IDX, \

		...<<call-dependent parms>>...);

}
 

The direct-call stub implements the call into the target driver when the environment wishes to invoke it directly from the original calling context:

static void

<<meta>>_<<op>>_direct (

	udi_op_t *op,

	udi_cb_t *gcb,

	va_list arglist )

{

	arg1_type arg1 = UDI_VA_ARG(arglist, arg1_type, arg1_va_code);

	...



	(*(<<meta>>_<<op>>_op_t)op)

		(UDI_MCB(gcb, <<meta>>_<cbtype>>_cb_t),

			arg1... );

}
 

The back-end stub implements the call into the target driver when the environment wishes to invoke it after having queued the channel operation:

static void

<<meta>>_<<op>>_backend (

	udi_op_t *op,

	udi_cb_t *gcb,

	void *marshal_space )

{

	struct <<meta>>_<<op>>_marshal {

		arg1_type arg1;

		...

	} *mp = marshal_space;



	(*(<<meta>>_<<op>>_op_t)op)

		(UDI_MCB(gcb, <<meta>>_<cbtype>>_cb_t),

			mp->arg1... );

}
 

NAME UDI_MEI_STUBS

Metalanguage stub generator macro

SYNOPSIS

#include <udi.h>

#define UDI_MEI_STUBS ( op_name, cb_type,

		argc, args, arg_types, arg_va_list,

		meta_ops_num, vec_idx )
 

ARGUMENTS op_name is a token specifying the name of the channel operation for which to create stub functions.

cb_type is the data type of control blocks used with this operation.

argc is the number of additional arguments to the operation.

args is a comma-separated list, enclosed in parentheses, of the names of the additional arguments.

arg_types is a comma-separated list, enclosed in parentheses, of the data types of the additional arguments.

arg_va_list is a comma-separated list, enclosed in parentheses, of the "VA codes" (see UDI_VA_ARG) for the additional arguments.

meta_ops_num is the metalanguage-defined identifier for the ops vector type to which this operation belongs. (See udi_mei_ops_vec_template_t.)

vec_idx is the index into the ops vector identified by meta_ops_num that corresponds to this operation, starting from zero. (A vec_idx of zero corresponds to the udi_channel_event_ind_op_t at the beginning of every ops vector type, and is not actually used in metalanguage libraries.)

DESCRIPTION Each invocation of UDI_MEI_STUBS creates the definition of the following three functions needed to support a metalanguage-specific channel operation:

Front-end stub:

	void op_name ( cb_type *cb 

			_UDI_ARG_LIST_##argc args );
 

Direct-call stub:

	static udi_mei_direct_stub_t op_name##_direct;
 

Back-end stub:

	static udi_mei_backend_stub_t op_name##_backend;
 

references udi_mei_ops_vec_template_t, udi_channel_event_ind, udi_mei_call, udi_mei_direct_stub_t, udi_mei_backend_stub_t, UDI_VA_ARG

examples The following examples illustrate the use of UDI_MEI_STUBS.

The udi_gio_bind_ack channel operation has three extra parameters and could be implemented using the stubs macro as follows:

UDI_MEI_STUBS(udi_gio_bind_ack, udi_gio_bind_cb_t,

		3, (device_size_lo, device_size_hi, status),

		 (udi_ubit32_t, udi_ubit32_t, udi_status_t),

		 (UDI_VA_UBIT32_T, UDI_VA_UBIT32_T,

		  UDI_VA_STATUS_T),

		UDI_GIO_CLIENT_OPS_NUM,

		UDI_GIO_BIND_ACK)
 

The udi_scsi_io_req channel operation has no extra parameters and could be implemented using the stubs macro as follows:

UDI_MEI_STUBS(udi_scsi_io_req, udi_scsi_io_cb_t,

		0, (), (), (),

		UDI_SCSI_META_ID, UDI_SCSI_HD_OPS_NUM,

		UDI_SCSI_IO_REQ)
 

NAME udi_mei_call

Channel operation invocation

SYNOPSIS

#include <udi.h>

void udi_mei_call (

	udi_cb_t *gcb,

	udi_mei_init_t *meta_info,

	udi_index_t meta_ops_num,

	udi_index_t vec_idx,

	... );
 

ARGUMENTS gcb is a pointer to the control block passed to the actual channel operation.

meta_info is a pointer to this metalanguage's udi_meta_info structure, which can be used to uniquely identify this metalanguage.

meta_ops_num is the metalanguage-defined identifier for the ops vector type to which this operation belongs. (See udi_mei_ops_vec_template_t.)

vec_idx is the index into the ops vector identified by meta_ops_num that corresponds to this operation, starting from zero. (A vec_idx of zero corresponds to the udi_channel_event_ind_op_t at the beginning of every ops vector type, and is not actually used in metalanguage libraries.)

... are zero or more additional metalanguage-specific parameters for this channel operation. This will be passed to the callee-side entry point in the target driver, immediately following the control block argument.

DESCRIPTION This function is called from within a portable front-end stub to implement a channel operation. udi_mei_call prepares the control block for transfer to the target region, possibly reallocating the space for the control block and/or its scratch space. It also arranges for the corresponding entry point to be called in the target region, either "directly" (w/o queuing) or as a queued or cross-domain indirect operation.

If the environment chooses to (and is able to) make a direct call, udi_mei_call will make use of the corresponding direct-call stub in the metalanguage library to make the actual call to the target region with the appropriate parameters. This is the highest performance path and is thus specially optimized. The direct-call stub (of type udi_mei_direct_stub_t) simply takes the arguments pointed to by the var-args arglist, and calls the indicated function with these arguments.

There are many reasons why the environment might not use a direct call. Some of these include excess call depth, busy regions and domain crossings. All other things being equal, ownership transfer for transferable objects can be handled with the direct case.

If udi_mei_call does not make a direct call, it must first marshal any call-dependent parameters into the marshalling space of the control block. It can determine the number and type of these parameters from the marshal_layout in the ops template for this operation. The ops template can be located by a combination of either gcb->channel and vec_idx or meta_init and meta_ops_num. (Providing both of these sets of values to udi_mei_call allows for a double-check that the correct types of channel and control block were passed to the channel operation.)

After the control block is queued, copied across domains, or subject to any further processing needed by the environment, it will eventually need to be passed to the target region with the appropriate call-dependent parameters. This is done by calling the appropriate back-end stub (of type udi_mei_backend_stub_t) in the metalanguage library. The back-end stub unmarshals the parameters from the marshalling space (pointed to by marshal_space) and calls the driver entry point with these parameters

references udi_mei_ops_vec_template_t, udi_channel_event_ind, udi_mei_direct_stub_t, udi_mei_backend_stub_t, UDI_MEI_STUBS

NAME udi_mei_driver_error

Metalanguage violation by the driver

SYNOPSIS

#include <udi.h>

void udi_mei_driver_error (

	udi_cb_t *gcb,

	udi_mei_init_t *meta_info,

	udi_index_t meta_ops_num,

	udi_index_t vec_idx );
 

ARGUMENTS gcb is a pointer to the control blocked passed to the actual channel operation.

meta_info is a pointer to this metalanguage's udi_meta_info structure, which can be used to uniquely identify this metalanguage.

meta_ops_num is the metalanguage-defined identifier for the ops vector type to which this operation belongs.

vec_idx is the index into the ops vector identified by meta_ops_num that corresponds to this operation, starting from zero.

DESCRIPTION This function is called by a metalanguage library when it determines that the driver that issued the specified channel operation has performed an illegal operation. An illegal operation includes one in which the operation parameters for the channel operation are invalid. The metalanguage library is not required to check for invalid parameters or other illegal conditions, and should normally not check for invalid parameter values that would (per the metalanguage definition) be expected to be checked in the target driver. Illegal conditions that are detectable only by a portable metalanguage library (not by either the driver or the environment) should be checked for in untrusting metalanguage library implementations.

The environment may choose to handle the specified operation in several ways, including killing the region or completing the operation via the exception completion operation with a UDI_STAT_NOT_UNDERSTOOD status code. In all cases, ownership of the control block is passed to the environment and the metalanguage should no longer access the control block or operate on behalf of this channel operation after the udi_mei_driver_error call returns.

REFERENCES udi_mei_call

28.5 MEI Stub Implementation

This section presents a typical implementation of the UDI_MEI_STUBS macro. Actual implementations of UDI_MEI_STUBS may vary, but must generate equivalent code.

#define UDI_MEI_STUBS(op_name, cb_type, \

				 argc, args, arg_types, \

				 meta_ID, ops_num, vec_idx) \

	void op_name ( cb_type *cb \

		         _UDI_ARG_LIST_##argc args ) { \

		udi_mei_call ( UDI_GCB(cb), &udi_meta_info, \

				   ops_num, vec_idx \

				   _UDI_ARG_VARS_##argc ); \

	} \

	static void op_name##_direct ( \

				udi_op_t *op, udi_cb_t *gcb, \

				va_list arglist ) { \

		_UDI_VA_ARGS_##argc arg_types \

		\

		(*(op_name##_op_t *)op) ( \

				UDI_MCB(gcb, cb_type) \

				_UDI_ARG_VARS_##argc ); \

	} \

	static void op_name##_backend ( \

				udi_op_t *op, udi_cb_t *gcb, \

				void *marshal_space ) { \

		struct op_name##_marshal { \

			_UDI_ARG_MEMBERS_##argc arg_types \

		} *mp = marshal_space; \

		\

		(*(op_name##_op_t *)op) ( \

				UDI_MCB(gcb, cb_type) \

				_UDI_MP_ARGS_##argc ); \

	}
 

 
#define _UDI_ARG_LIST_0()

#define _UDI_ARG_LIST_1(a)             ,a arg1

#define _UDI_ARG_LIST_2(a,b)           ,a arg1,b arg2

#define _UDI_ARG_LIST_3(a,b,c)         ,a arg1,b arg2,c arg3

#define _UDI_ARG_LIST_4(a,b,c,d)       \

			,a arg1,b arg2,c arg3,d arg4

#define _UDI_ARG_LIST_5(a,b,c,d,e)     \

			,a arg1,b arg2,c arg3,d arg4,e arg5

#define _UDI_ARG_LIST_6(a,b,c,d,e,f)   \

			,a arg1,b arg2,c arg3,d arg4,e arg5,f arg6

#define _UDI_ARG_LIST_7(a,b,c,d,e,f,g) \

			,a arg1,b arg2,c arg3,d arg4,e arg5,f arg6,g arg7
 

 
/*

 * The following macros are used to concatenate two argument lists.

 */
 
#define _UDI_L_0()                 (

#define _UDI_L_1(a)                (a,

#define _UDI_L_2(a,b)              (a,b,

#define _UDI_L_3(a,b,c)            (a,b,c,

#define _UDI_L_4(a,b,c,d)          (a,b,c,d,

#define _UDI_L_5(a,b,c,d,e)        (a,b,c,d,e,

#define _UDI_L_6(a,b,c,d,e,f)      (a,b,c,d,e,f,

#define _UDI_L_7(a,b,c,d,e,f,g)    (a,b,c,d,e,f,g,
 

 
#define _UDI_R_0()                 )

#define _UDI_R_1(a)                a)

#define _UDI_R_2(a,b)              a,b)

#define _UDI_R_3(a,b,c)            a,b,c)

#define _UDI_R_4(a,b,c,d)          a,b,c,d)

#define _UDI_R_5(a,b,c,d,e)        a,b,c,d,e)

#define _UDI_R_6(a,b,c,d,e,f)      a,b,c,d,e,f)

#define _UDI_R_7(a,b,c,d,e,f,g)    a,b,c,d,e,f,g)
 

 
#define _UDI_CAT_LIST(argc,list1,list2) \

			_UDI_L_##argc list1 _UDI_R_##argc list2
 

 
#define _UDI_VA_ARGS_0()

#define _UDI_VA_ARGS_1(a,va_a) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a);

#define _UDI_VA_ARGS_2(a,b,va_a,va_b) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a); \

			b arg2 = UDI_VA_ARG(arglist, b, va_b);

#define _UDI_VA_ARGS_3(a,b,c,va_a,va_b,va_c) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a); \

			b arg2 = UDI_VA_ARG(arglist, b, va_b); \

			c arg3 = UDI_VA_ARG(arglist, c, va_c);

#define _UDI_VA_ARGS_4(a,b,c,d,va_a,va_b,va_c,va_d) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a); \

			b arg2 = UDI_VA_ARG(arglist, b, va_b); \

			c arg3 = UDI_VA_ARG(arglist, c, va_c); \

			d arg4 = UDI_VA_ARG(arglist, d, va_d);

#define _UDI_VA_ARGS_5(a,b,c,d,e,va_a,va_b,va_c,va_d,va_e) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a); \

			b arg2 = UDI_VA_ARG(arglist, b, va_b); \

			c arg3 = UDI_VA_ARG(arglist, c, va_c); \

			d arg4 = UDI_VA_ARG(arglist, d, va_d); \

			e arg5 = UDI_VA_ARG(arglist, e, va_e);

#define _UDI_VA_ARGS_6(a,b,c,d,e,f, \

				  va_a,va_b,va_c,va_d,va_e,va_f) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a); \

			b arg2 = UDI_VA_ARG(arglist, b, va_b); \

			c arg3 = UDI_VA_ARG(arglist, c, va_c); \

			d arg4 = UDI_VA_ARG(arglist, d, va_d); \

			e arg5 = UDI_VA_ARG(arglist, e, va_e); \

			f arg6 = UDI_VA_ARG(arglist, f, va_f);

#define _UDI_VA_ARGS_7(a,b,c,d,e,f,g, \

				  va_a,va_b,va_c,va_d,va_e,va_f,va_g) \

			a arg1 = UDI_VA_ARG(arglist, a, va_a); \

			b arg2 = UDI_VA_ARG(arglist, b, va_b); \

			c arg3 = UDI_VA_ARG(arglist, c, va_c); \

			d arg4 = UDI_VA_ARG(arglist, d, va_d); \

			e arg5 = UDI_VA_ARG(arglist, e, va_e); \

			f arg6 = UDI_VA_ARG(arglist, f, va_f); \

			g arg7 = UDI_VA_ARG(arglist, g, va_g);
 

 
#define __UDI_VA_ARGLIST(argc,list) \

			_UDI_VA_ARGS_##argc list
 

 
#define _UDI_VA_ARGLIST(argc,list1,list2) \

			__UDI_VA_ARGLIST(argc, \

				_UDI_CAT_LIST(argc, list1, list2))
 

 
#define _UDI_ARG_VARS_0

#define _UDI_ARG_VARS_1 ,arg1

#define _UDI_ARG_VARS_2 ,arg1,arg2

#define _UDI_ARG_VARS_3 ,arg1,arg2,arg3

#define _UDI_ARG_VARS_4 ,arg1,arg2,arg3,arg4

#define _UDI_ARG_VARS_5 ,arg1,arg2,arg3,arg4,arg5

#define _UDI_ARG_VARS_6 ,arg1,arg2,arg3,arg4,arg5,arg6

#define _UDI_ARG_VARS_7 ,arg1,arg2,arg3,arg4,arg5,arg6,arg7
 

 
#define _UDI_ARG_MEMBERS_0() \

			char dummy;

#define _UDI_ARG_MEMBERS_1(a) \

			a arg1;

#define _UDI_ARG_MEMBERS_2(a,b) \

			a arg1; \

			b arg2;

#define _UDI_ARG_MEMBERS_3(a,b,c) \

			a arg1; \

			b arg2; \

			c arg3;

#define _UDI_ARG_MEMBERS_4(a,b,c,d) \

			a arg1; \

			b arg2; \

			c arg3; \

			d arg4;

#define _UDI_ARG_MEMBERS_5(a,b,c,d,e) \

			a arg1; \

			b arg2; \

			c arg3; \

			d arg4; \

			e arg5;

#define _UDI_ARG_MEMBERS_6(a,b,c,d,e,f) \

			a arg1; \

			b arg2; \

			c arg3; \

			d arg4; \

			e arg5; \

			f arg6;
 
#define _UDI_ARG_MEMBERS_7(a,b,c,d,e,f,g) \

			a arg1; \

			b arg2; \

			c arg3; \

			d arg4; \

			e arg5; \

			f arg6; \

			g arg7;
 

 
#define _UDI_MP_ARGS_0

#define _UDI_MP_ARGS_1 ,mp->arg1

#define _UDI_MP_ARGS_2 ,mp->arg1,mp->arg2

#define _UDI_MP_ARGS_3 ,mp->arg1,mp->arg2,mp->arg3

#define _UDI_MP_ARGS_4 ,mp->arg1,mp->arg2,mp->arg3,mp->arg4

#define _UDI_MP_ARGS_5 ,mp->arg1,mp->arg2,mp->arg3,mp->arg4, \

					mp->arg5

#define _UDI_MP_ARGS_6 ,mp->arg1,mp->arg2,mp->arg3,mp->arg4, \

					mp->arg5,mp->arg6

#define _UDI_MP_ARGS_7 ,mp->arg1,mp->arg2,mp->arg3,mp->arg4, \

					mp->arg5,mp->arg6,mp->arg7
 


TOC PREV NEXT INDEX