openpmix-src 0.1.0-rc.1

Vendored build of OpenPMIx, developed for use by the Lamellar runtime.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
 *                         University Research and Technology
 *                         Corporation.  All rights reserved.
 * Copyright (c) 2004-2005 The University of Tennessee and The University
 *                         of Tennessee Research Foundation.  All rights
 *                         reserved.
 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
 *                         University of Stuttgart.  All rights reserved.
 * Copyright (c) 2004-2005 The Regents of the University of California.
 *                         All rights reserved.
 * Copyright (c) 2012      Los Alamos National Security, Inc. All rights reserved.
 * Copyright (c) 2013-2020 Intel, Inc.  All rights reserved.
 * Copyright (c) 2015      Research Organization for Information Science
 *                         and Technology (RIST). All rights reserved.
 * Copyright (c) 2016      Mellanox Technologies, Inc.
 *                         All rights reserved.
 * Copyright (c) 2021-2022 Nanook Consulting.  All rights reserved.
 * $COPYRIGHT$
 *
 * Additional copyrights may follow
 *
 * $HEADER$
 */
/**
 * @file
 *
 * Data packing subsystem.
 */

#ifndef PMIX_BFROP_H_
#define PMIX_BFROP_H_

#include "src/include/pmix_config.h"
#include "pmix_common.h"
#include "src/include/pmix_types.h"

#include "src/mca/mca.h"

#include "bfrops_types.h"

BEGIN_C_DECLS

/* The overall objective of this framework is to provide seamless
 * cross-version support for communications by allowing a process
 * to communicate with a peer:
 *
 * (a) using a different version of the buffer operations. We are
 *     allowing changes in the structure compositions and/or data
 *     type definitions between versions. This specifically affects
 *     our ability to pack/unpack across versions.
 *
 * (b) using a different buffer type (described vs non-described).
 *     This resolves conflicts when one side was compiled with a
 *     debug option, while the other side has been "optimized".
 *
 * This is a mult-select framework - i.e., multiple components
 * are selected and "active" at the same time. The intent is
 * to have one component for each data type variation, with the
 * expectation that the community will do its best not to revise
 * existing data type definitions. Thus, new variations should be
 * rare, and only a few components will exist.
 *
 * The framework itself reflects the fact that any given peer
 * will utilize only one variation of the data type definitions.
 * Thus, once a peer is identified, it will pass its version string
 * to this framework's "assign_module" function, which will then
 * pass it to each component until one returns a module capable of
 * processing the given version. This module is then "attached" to
 * the pmix_peer_t object so it can be used for all subsequent
 * communication to/from that peer.
 *
 * Buffer type is included in the buffer metadata. Unfortunately,
 * the metadata is not communicated at each exchange. Thus, the
 * peers will indicate during the connection handshake the type
 * of buffer they will use for all subsequent communications. The
 * peer must then utilize that same buffer type for all messages
 * sent to that remote proc, so we provide new macros for creating
 * and constructing buffers that ensures the correct buffer type
 * is marked.
 *
 * Accordingly, there are two levels of APIs defined for this
 * framework:
 *
 * (a) component level - these allow for init/finalize of the
 *     component, and assignment of a module to a given peer
 *     based on the version that peer is using
 *
 * (b) module level - implement pack/unpack/copy/recv/etc. of
 *     the various datatypes. Note that the module only needs
 *     to provide those functions that differ from the base
 *     functions - they don't need to duplicate all that code!
 */

/* The following functions are exposed to the user - they
 * therefore are implemented in the bfrops/base functions
 * as wrappers to the real functions.
 *
 * NOTE: THESE FUNCTIONS ARE NOT TO BE USED INTERNALLY -
 * USE THE MACROS INSTEAD
 */
bool pmix_value_cmp(pmix_value_t *p, pmix_value_t *p1);

/****    MODULE INTERFACE DEFINITION    ****/

/* initialize the module - the module is expected
 * to register its datatype functions at this time */
typedef pmix_status_t (*pmix_bfrop_init_fn_t)(void);

/* finalize the module */
typedef void (*pmix_bfrop_finalize_fn_t)(void);

/**
 * Pack one or more values into a buffer.
 *
 * The pack function packs one or more values of a specified type into
 * the specified buffer.  The buffer must have already been
 * initialized via an PMIX_NEW or PMIX_CONSTRUCT call - otherwise, the
 * pack_value function will return an error. Providing an unsupported
 * type flag will likewise be reported as an error.
 *
 * Note that any data to be packed that is not hard type cast (i.e.,
 * not type cast to a specific size) may lose precision when unpacked
 * by a non-homogeneous recipient.  The BFROP will do its best to deal
 * with heterogeneity issues between the packer and unpacker in such
 * cases. Sending a number larger than can be handled by the recipient
 * will return an error code (generated by the BFROP upon unpacking) -
 * the BFROP cannot detect such errors during packing.
 *
 * @param *buffer A pointer to the buffer into which the value is to
 * be packed.
 *
 * @param *src A void* pointer to the data that is to be packed. This
 * is interpreted as a pointer to an array of that data type containing
 * length num_values. Note that strings are of data type char*, and so
 * they are to be passed as (char **) - i.e., the caller must
 * pass the address of the pointer to the string as the void*. This
 * allows the BFROP to use a single interface function, but still allow
 * the caller to pass multiple strings in a single call.
 *
 * @param num_values An int32_t indicating the number of values that are
 * to be packed, beginning at the location pointed to by src. A string
 * value is counted as a single value regardless of length. The values
 * must be contiguous in memory. Arrays of pointers (e.g., string
 * arrays) should be contiguous, although (obviously) the data pointed
 * to need not be contiguous across array entries.
 *
 * @param type The type of the data to be packed - must be one of the
 * PMIX defined data types.
 *
 * @retval PMIX_SUCCESS The data was packed as requested.
 *
 * @retval PMIX_ERROR(s) An appropriate PMIX error code indicating the
 * problem encountered. This error code should be handled
 * appropriately.
 *
 * @code
 * pmix_buffer_t *buffer;
 * int32_t src;
 *
 * status_code = pmix_bfrop.pack(buffer, &src, 1, PMIX_INT32);
 * @endcode
 */
typedef pmix_status_t (*pmix_bfrop_pack_fn_t)(pmix_buffer_t *buffer, const void *src,
                                              int32_t num_values, pmix_data_type_t type);

/**
 * Unpack values from a buffer.
 *
 * The unpack function unpacks the next value (or values) of a
 * specified type from the specified buffer.
 *
 * The buffer must have already been initialized via an PMIX_NEW or
 * PMIX_CONSTRUCT call (and assumedly filled with some data) -
 * otherwise, the unpack_value function will return an
 * error. Providing an unsupported type flag will likewise be reported
 * as an error, as will specifying a data type that DOES NOT match the
 * type of the next item in the buffer. An attempt to read beyond the
 * end of the stored data held in the buffer will also return an
 * error.
 *
 * NOTE: it is possible for the buffer to be corrupted and that
 * the BFROP will *think* there is a proper variable type at the
 * beginning of an unpack region - but that the value is bogus (e.g., just
 * a byte field in a string array that so happens to have a value that
 * matches the specified data type flag). Therefore, the data type error check
 * is NOT completely safe. This is true for ALL unpack functions.
 *
 * Warning: The caller is responsible for providing adequate memory
 * storage for the requested data. As noted below, the user
 * must provide a parameter indicating the maximum number of values that
 * can be unpacked into the allocated memory. If more values exist in the
 * buffer than can fit into the memory storage, then the bfrop will unpack
 * what it can fit into that location and return an error code indicating
 * that the buffer was only partially unpacked.
 *
 * Note that any data that was not hard type cast (i.e., not type cast
 * to a specific size) when packed may lose precision when unpacked by
 * a non-homogeneous recipient.  The BFROP will do its best to deal with
 * heterogeneity issues between the packer and unpacker in such
 * cases. Sending a number larger than can be handled by the recipient
 * will return an error code generated by the BFROP upon unpacking - the
 * BFROP cannot detect such errors during packing.
 *
 * @param *buffer A pointer to the buffer from which the value will be
 * extracted.
 *
 * @param *dest A void* pointer to the memory location into which the
 * data is to be stored. Note that these values will be stored
 * contiguously in memory. For strings, this pointer must be to (char
 * **) to provide a means of supporting multiple string
 * operations. The BFROP unpack function will allocate memory for each
 * string in the array - the caller must only provide adequate memory
 * for the array of pointers.
 *
 * @param type The type of the data to be unpacked - must be one of
 * the BFROP defined data types.
 *
 * @retval *max_num_values The number of values actually unpacked. In
 * most cases, this should match the maximum number provided in the
 * parameters - but in no case will it exceed the value of this
 * parameter.  Note that if you unpack fewer values than are actually
 * available, the buffer will be in an unpackable state - the bfrop will
 * return an error code to warn of this condition.
 *
 * @note The unpack function will return the actual number of values
 * unpacked in this location.
 *
 * @retval PMIX_SUCCESS The next item in the buffer was successfully
 * unpacked.
 *
 * @retval PMIX_ERROR(s) The unpack function returns an error code
 * under one of several conditions: (a) the number of values in the
 * item exceeds the max num provided by the caller; (b) the type of
 * the next item in the buffer does not match the type specified by
 * the caller; or (c) the unpack failed due to either an error in the
 * buffer or an attempt to read past the end of the buffer.
 *
 * @code
 * pmix_buffer_t *buffer;
 * int32_t dest;
 * char **string_array;
 * int32_t num_values;
 *
 * num_values = 1;
 * status_code = pmix_bfrop.unpack(buffer, (void*)&dest, &num_values, PMIX_INT32);
 *
 * num_values = 5;
 * string_array = malloc(num_values*sizeof(char *));
 * status_code = pmix_bfrop.unpack(buffer, (void*)(string_array), &num_values, PMIX_STRING);
 *
 * @endcode
 */
typedef pmix_status_t (*pmix_bfrop_unpack_fn_t)(pmix_buffer_t *buffer, void *dest,
                                                int32_t *max_num_values, pmix_data_type_t type);
/**
 * Copy a payload from one buffer to another
 * This function will append a copy of the payload in one buffer into
 * another buffer. If the destination buffer is NOT empty, then the
 * type of the two buffers MUST match or else an
 * error will be returned. If the destination buffer IS empty, then
 * its type will be set to that of the source buffer.
 * NOTE: This is NOT a destructive procedure - the
 * source buffer's payload will remain intact, as will any pre-existing
 * payload in the destination's buffer.
 */
typedef pmix_status_t (*pmix_bfrop_copy_payload_fn_t)(pmix_buffer_t *dest, pmix_buffer_t *src);

/**
 * Copy a data value from one location to another.
 *
 * Since registered data types can be complex structures, the system
 * needs some way to know how to copy the data from one location to
 * another (e.g., for storage in the registry). This function, which
 * can call other copy functions to build up complex data types, defines
 * the method for making a copy of the specified data type.
 *
 * @param **dest The address of a pointer into which the
 * address of the resulting data is to be stored.
 *
 * @param *src A pointer to the memory location from which the
 * data is to be copied.
 *
 * @param type The type of the data to be copied - must be one of
 * the BFROP defined data types.
 *
 * @retval PMIX_SUCCESS The value was successfully copied.
 *
 * @retval PMIX_ERROR(s) An appropriate error code.
 *
 */
typedef pmix_status_t (*pmix_bfrop_copy_fn_t)(void **dest, void *src, pmix_data_type_t type);

/**
 * Print a data value.
 *
 * Since registered data types can be complex structures, the system
 * needs some way to know how to print them (i.e., convert them to a string
 * representation). Provided for debug purposes.
 *
 * @retval PMIX_SUCCESS The value was successfully printed.
 *
 * @retval PMIX_ERROR(s) An appropriate error code.
 */
typedef pmix_status_t (*pmix_bfrop_print_fn_t)(char **output, char *prefix, void *src,
                                               pmix_data_type_t type);

/**
 * Transfer a value from one pmix_value_t to another. Ordinarily,
 * this would be executed as a base function. However, it is
 * possible that future versions may add new data types, and
 * thus the xfer function may differ
 *
 * @retval PMIX_SUCCESS The value was successfully transferred
 *
 * @retval PMIX_ERROR(s) An appropriate error code
 */
typedef pmix_status_t (*pmix_bfrop_value_xfer_fn_t)(pmix_value_t *dest, const pmix_value_t *src);

/**
 * Load data into a pmix_value_t object. Again, this is provided
 * as a component function to support different data types
 */
typedef void (*pmix_bfrop_value_load_fn_t)(pmix_value_t *v, const void *data,
                                           pmix_data_type_t type);

/**
 * Unload data from a pmix_value_t object
 *
 * @retval PMIX_SUCCESS The value was successfully unloaded
 *
 * @retval PMIX_ERROR(s) An appropriate error code
 */
typedef pmix_status_t (*pmix_bfrop_value_unload_fn_t)(pmix_value_t *kv, void **data, size_t *sz);

/**
 * Compare two pmix_value_t structs
 */
typedef pmix_value_cmp_t (*pmix_bfrop_value_cmp_fn_t)(pmix_value_t *p1, pmix_value_t *p2);

/* return the string name of a provided data type */
typedef const char *(*pmix_bfrop_data_type_string_fn_t)(pmix_data_type_t type);

/**
 * Base structure for a BFROP module
 */
typedef struct {
    char *version;
    pmix_bfrop_init_fn_t init;
    pmix_bfrop_finalize_fn_t finalize;
    pmix_bfrop_pack_fn_t pack;
    pmix_bfrop_unpack_fn_t unpack;
    pmix_bfrop_copy_fn_t copy;
    pmix_bfrop_print_fn_t print;
    pmix_bfrop_copy_payload_fn_t copy_payload;
    pmix_bfrop_value_xfer_fn_t value_xfer;
    pmix_bfrop_value_load_fn_t value_load;
    pmix_bfrop_value_unload_fn_t value_unload;
    pmix_bfrop_value_cmp_fn_t value_cmp;
    pmix_bfrop_data_type_string_fn_t data_type_string;
} pmix_bfrops_module_t;

/* get a list of available versions - caller must free results
 * when done */
PMIX_EXPORT char *pmix_bfrops_base_get_available_modules(void);

/* Select a bfrops module for a given version */
PMIX_EXPORT pmix_bfrops_module_t *pmix_bfrops_base_assign_module(const char *version);

/* provide a backdoor to access the framework debug output */
PMIX_EXPORT extern int pmix_bfrops_base_output;

/* MACROS FOR EXECUTING BFROPS FUNCTIONS */
#define PMIX_BFROPS_ASSIGN_TYPE(p, b) (b)->type = (p)->nptr->compat.type

#define PMIX_BFROPS_PACK(r, p, b, s, n, t)                                                   \
    do {                                                                                     \
        pmix_output_verbose(2, pmix_bfrops_base_output, "[%s:%d] PACK version %s type %s",   \
                            __FILE__, __LINE__, (p)->nptr->compat.bfrops->version,           \
                            PMIx_Data_type_string(t));                                      \
        if (PMIX_BFROP_BUFFER_UNDEF == (b)->type) {                                          \
            (b)->type = (p)->nptr->compat.type;                                              \
            (r) = (p)->nptr->compat.bfrops->pack(b, s, n, t);                                \
        } else if ((b)->type == (p)->nptr->compat.type) {                                    \
            (r) = (p)->nptr->compat.bfrops->pack(b, s, n, t);                                \
        } else {                                                                             \
            (r) = PMIX_ERR_PACK_MISMATCH;                                                    \
        }                                                                                    \
    } while (0)

#define PMIX_BFROPS_UNPACK(r, p, b, d, m, t)                                                   \
    do {                                                                                       \
        pmix_output_verbose(2, pmix_bfrops_base_output, "[%s:%d] UNPACK version %s type %s",   \
                            __FILE__, __LINE__, (p)->nptr->compat.bfrops->version,             \
                            PMIx_Data_type_string(t));                                         \
        if ((b)->type == (p)->nptr->compat.type) {                                             \
            (r) = (p)->nptr->compat.bfrops->unpack(b, d, m, t);                                \
        } else {                                                                               \
            (r) = PMIX_ERR_UNPACK_FAILURE;                                                     \
        }                                                                                      \
    } while (0)

#define PMIX_BFROPS_COPY(r, p, d, s, t) (r) = (p)->nptr->compat.bfrops->copy(d, s, t)

#define PMIX_BFROPS_PRINT(r, p, o, pr, s, t) (r) = (p)->nptr->compat.bfrops->print(o, pr, s, t)

#define PMIX_BFROPS_COPY_PAYLOAD(r, p, d, s)                    \
    do {                                                        \
        if (PMIX_BFROP_BUFFER_UNDEF == (d)->type) {             \
            (d)->type = (p)->nptr->compat.type;                 \
            (r) = (p)->nptr->compat.bfrops->copy_payload(d, s); \
        } else if ((d)->type == (p)->nptr->compat.type) {       \
            (r) = (p)->nptr->compat.bfrops->copy_payload(d, s); \
        } else {                                                \
            (r) = PMIX_ERR_PACK_MISMATCH;                       \
        }                                                       \
    } while (0)

#define PMIX_BFROPS_VALUE_XFER(r, p, d, s) (r) = (p)->nptr->compat.bfrops->value_xfer(d, s)

#define PMIX_BFROPS_VALUE_LOAD(p, v, d, t) (p)->nptr->compat.bfrops->value_load(v, d, t)

#define PMIX_BFROPS_VALUE_UNLOAD(r, p, k, d, s) \
    (r) = (p)->nptr->compat.bfrops->value_unload(k, , d, s)

#define PMIX_BFROPS_VALUE_CMP(r, p, q, s) (r) = (p)->nptr->compat.bfrops->value_cmp(q, s)

#define PMIX_BFROPS_REGISTER(r, p, n, t, pk, u, c, pr) \
    (r) = (p)->nptr->compat.bfrops->register_type(n, t, pk, u, c, pr)

#define PMIX_BFROPS_PRINT_TYPE(c, p, t) (c) = (p)->nptr->compat.bfrops->data_type_string(t)

/****    COMPONENT STRUCTURE DEFINITION    ****/

/* define a component-level API for getting a module */
typedef pmix_bfrops_module_t *(*pmix_bfrop_base_component_assign_module_fn_t)(void);

/*
 * the standard component data structure
 */
struct pmix_bfrops_base_component_t {
    pmix_mca_base_component_t base;
    int priority;
    pmix_pointer_array_t types;
    pmix_bfrop_base_component_assign_module_fn_t assign_module;
};
typedef struct pmix_bfrops_base_component_t pmix_bfrops_base_component_t;

/*
 * Macro for use in components that are of type bfrops
 */
#define PMIX_BFROPS_BASE_VERSION_1_0_0 PMIX_MCA_BASE_VERSION_1_0_0("bfrops", 1, 0, 0)

END_C_DECLS

#endif /* PMIX_BFROP_H */