LAPI_Util Subroutine

Purpose

Serves as a wrapper function for such data gather/scatter operations as registration and reservation, for updating UDP port information, and for obtaining pointers to locking and signaling functions that are associated with a shared LAPI lock.

Library

Availability Library (liblapi_r.a)

C Syntax

#include <lapi.h>
 
int LAPI_Util(hndl, util_cmd)
lapi_handle_t hndl;
lapi_util_t *util_cmd;

FORTRAN Syntax

include 'lapif.h'
 
LAPI_UTIL(hndl, util_cmd, ierror)
INTEGER hndl
TYPE (LAPI_UTIL_T) :: util_cmd
INTEGER ierror

Description

Type of call: Data gather/scatter program (DGSP), UDP port information, and lock sharing utilities

This subroutine is used for several different operations, which are indicated by the command type value in the beginning of the command structure. The lapi_util_t structure is defined as:
typedef union {
    lapi_util_type_t    Util_type;  
    lapi_reg_dgsp_t     RegDgsp;    
    lapi_dref_dgsp_t    DrefDgsp;   
    lapi_resv_dgsp_t    ResvDgsp;   
    lapi_reg_ddm_t      DdmFunc;    
    lapi_add_udp_port_t Udp;        
    lapi_pack_dgsp_t    PackDgsp;   
    lapi_unpack_dgsp_t  UnpackDgsp;
    lapi_thread_func_t  ThreadFunc;
} lapi_util_t;
The enumerated type lapi_util_type_t has these values:
Table 1. lapi_util_type_t types
Value of Util_type Union member as interpreted by LAPI_Util
LAPI_REGISTER_DGSP lapi_reg_dgsp_t
LAPI_UNRESERVE_DGSP lapi_dref_dgsp_t
LAPI_RESERVE_DGSP lapi_resv_dgsp_t
LAPI_REG_DDM_FUNC lapi_reg_ddm_t
LAPI_ADD_UDP_DEST_PORT lapi_add_udp_port_t
LAPI_DGSP_PACK lapi_pack_dgsp_t
LAPI_DGSP_UNPACK lapi_unpack_dgsp_t
LAPI_GET_THREAD_FUNC lapi_thread_func_t
hndl is not checked for command type LAPI_REGISTER_DGSP, LAPI_RESERVE_DGSP, or LAPI_UNRESERVE_DGSP.

LAPI_REGISTER_DGSP

You can use this operation to register a LAPI DGSP that you have created. To register a LAPI DGSP, lapi_dgsp_descr_t idgsp must be passed in. LAPI returns a handle (lapi_dg_handle_t dgsp_handle) to use for all future LAPI calls. The dgsp_handle that is returned by a register operation is identified as a lapi_dg_handle_t type, which is the appropriate type for LAPI_Xfer and LAPI_Util calls that take a DGSP. This returned dgsp_handle is also defined to be castable to a pointer to a lapi_dgsp_descr_t for those situations where the LAPI user requires read-only access to information that is contained in the cached DGSP. The register operation delivers a DGSP to LAPI for use in future message send, receive, pack, and unpack operations. LAPI creates its own copy of the DGSP and protects it by reference count. All internal LAPI operations that depend on a DGSP cached in LAPI ensure the preservation of the DGSP by incrementing the reference count when they begin a dependency on the DGSP and decrementing the count when that dependency ends. A DGSP, once registered, can be used from any LAPI instance. LAPI_Term does not discard any DGSPs.

You can register a DGSP, start one or more LAPI operations using the DGSP, and then unreserve it with no concern about when the LAPI operations that depend on the DGSP will be done using it. See LAPI_RESERVE_DGSP and LAPI_UNRESERVE_DGSP for more information.

In general, the DGSP you create and pass in to the LAPI_REGISTER_DGSP call using the dgsp parameter is discarded after LAPI makes and caches its own copy. Because DGSP creation is complex, user errors may occur, but extensive error checking at data transfer time would hurt performance. When developing code that creates DGSPs, you can invoke extra validation at the point of registration by setting the LAPI_VERIFY_DGSP environment variable. LAPI_Util will return any detected errors. Any errors that exist and are not detected at registration time will cause problems during data transfer. Any errors detected during data transfer will be reported by an asynchronous error handler. A segmentation fault is one common symptom of a faulty DGSP. If multiple DGSPs are in use, the asynchronous error handler will not be able to identify which DGSP caused the error. For more information about asynchronous error handling, see LAPI_Init.

LAPI_REGISTER_DGSP uses the lapi_reg_dgsp_t command structure.
Table 2. The lapi_reg_dgsp_t fields
lapi_reg_dgsp_t field lapi_reg_dgsp_t field type lapi_reg_dgsp_t usage
Util_type lapi_util_type_t LAPI_REGISTER_DGSP
idgsp lapi_dgsp_descr_t IN - pointer to DGSP program
dgsp_handle lapi_dg_handle_t OUT - handle for a registered DGSP program
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_RESERVE_DGSP

You can use this operation to reserve a DGSP. This operation is provided because a LAPI client might cache a LAPI DGSP handle for later use. The client needs to ensure the DGSP will not be discarded before the cached handle is used. A DGSP handle, which is defined to be a pointer to a DGSP description that is already cached inside LAPI, is passed to this operation. The DGSP handle is also defined to be a structure pointer, so that client programs can get direct access to information in the DGSP. Unless the client can be certain that the DGSP will not be "unreserved" by another thread while it is being accessed, the client should bracket the access window with its own reserve/unreserve operation. The client is not to modify the cached DGSP, but LAPI has no way to enforce this. The reserve operation increments the user reference count, thus protecting the DGSP until an unreserve operation occurs. This is needed because the thread that placed the reservation will expect to be able to use or examine the cached DGSP until it makes an unreserve call (which decrements the user reference count), even if the unreserve operation that matches the original register operation occurs within this window on some other thread.

LAPI_RESERVE_DGSP uses the lapi_resv_dgsp_t command structure.
Table 3. The lapi_resv_dgsp_t fields
lapi_resv_dgsp_t field lapi_resv_dgsp_t field type lapi_resv_dgsp_t usage
Util_type lapi_util_type_t LAPI_RESERVE_DGSP
dgsp_handle lapi_dg_handle_t OUT - handle for a registered DGSP program
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_UNRESERVE_DGSP

You can use this operation to unregister or unreserve a DGSP. This operation decrements the user reference count. If external and internal reference counts are zero, this operation lets LAPI free the DGSP. All operations that decrement a reference count cause LAPI to check to see if the counts have both become 0 and if they have, dispose of the DGSP. Several internal LAPI activities increment and decrement a second reference count. The cached DGSP is disposable only when all activities (internal and external) that depend on it and use reference counting to preserve it have discharged their reference. The DGSP handle is passed to LAPI as a value parameter and LAPI does not nullify the caller's handle. It is your responsibility to not use this handle again because in doing an unreserve operation, you have indicated that you no longer count on the handle remaining valid.

LAPI_UNRESERVE_DGSP uses the lapi_dref_dgsp_t command structure.
Table 4. The lapi_dref_dgsp_t fields
lapi_dref_dgsp_t field lapi_dref_dgsp_t field type lapi_dref_dgsp_t usage
Util_type lapi_util_type_t LAPI_UNRESERVE_DGSP
dgsp_handle lapi_dg_handle_t OUT - handle for a registered DGSP program
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_REG_DDM_FUNC

You can use this operation to register data distribution manager (DDM) functions. It works in conjunction with the DGSM CONTROL instruction. Primarily, it is used for MPI_Accumulate, but LAPI clients can provide any DDM function. It is also used to establish a callback function for processing data that is being scattered into a user buffer on the destination side.

The native LAPI user can install a callback without affecting the one MPI has registered for MPI_Accumulate. The function prototype for the callback function is:
typedef long ddm_func_t (        /* return number of bytes processed */
        void      *in,           /* pointer to inbound data          */
        void      *inout,        /* pointer to destination space     */
        long      bytes,         /* number of bytes inbound          */
        int       operand,       /* CONTROL operand value            */
        int       operation      /* CONTROL operation value          */
);

A DDM function acts between the arrival of message data and the target buffer. The most common usage is to combine inbound data with data already in the target buffer. For example, if the target buffer is an array of integers and the incoming message consists of integers, the DDM function can be written to add each incoming integer to the value that is already in the buffer. The operand and operation fields of the DDM function allow one DDM function to support a range of operations with the CONTROL instruction by providing the appropriate values for these fields.

See RSCT for AIX 5L™: LAPI Programming Guide for more information about DGSP programming.

LAPI_REG_DDM_FUNC uses the lapi_reg_ddm_t command structure. Each call replaces the previous function pointer, if there was one.
Table 5. The lapi_reg_ddm_t fields
lapi_reg_ddm_t field lapi_reg_ddm_t field type lapi_reg_ddm_t usage
Util_type lapi_util_type_t LAPI_REG_DDM_FUNC
ddm_func ddm_func_t * IN - DDM function pointer
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_DGSP_PACK

You can use this operation to gather data to a pack buffer from a user buffer under control of a DGSP. A single buffer may be packed by a series of calls. The caller provides a position value that is initialized to the starting offset within the buffer. Each pack operation adjusts position, so the next pack operation can begin where the previous pack operation ended. In general, a series of pack operations begins with position initialized to 0, but any offset is valid. There is no state carried from one pack operation to the next. Each pack operation starts at the beginning of the DGSP it is passed.

LAPI_DGSP_PACK uses the lapi_pack_dgsp_t command structure.
Table 6. The lapi_pack_dgsp_t fields
lapi_pack_dgsp_t field lapi_pack_dgsp_t field type lapi_pack_dgsp_t usage
Util_type lapi_util_type_t LAPI_DGSP_PACK
dgsp_handle lapi_dg_handle_t OUT - handle for a registered DGSP program
in_buf void * IN - source buffer to pack
bytes ulong IN - number of bytes to pack
out_buf void * OUT - output buffer for pack
out_size ulong IN - output buffer size in bytes
position ulong IN/OUT - current buffer offset
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_DGSP_UNPACK

You can use this operation to scatter data from a packed buffer to a user buffer under control of a DGSP. A single buffer may be unpacked by a series of calls. The caller provides a position value that is initialized to the starting offset within the packed buffer. Each unpack operation adjusts position, so the next unpack operation can begin where the previous unpack operation ended. In general, a series of unpack operations begins with position initialized to 0, but any offset is valid. There is no state carried from one unpack operation to the next. Each unpack operation starts at the beginning of the DGSP it is passed.

LAPI_DGSP_UNPACK uses the lapi_unpack_dgsp_t command structure.
Table 7. The lapi_unpack_dgsp_t fields
lapi_unpack_dgsp_t field lapi_unpack_dgsp_t field type lapi_unpack_dgsp_t usage
Util_type lapi_util_type_t LAPI_DGSP_UNPACK
dgsp_handle lapi_dg_handle_t OUT - handle for a registered DGSP program
buf void * IN - source buffer for unpack
in_size ulong IN - source buffer size in bytes
out_buf void * OUT - output buffer for unpack
bytes ulong IN - number of bytes to unpack
out_size ulong IN - output buffer size in bytes
position ulong IN/OUT - current buffer offset
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_ADD_UDP_DEST_PORT

You can use this operation to update UDP port information about the destination task. This operation can be used when you have written your own UDP handler (udp_hndlr) and you need to support recovery of failed tasks. You cannot use this operation under the POE runtime environment.

LAPI_ADD_UDP_DEST_PORT uses the lapi_add_udp_port_t command structure.
Table 8. The lapi_add_udp_port_t fields
lapi_add_udp_port_t field lapi_add_udp_port_t field type lapi_add_udp_port_t usage
Util_type lapi_util_type_t LAPI_ADD_UDP_DEST_PORT
tgt uint IN - destination task ID
udp_port lapi_udp_t * IN - UDP port information for the target
instance_no uint IN - Instance number of UDP
in_usr_func lapi_usr_fcall_t For debugging only
status lapi_status_t OUT - future support

LAPI_GET_THREAD_FUNC

You can use this operation to retrieve various shared locking and signaling functions. Retrieval of these functions is valid only after LAPI is initialized and before LAPI is terminated. You should not call any of these functions after LAPI is terminated.

LAPI_GET_THREAD_FUNC uses the lapi_thread_func_t command structure.
Table 9. The lapi_thread_func_t fields
lapi_thread_func_t field lapi_thread_func_t field type lapi_thread_func_t usage
Util_type lapi_util_type_t LAPI_GET_THREAD_FUNC
mutex_lock lapi_mutex_lock_t OUT - mutex lock function pointer
mutex_unlock lapi_mutex_unlock_t OUT - mutex unlock function pointer
mutex_trylock lapi_mutex_trylock_t OUT - mutex try lock function pointer
mutex_getowner lapi_mutex_getowner_t OUT - mutex get owner function pointer
cond_wait lapi_cond_wait_t OUT - condition wait function pointer
cond_timedwait lapi_cond_timedwait_t OUT - condition timed wait function pointer
cond_signal lapi_cond_signal_t OUT - condition signal function pointer
cond_init lapi_cond_init_t OUT - initialize condition function pointer
cond_destroy lapi_cond_destroy_t OUT - destroy condition function pointer

LAPI uses the pthread library for thread ID management. You can therefore use pthread_self() to get the running thread ID and lapi_mutex_getowner_t to get the thread ID that owns the shared lock. Then, you can use pthread_equal() to see if the two are the same.

Mutex thread functions

LAPI_GET_THREAD_FUNC includes the following mutex thread functions: mutex lock, mutex unlock, mutex try lock, and mutex get owner.

Mutex lock function pointer
int (*lapi_mutex_lock_t)(lapi_handle_t hndl);
This function acquires the lock that is associated with the specified LAPI handle. The call blocks if the lock is already held by another thread. Deadlock can occur if the calling thread is already holding the lock. You are responsible for preventing and detecting deadlocks.
Parameters
INPUT
hndl
Specifies the LAPI handle.
Return values
0
Indicates that the lock was acquired successfully.
EINVAL
Is returned if the lock is not valid because of an incorrect hndl value.
Mutex unlock function pointer
int (*lapi_mutex_unlock_t)(lapi_handle_t hndl);
This function releases the lock that is associated with the specified LAPI handle. A thread should only unlock its own locks.
Parameters
INPUT
hndl
Specifies the LAPI handle.
Return values
0
Indicates that the lock was released successfully.
EINVAL
Is returned if the lock is not valid because of an incorrect hndl value.
Mutex try lock function pointer
int (*lapi_mutex_trylock_t)(lapi_handle_t hndl);
This function tries to acquire the lock that is associated with the specified LAPI handle, but returns immediately if the lock is already held.
Parameters
INPUT
hndl
Specifies the LAPI handle.
Return values
0
Indicates that the lock was acquired successfully.
EBUSY
Indicates that the lock is being held.
EINVAL
Is returned if the lock is not valid because of an incorrect hndl value.
Mutex get owner function pointer
int (*lapi_mutex_getowner_t)(lapi_handle_t hndl, pthread_t *tid);
This function gets the pthread ID of the thread that is currently holding the lock associated with the specified LAPI handle. LAPI_NULL_THREAD_ID indicates that the lock is not held at the time the function is called.
Parameters
INPUT
hndl
Specifies the LAPI handle.
OUTPUT
tid
Is a pointer to hold the pthread ID to be retrieved.
Return values
0
Indicates that the lock owner was retrieved successfully.
EINVAL
Is returned if the lock is not valid because of an incorrect hndl value.

Condition functions

LAPI_GET_THREAD_FUNC includes the following condition functions: condition wait, condition timed wait, condition signal, initialize condition, and destroy condition.

Condition wait function pointer
int (*lapi_cond_wait_t)(lapi_handle_t hndl, lapi_cond_t *cond);
This function waits on a condition variable (cond). The user must hold the lock associated with the LAPI handle (hndl) before making the call. Upon the return of the call, LAPI guarantees that the lock is still being held. The same LAPI handle must be supplied to concurrent lapi_cond_wait_t operations on the same condition variable.
Parameters
INPUT
hndl
Specifies the LAPI handle.
cond
Is a pointer to the condition variable to be waited on.
Return values
0
Indicates that the condition variable has been signaled.
EINVAL
Indicates that the value specified by hndl or cond is not valid.
Condition timed wait function pointer
int (*lapi_cond_timedwait_t)(lapi_handle_t hndl, 
                             lapi_cond_t *cond, 
                             struct timespec *timeout);
This function waits on a condition variable (cond). The user must hold the lock associated with the LAPI handle (hndl) before making the call. Upon the return of the call, LAPI guarantees that the lock is still being held. The same LAPI handle must be supplied to concurrent lapi_cond_timedwait_t operations on the same condition variable.
Parameters
INPUT
hndl
Specifies the LAPI handle.
cond
Is a pointer to the condition variable to be waited on.
timeout
Is a pointer to the absolute time structure specifying the timeout.
Return values
0
Indicates that the condition variable has been signaled.
ETIMEDOUT
Indicates that time specified by timeout has passed.
EINVAL
Indicates that the value specified by hndl, cond, or timeout is not valid.
Condition signal function pointer
int (*lapi_cond_wait_t)(lapi_handle_t hndl, lapi_cond_t *cond);
typedef int (*lapi_cond_signal_t)(lapi_handle_t hndl, lapi_cond_t *cond);
This function signals a condition variable (cond) to wake up a thread that is blocked on the condition. If there are multiple threads waiting on the condition variable, which thread to wake up is decided randomly.
Parameters
INPUT
hndl
Specifies the LAPI handle.
cond
Is a pointer to the condition variable to be signaled.
Return values
0
Indicates that the condition variable has been signaled.
EINVAL
Indicates that the value specified by hndl or cond is not valid.
Initialize condition function pointer
int (*lapi_cond_init_t)(lapi_handle_t hndl, lapi_cond_t *cond);
This function initializes a condition variable.
Parameters
INPUT
hndl
Specifies the LAPI handle.
cond
Is a pointer to the condition variable to be initialized.
Return values
0
Indicates that the condition variable was initialized successfully.
EAGAIN
Indicates that the system lacked the necessary resources (other than memory) to initialize another condition variable.
ENOMEM
Indicates that there is not enough memory to initialize the condition variable.
EINVAL
Is returned if the hndl value is not valid.
Destroy condition function pointer
int (*lapi_cond_destroy_t)(lapi_handle_t hndl, lapi_cond_t *cond);
This function destroys a condition variable.
Parameters
INPUT
hndl
Specifies the LAPI handle.
cond
Is a pointer to the condition variable to be destroyed.
Return values
0
Indicates that the condition variable was destroyed successfully.
EBUSY
Indicates that the implementation has detected an attempt to destroy the object referenced by cond while it is referenced (while being used in a lapi_cond_wait_t or lapi_cond_timedwait_t by another thread, for example).
EINVAL
Indicates that the value specified by hndl or cond is not valid.

Parameters

INPUT
hndl
Specifies the LAPI handle.
INPUT/OUTPUT
util_cmd
Specifies the command type of the utility function.
OUTPUT
ierror
Specifies a FORTRAN return code. This is always the last parameter.

Return Values

LAPI_SUCCESS
Indicates that the function call completed successfully.
LAPI_ERR_DGSP
Indicates that the DGSP that was passed in is NULL (in C) or LAPI_ADDR_NULL (in FORTRAN) or is not a registered DGSP.
LAPI_ERR_DGSP_ATOM
Indicates that the DGSP has an atom_size that is less than 0 or greater than MAX_ATOM_SIZE.
LAPI_ERR_DGSP_BRANCH
Indicates that the DGSP attempted a branch that fell outside of the code array. This is returned only in validation mode.
LAPI_ERR_DGSP_COPY_SZ
Is returned with DGSP validation turned on when MCOPY block < 0 or COPY instruction with bytes < 0. This is returned only in validation mode.
LAPI_ERR_DGSP_FREE
Indicates that LAPI tried to free a DGSP that is not valid or is no longer registered. There should be one LAPI_UNRESERVE_DGSP operation to close the LAPI_REGISTER_DGSP operation and one LAPI_UNRESERVE_DGSP operation for each LAPI_RESERVE_DGSP operation.
LAPI_ERR_DGSP_OPC
Indicates that the DGSP opcode is not valid. This is returned only in validation mode.
LAPI_ERR_DGSP_STACK
Indicates that the DGSP has a greater GOSUB depth than the allocated stack supports. Stack allocation is specified by the dgsp->depth member. This is returned only in validation mode.
LAPI_ERR_HNDL_INVALID
Indicates that the hndl passed in is not valid (not initialized or in terminated state).
LAPI_ERR_MEMORY_EXHAUSTED
Indicates that LAPI is unable to obtain memory from the system.
LAPI_ERR_UDP_PORT_INFO
Indicates that the udp_port information pointer is NULL (in C) or that the value of udp_port is LAPI_ADDR_NULL (in FORTRAN).
LAPI_ERR_UTIL_CMD
Indicates that the command type is not valid.

C Examples

  1. To create and register a DGSP:
    {
          /*
          ** DGSP code array.  DGSP instructions are stored
          ** as ints (with constants defined in lapi.h for
          ** the number of integers needed to store each
          ** instruction).  We will have one COPY and one ITERATE
          ** instruction in our DGSP.  We use LAPI's constants
          ** to allocate the appropriate storage.
          */
          int code[LAPI_DGSM_COPY_SIZE+LAPI_DGSM_ITERATE_SIZE];
    
          /* DGSP description */
          lapi_dgsp_descr_t dgsp_d;
    
          /*
          ** Data structure for the xfer call.
          */
          lapi_xfer_t   xfer_struct;
    
       
          /* DGSP data structures */
          lapi_dgsm_copy_t     *copy_p;   /* copy instruction    */
          lapi_dgsm_iterate_t  *iter_p;   /* iterate instruction */
          int                  *code_ptr; /* code pointer        */
    
          /* constant for holding code array info */
          int                   code_less_iterate_size;
    
          /* used for DGSP registration */
          lapi_reg_dgsp_t     reg_util;
    
    
          /*
          ** Set up dgsp description
          */
    
          /* set pointer to code array */
          dgsp_d.code = &code[0];
    
          /* set size of code array */
          dgsp_d.code_size = LAPI_DGSM_COPY_SIZE + LAPI_DGSM_ITERATE_SIZE;
    
          /* not using DGSP gosub instruction */
          dgsp_d.depth = 1;
    
          /*
          ** set density to show internal gaps in the
          ** DGSP data layout
          */
          dgsp_d.density = LAPI_DGSM_SPARSE;
    
          /* transfer 4 bytes at a time */
          dgsp_d.size = 4;
    
          /* advance the template by 8 for each iteration */
          dgsp_d.extent = 8;
    
          /*
          ** ext specifies the memory 'footprint' of
          ** data to be transferred. The lext specifies
          ** the offset from the base address to begin
          ** viewing the data.  The rext specifies the
          ** length from the base address to use.
          */
          dgsp_d.lext = 0;
          dgsp_d.rext = 4;
          /* atom size of 0 lets LAPI choose the packet size */
          dgsp_d.atom_size = 0;
    
          /*
          ** set up the copy instruction
          */
          copy_p = (lapi_dgsm_copy_t *)(dgsp_d.code);
          copy_p->opcode = LAPI_DGSM_COPY;
    
          /* copy 4 bytes at a time */
          copy_p->bytes = (long) 4;
    
          /* start at offset 0 */
          copy_p->offset = (long) 0;
    
          /* set code pointer to address of iterate instruction */
          code_less_iterate_size =  dgsp_d.code_size - LAPI_DGSM_ITERATE_SIZE;
          code_ptr = ((int *)(code))+code_less_iterate_size;
    
          /*
          ** Set up iterate instruction
          */
          iter_p = (lapi_dgsm_iterate_t *) code_ptr;
          iter_p->opcode = LAPI_DGSM_ITERATE;
          iter_p->iter_loc = (-code_less_iterate_size);
    
          /* Set up and do DGSP registration */
          reg_util.Util_type = LAPI_REGISTER_DGSP;
          reg_util.idgsp = &dgsp_d;
          LAPI_Util(hndl, (lapi_util_t *)&reg_util);
    
          /* 
          ** LAPI returns a usable DGSP handle in 
          ** reg_util.dgsp_handle
          ** Use this handle for subsequent reserve/unreserve
          ** and Xfer calls.  On the receive side, this
          ** handle can be returned by the header handler using the 
          ** return_info_t mechanism.  The DGSP will then be used for
          ** scattering data.
          */
          
    }
  2. To reserve a DGSP handle:
    {
    	
          reg_util.dgsp_handle = dgsp_handle;
    
          /* 
          ** dgsp_handle has already been created and
          ** registered as in the above example
          */
    
          reg_util.Util_type = LAPI_RESERVE_DGSP;
          LAPI_Util(hndl, (lapi_util_t *)&reg_util);
    
          /*
          ** LAPI's internal reference count to dgsp_handle
          ** will be incremented.  DGSP will
          ** remain available until an unreserve is
          ** done for each reserve, plus one more for
          ** the original registration.
          */
    
    }
  3. To unreserve a DGSP handle:
    {
    	
          reg_util.dgsp_handle = dgsp_handle;
    
          /* 
          ** dgsp_handle has already created and
          ** registered as in the above example, and
          ** this thread no longer needs it.
          */
    
          reg_util.Util_type = LAPI_UNRESERVE_DGSP;
          LAPI_Util(hndl, (lapi_util_t *)&reg_util);
    
          /*
          ** An unreserve is required for each reserve,
          ** plus one more for the original registration.
          */
    
    }

Location

/usr/lib/liblapi_r.a

Related Information

Subroutines: LAPI_Init, LAPI_Xfer