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.
Availability Library (liblapi_r.a)
#include <lapi.h>
int LAPI_Util(hndl, util_cmd)
lapi_handle_t hndl;
lapi_util_t *util_cmd;
include 'lapif.h'
LAPI_UTIL(hndl, util_cmd, ierror)
INTEGER hndl
TYPE (LAPI_UTIL_T) :: util_cmd
INTEGER ierror
Type of call: Data gather/scatter program (DGSP), UDP port information, and lock sharing utilities
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;
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 |
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_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_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_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.
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_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_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_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_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_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.
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.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.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. 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.Condition functions
LAPI_GET_THREAD_FUNC includes the following condition functions: condition wait, condition timed wait, condition signal, initialize condition, and destroy condition.
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.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.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.int (*lapi_cond_init_t)(lapi_handle_t hndl, lapi_cond_t *cond);
This
function initializes a condition variable.int (*lapi_cond_destroy_t)(lapi_handle_t hndl, lapi_cond_t *cond);
This
function destroys a condition variable.Parameters
Return Values
C Examples
{
/*
** 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 *)®_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.
*/
}
{
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 *)®_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.
*/
}
{
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 *)®_util);
/*
** An unreserve is required for each reserve,
** plus one more for the original registration.
*/
}
Location
Related Information
Subroutines: LAPI_Init, LAPI_Xfer