Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:47:24

0001 /* -*- Mode: C; c-basic-offset:4 ; -*- */
0002 /*
0003  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
0004  *                         University Research and Technology
0005  *                         Corporation.  All rights reserved.
0006  * Copyright (c) 2004-2005 The University of Tennessee and The University
0007  *                         of Tennessee Research Foundation.  All rights
0008  *                         reserved.
0009  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
0010  *                         University of Stuttgart.  All rights reserved.
0011  * Copyright (c) 2004-2005 The Regents of the University of California.
0012  *                         All rights reserved.
0013  * Copyright (c) 2012      Los Alamos National Security, Inc. All rights reserved.
0014  * Copyright (c) 2013-2020 Intel, Inc.  All rights reserved.
0015  * Copyright (c) 2015      Research Organization for Information Science
0016  *                         and Technology (RIST). All rights reserved.
0017  * Copyright (c) 2016      Mellanox Technologies, Inc.
0018  *                         All rights reserved.
0019  * Copyright (c) 2021-2022 Nanook Consulting.  All rights reserved.
0020  * $COPYRIGHT$
0021  *
0022  * Additional copyrights may follow
0023  *
0024  * $HEADER$
0025  */
0026 /**
0027  * @file
0028  *
0029  * Data packing subsystem.
0030  */
0031 
0032 #ifndef PMIX_BFROP_H_
0033 #define PMIX_BFROP_H_
0034 
0035 #include "src/include/pmix_config.h"
0036 #include "pmix_common.h"
0037 #include "src/include/pmix_types.h"
0038 
0039 #include "src/mca/mca.h"
0040 
0041 #include "bfrops_types.h"
0042 
0043 BEGIN_C_DECLS
0044 
0045 /* The overall objective of this framework is to provide seamless
0046  * cross-version support for communications by allowing a process
0047  * to communicate with a peer:
0048  *
0049  * (a) using a different version of the buffer operations. We are
0050  *     allowing changes in the structure compositions and/or data
0051  *     type definitions between versions. This specifically affects
0052  *     our ability to pack/unpack across versions.
0053  *
0054  * (b) using a different buffer type (described vs non-described).
0055  *     This resolves conflicts when one side was compiled with a
0056  *     debug option, while the other side has been "optimized".
0057  *
0058  * This is a mult-select framework - i.e., multiple components
0059  * are selected and "active" at the same time. The intent is
0060  * to have one component for each data type variation, with the
0061  * expectation that the community will do its best not to revise
0062  * existing data type definitions. Thus, new variations should be
0063  * rare, and only a few components will exist.
0064  *
0065  * The framework itself reflects the fact that any given peer
0066  * will utilize only one variation of the data type definitions.
0067  * Thus, once a peer is identified, it will pass its version string
0068  * to this framework's "assign_module" function, which will then
0069  * pass it to each component until one returns a module capable of
0070  * processing the given version. This module is then "attached" to
0071  * the pmix_peer_t object so it can be used for all subsequent
0072  * communication to/from that peer.
0073  *
0074  * Buffer type is included in the buffer metadata. Unfortunately,
0075  * the metadata is not communicated at each exchange. Thus, the
0076  * peers will indicate during the connection handshake the type
0077  * of buffer they will use for all subsequent communications. The
0078  * peer must then utilize that same buffer type for all messages
0079  * sent to that remote proc, so we provide new macros for creating
0080  * and constructing buffers that ensures the correct buffer type
0081  * is marked.
0082  *
0083  * Accordingly, there are two levels of APIs defined for this
0084  * framework:
0085  *
0086  * (a) component level - these allow for init/finalize of the
0087  *     component, and assignment of a module to a given peer
0088  *     based on the version that peer is using
0089  *
0090  * (b) module level - implement pack/unpack/copy/recv/etc. of
0091  *     the various datatypes. Note that the module only needs
0092  *     to provide those functions that differ from the base
0093  *     functions - they don't need to duplicate all that code!
0094  */
0095 
0096 /* The following functions are exposed to the user - they
0097  * therefore are implemented in the bfrops/base functions
0098  * as wrappers to the real functions.
0099  *
0100  * NOTE: THESE FUNCTIONS ARE NOT TO BE USED INTERNALLY -
0101  * USE THE MACROS INSTEAD
0102  */
0103 bool pmix_value_cmp(pmix_value_t *p, pmix_value_t *p1);
0104 
0105 /****    MODULE INTERFACE DEFINITION    ****/
0106 
0107 /* initialize the module - the module is expected
0108  * to register its datatype functions at this time */
0109 typedef pmix_status_t (*pmix_bfrop_init_fn_t)(void);
0110 
0111 /* finalize the module */
0112 typedef void (*pmix_bfrop_finalize_fn_t)(void);
0113 
0114 /**
0115  * Pack one or more values into a buffer.
0116  *
0117  * The pack function packs one or more values of a specified type into
0118  * the specified buffer.  The buffer must have already been
0119  * initialized via an PMIX_NEW or PMIX_CONSTRUCT call - otherwise, the
0120  * pack_value function will return an error. Providing an unsupported
0121  * type flag will likewise be reported as an error.
0122  *
0123  * Note that any data to be packed that is not hard type cast (i.e.,
0124  * not type cast to a specific size) may lose precision when unpacked
0125  * by a non-homogeneous recipient.  The BFROP will do its best to deal
0126  * with heterogeneity issues between the packer and unpacker in such
0127  * cases. Sending a number larger than can be handled by the recipient
0128  * will return an error code (generated by the BFROP upon unpacking) -
0129  * the BFROP cannot detect such errors during packing.
0130  *
0131  * @param *buffer A pointer to the buffer into which the value is to
0132  * be packed.
0133  *
0134  * @param *src A void* pointer to the data that is to be packed. This
0135  * is interpreted as a pointer to an array of that data type containing
0136  * length num_values. Note that strings are of data type char*, and so
0137  * they are to be passed as (char **) - i.e., the caller must
0138  * pass the address of the pointer to the string as the void*. This
0139  * allows the BFROP to use a single interface function, but still allow
0140  * the caller to pass multiple strings in a single call.
0141  *
0142  * @param num_values An int32_t indicating the number of values that are
0143  * to be packed, beginning at the location pointed to by src. A string
0144  * value is counted as a single value regardless of length. The values
0145  * must be contiguous in memory. Arrays of pointers (e.g., string
0146  * arrays) should be contiguous, although (obviously) the data pointed
0147  * to need not be contiguous across array entries.
0148  *
0149  * @param type The type of the data to be packed - must be one of the
0150  * PMIX defined data types.
0151  *
0152  * @retval PMIX_SUCCESS The data was packed as requested.
0153  *
0154  * @retval PMIX_ERROR(s) An appropriate PMIX error code indicating the
0155  * problem encountered. This error code should be handled
0156  * appropriately.
0157  *
0158  * @code
0159  * pmix_buffer_t *buffer;
0160  * int32_t src;
0161  *
0162  * status_code = pmix_bfrop.pack(buffer, &src, 1, PMIX_INT32);
0163  * @endcode
0164  */
0165 typedef pmix_status_t (*pmix_bfrop_pack_fn_t)(pmix_buffer_t *buffer, const void *src,
0166                                               int32_t num_values, pmix_data_type_t type);
0167 
0168 /**
0169  * Unpack values from a buffer.
0170  *
0171  * The unpack function unpacks the next value (or values) of a
0172  * specified type from the specified buffer.
0173  *
0174  * The buffer must have already been initialized via an PMIX_NEW or
0175  * PMIX_CONSTRUCT call (and assumedly filled with some data) -
0176  * otherwise, the unpack_value function will return an
0177  * error. Providing an unsupported type flag will likewise be reported
0178  * as an error, as will specifying a data type that DOES NOT match the
0179  * type of the next item in the buffer. An attempt to read beyond the
0180  * end of the stored data held in the buffer will also return an
0181  * error.
0182  *
0183  * NOTE: it is possible for the buffer to be corrupted and that
0184  * the BFROP will *think* there is a proper variable type at the
0185  * beginning of an unpack region - but that the value is bogus (e.g., just
0186  * a byte field in a string array that so happens to have a value that
0187  * matches the specified data type flag). Therefore, the data type error check
0188  * is NOT completely safe. This is true for ALL unpack functions.
0189  *
0190  * Warning: The caller is responsible for providing adequate memory
0191  * storage for the requested data. As noted below, the user
0192  * must provide a parameter indicating the maximum number of values that
0193  * can be unpacked into the allocated memory. If more values exist in the
0194  * buffer than can fit into the memory storage, then the bfrop will unpack
0195  * what it can fit into that location and return an error code indicating
0196  * that the buffer was only partially unpacked.
0197  *
0198  * Note that any data that was not hard type cast (i.e., not type cast
0199  * to a specific size) when packed may lose precision when unpacked by
0200  * a non-homogeneous recipient.  The BFROP will do its best to deal with
0201  * heterogeneity issues between the packer and unpacker in such
0202  * cases. Sending a number larger than can be handled by the recipient
0203  * will return an error code generated by the BFROP upon unpacking - the
0204  * BFROP cannot detect such errors during packing.
0205  *
0206  * @param *buffer A pointer to the buffer from which the value will be
0207  * extracted.
0208  *
0209  * @param *dest A void* pointer to the memory location into which the
0210  * data is to be stored. Note that these values will be stored
0211  * contiguously in memory. For strings, this pointer must be to (char
0212  * **) to provide a means of supporting multiple string
0213  * operations. The BFROP unpack function will allocate memory for each
0214  * string in the array - the caller must only provide adequate memory
0215  * for the array of pointers.
0216  *
0217  * @param type The type of the data to be unpacked - must be one of
0218  * the BFROP defined data types.
0219  *
0220  * @retval *max_num_values The number of values actually unpacked. In
0221  * most cases, this should match the maximum number provided in the
0222  * parameters - but in no case will it exceed the value of this
0223  * parameter.  Note that if you unpack fewer values than are actually
0224  * available, the buffer will be in an unpackable state - the bfrop will
0225  * return an error code to warn of this condition.
0226  *
0227  * @note The unpack function will return the actual number of values
0228  * unpacked in this location.
0229  *
0230  * @retval PMIX_SUCCESS The next item in the buffer was successfully
0231  * unpacked.
0232  *
0233  * @retval PMIX_ERROR(s) The unpack function returns an error code
0234  * under one of several conditions: (a) the number of values in the
0235  * item exceeds the max num provided by the caller; (b) the type of
0236  * the next item in the buffer does not match the type specified by
0237  * the caller; or (c) the unpack failed due to either an error in the
0238  * buffer or an attempt to read past the end of the buffer.
0239  *
0240  * @code
0241  * pmix_buffer_t *buffer;
0242  * int32_t dest;
0243  * char **string_array;
0244  * int32_t num_values;
0245  *
0246  * num_values = 1;
0247  * status_code = pmix_bfrop.unpack(buffer, (void*)&dest, &num_values, PMIX_INT32);
0248  *
0249  * num_values = 5;
0250  * string_array = malloc(num_values*sizeof(char *));
0251  * status_code = pmix_bfrop.unpack(buffer, (void*)(string_array), &num_values, PMIX_STRING);
0252  *
0253  * @endcode
0254  */
0255 typedef pmix_status_t (*pmix_bfrop_unpack_fn_t)(pmix_buffer_t *buffer, void *dest,
0256                                                 int32_t *max_num_values, pmix_data_type_t type);
0257 /**
0258  * Copy a payload from one buffer to another
0259  * This function will append a copy of the payload in one buffer into
0260  * another buffer. If the destination buffer is NOT empty, then the
0261  * type of the two buffers MUST match or else an
0262  * error will be returned. If the destination buffer IS empty, then
0263  * its type will be set to that of the source buffer.
0264  * NOTE: This is NOT a destructive procedure - the
0265  * source buffer's payload will remain intact, as will any pre-existing
0266  * payload in the destination's buffer.
0267  */
0268 typedef pmix_status_t (*pmix_bfrop_copy_payload_fn_t)(pmix_buffer_t *dest, pmix_buffer_t *src);
0269 
0270 /**
0271  * Copy a data value from one location to another.
0272  *
0273  * Since registered data types can be complex structures, the system
0274  * needs some way to know how to copy the data from one location to
0275  * another (e.g., for storage in the registry). This function, which
0276  * can call other copy functions to build up complex data types, defines
0277  * the method for making a copy of the specified data type.
0278  *
0279  * @param **dest The address of a pointer into which the
0280  * address of the resulting data is to be stored.
0281  *
0282  * @param *src A pointer to the memory location from which the
0283  * data is to be copied.
0284  *
0285  * @param type The type of the data to be copied - must be one of
0286  * the BFROP defined data types.
0287  *
0288  * @retval PMIX_SUCCESS The value was successfully copied.
0289  *
0290  * @retval PMIX_ERROR(s) An appropriate error code.
0291  *
0292  */
0293 typedef pmix_status_t (*pmix_bfrop_copy_fn_t)(void **dest, void *src, pmix_data_type_t type);
0294 
0295 /**
0296  * Print a data value.
0297  *
0298  * Since registered data types can be complex structures, the system
0299  * needs some way to know how to print them (i.e., convert them to a string
0300  * representation). Provided for debug purposes.
0301  *
0302  * @retval PMIX_SUCCESS The value was successfully printed.
0303  *
0304  * @retval PMIX_ERROR(s) An appropriate error code.
0305  */
0306 typedef pmix_status_t (*pmix_bfrop_print_fn_t)(char **output, char *prefix, void *src,
0307                                                pmix_data_type_t type);
0308 
0309 /**
0310  * Transfer a value from one pmix_value_t to another. Ordinarily,
0311  * this would be executed as a base function. However, it is
0312  * possible that future versions may add new data types, and
0313  * thus the xfer function may differ
0314  *
0315  * @retval PMIX_SUCCESS The value was successfully transferred
0316  *
0317  * @retval PMIX_ERROR(s) An appropriate error code
0318  */
0319 typedef pmix_status_t (*pmix_bfrop_value_xfer_fn_t)(pmix_value_t *dest, const pmix_value_t *src);
0320 
0321 /**
0322  * Load data into a pmix_value_t object. Again, this is provided
0323  * as a component function to support different data types
0324  */
0325 typedef void (*pmix_bfrop_value_load_fn_t)(pmix_value_t *v, const void *data,
0326                                            pmix_data_type_t type);
0327 
0328 /**
0329  * Unload data from a pmix_value_t object
0330  *
0331  * @retval PMIX_SUCCESS The value was successfully unloaded
0332  *
0333  * @retval PMIX_ERROR(s) An appropriate error code
0334  */
0335 typedef pmix_status_t (*pmix_bfrop_value_unload_fn_t)(pmix_value_t *kv, void **data, size_t *sz);
0336 
0337 /**
0338  * Compare two pmix_value_t structs
0339  */
0340 typedef pmix_value_cmp_t (*pmix_bfrop_value_cmp_fn_t)(pmix_value_t *p1, pmix_value_t *p2);
0341 
0342 /* return the string name of a provided data type */
0343 typedef const char *(*pmix_bfrop_data_type_string_fn_t)(pmix_data_type_t type);
0344 
0345 /**
0346  * Base structure for a BFROP module
0347  */
0348 typedef struct {
0349     char *version;
0350     pmix_bfrop_init_fn_t init;
0351     pmix_bfrop_finalize_fn_t finalize;
0352     pmix_bfrop_pack_fn_t pack;
0353     pmix_bfrop_unpack_fn_t unpack;
0354     pmix_bfrop_copy_fn_t copy;
0355     pmix_bfrop_print_fn_t print;
0356     pmix_bfrop_copy_payload_fn_t copy_payload;
0357     pmix_bfrop_value_xfer_fn_t value_xfer;
0358     pmix_bfrop_value_load_fn_t value_load;
0359     pmix_bfrop_value_unload_fn_t value_unload;
0360     pmix_bfrop_value_cmp_fn_t value_cmp;
0361     pmix_bfrop_data_type_string_fn_t data_type_string;
0362 } pmix_bfrops_module_t;
0363 
0364 /* get a list of available versions - caller must free results
0365  * when done */
0366 PMIX_EXPORT char *pmix_bfrops_base_get_available_modules(void);
0367 
0368 /* Select a bfrops module for a given version */
0369 PMIX_EXPORT pmix_bfrops_module_t *pmix_bfrops_base_assign_module(const char *version);
0370 
0371 /* provide a backdoor to access the framework debug output */
0372 PMIX_EXPORT extern int pmix_bfrops_base_output;
0373 
0374 /* MACROS FOR EXECUTING BFROPS FUNCTIONS */
0375 #define PMIX_BFROPS_ASSIGN_TYPE(p, b) (b)->type = (p)->nptr->compat.type
0376 
0377 #define PMIX_BFROPS_PACK(r, p, b, s, n, t)                                                   \
0378     do {                                                                                     \
0379         pmix_output_verbose(2, pmix_bfrops_base_output, "[%s:%d] PACK version %s type %s",   \
0380                             __FILE__, __LINE__, (p)->nptr->compat.bfrops->version,           \
0381                             PMIx_Data_type_string(t));                                      \
0382         if (PMIX_BFROP_BUFFER_UNDEF == (b)->type) {                                          \
0383             (b)->type = (p)->nptr->compat.type;                                              \
0384             (r) = (p)->nptr->compat.bfrops->pack(b, s, n, t);                                \
0385         } else if ((b)->type == (p)->nptr->compat.type) {                                    \
0386             (r) = (p)->nptr->compat.bfrops->pack(b, s, n, t);                                \
0387         } else {                                                                             \
0388             (r) = PMIX_ERR_PACK_MISMATCH;                                                    \
0389         }                                                                                    \
0390     } while (0)
0391 
0392 #define PMIX_BFROPS_UNPACK(r, p, b, d, m, t)                                                   \
0393     do {                                                                                       \
0394         pmix_output_verbose(2, pmix_bfrops_base_output, "[%s:%d] UNPACK version %s type %s",   \
0395                             __FILE__, __LINE__, (p)->nptr->compat.bfrops->version,             \
0396                             PMIx_Data_type_string(t));                                         \
0397         if ((b)->type == (p)->nptr->compat.type) {                                             \
0398             (r) = (p)->nptr->compat.bfrops->unpack(b, d, m, t);                                \
0399         } else {                                                                               \
0400             (r) = PMIX_ERR_UNPACK_FAILURE;                                                     \
0401         }                                                                                      \
0402     } while (0)
0403 
0404 #define PMIX_BFROPS_COPY(r, p, d, s, t) (r) = (p)->nptr->compat.bfrops->copy(d, s, t)
0405 
0406 #define PMIX_BFROPS_PRINT(r, p, o, pr, s, t) (r) = (p)->nptr->compat.bfrops->print(o, pr, s, t)
0407 
0408 #define PMIX_BFROPS_COPY_PAYLOAD(r, p, d, s)                    \
0409     do {                                                        \
0410         if (PMIX_BFROP_BUFFER_UNDEF == (d)->type) {             \
0411             (d)->type = (p)->nptr->compat.type;                 \
0412             (r) = (p)->nptr->compat.bfrops->copy_payload(d, s); \
0413         } else if ((d)->type == (p)->nptr->compat.type) {       \
0414             (r) = (p)->nptr->compat.bfrops->copy_payload(d, s); \
0415         } else {                                                \
0416             (r) = PMIX_ERR_PACK_MISMATCH;                       \
0417         }                                                       \
0418     } while (0)
0419 
0420 #define PMIX_BFROPS_VALUE_XFER(r, p, d, s) (r) = (p)->nptr->compat.bfrops->value_xfer(d, s)
0421 
0422 #define PMIX_BFROPS_VALUE_LOAD(p, v, d, t) (p)->nptr->compat.bfrops->value_load(v, d, t)
0423 
0424 #define PMIX_BFROPS_VALUE_UNLOAD(r, p, k, d, s) \
0425     (r) = (p)->nptr->compat.bfrops->value_unload(k, , d, s)
0426 
0427 #define PMIX_BFROPS_VALUE_CMP(r, p, q, s) (r) = (p)->nptr->compat.bfrops->value_cmp(q, s)
0428 
0429 #define PMIX_BFROPS_REGISTER(r, p, n, t, pk, u, c, pr) \
0430     (r) = (p)->nptr->compat.bfrops->register_type(n, t, pk, u, c, pr)
0431 
0432 #define PMIX_BFROPS_PRINT_TYPE(c, p, t) (c) = (p)->nptr->compat.bfrops->data_type_string(t)
0433 
0434 /****    COMPONENT STRUCTURE DEFINITION    ****/
0435 
0436 /* define a component-level API for getting a module */
0437 typedef pmix_bfrops_module_t *(*pmix_bfrop_base_component_assign_module_fn_t)(void);
0438 
0439 /*
0440  * the standard component data structure
0441  */
0442 struct pmix_bfrops_base_component_t {
0443     pmix_mca_base_component_t base;
0444     int priority;
0445     pmix_pointer_array_t types;
0446     pmix_bfrop_base_component_assign_module_fn_t assign_module;
0447 };
0448 typedef struct pmix_bfrops_base_component_t pmix_bfrops_base_component_t;
0449 
0450 /*
0451  * Macro for use in components that are of type bfrops
0452  */
0453 #define PMIX_BFROPS_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("bfrops", 1, 0, 0)
0454 
0455 END_C_DECLS
0456 
0457 #endif /* PMIX_BFROP_H */