1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4 * University Research and Technology
5 * Corporation. All rights reserved.
6 * Copyright (c) 2004-2005 The University of Tennessee and The University
7 * of Tennessee Research Foundation. All rights
8 * reserved.
9 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10 * University of Stuttgart. All rights reserved.
11 * Copyright (c) 2004-2005 The Regents of the University of California.
12 * All rights reserved.
13 * Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved.
14 * Copyright (c) 2014-2017 Intel, Inc. All rights reserved.
15 * Copyright (c) 2018 Triad National Security, LLC. All rights
16 * reserved.
17 * $COPYRIGHT$
18 *
19 * Additional copyrights may follow
20 *
21 * $HEADER$
22 */
23 /**
24 * @file
25 *
26 * Data packing subsystem.
27 */
28
29 #ifndef OPAL_DSS_H_
30 #define OPAL_DSS_H_
31
32 #include "opal_config.h"
33
34 #include "opal/dss/dss_types.h"
35
36 BEGIN_C_DECLS
37
38 /* Provide a macro for determining the bool value of an opal_value_t */
39 #define OPAL_CHECK_BOOL(v, p) \
40 do { \
41 if (OPAL_UNDEF == (v)->type) { \
42 (p) = true; \
43 } else { \
44 (p) = (v)->data.flag; \
45 } \
46 } while(0)
47
48 /* A non-API function for something that happens in a number
49 * of places throughout the code base - loading a value into
50 * an opal_value_t structure
51 */
52 OPAL_DECLSPEC int opal_value_load(opal_value_t *kv,
53 void *data, opal_data_type_t type);
54 OPAL_DECLSPEC int opal_value_unload(opal_value_t *kv,
55 void **data, opal_data_type_t type);
56 OPAL_DECLSPEC int opal_value_xfer(opal_value_t *dest,
57 opal_value_t *src);
58 /**
59 * Top-level interface function to pack one or more values into a
60 * buffer.
61 *
62 * The pack function packs one or more values of a specified type into
63 * the specified buffer. The buffer must have already been
64 * initialized via an OBJ_NEW or OBJ_CONSTRUCT call - otherwise, the
65 * pack_value function will return an error. Providing an unsupported
66 * type flag will likewise be reported as an error.
67 *
68 * Note that any data to be packed that is not hard type cast (i.e.,
69 * not type cast to a specific size) may lose precision when unpacked
70 * by a non-homogeneous recipient. The DSS will do its best to deal
71 * with heterogeneity issues between the packer and unpacker in such
72 * cases. Sending a number larger than can be handled by the recipient
73 * will return an error code (generated by the DSS upon unpacking) via
74 * the RML upon transmission - the DSS cannot detect such errors
75 * during packing.
76 *
77 * @param *buffer A pointer to the buffer into which the value is to
78 * be packed.
79 *
80 * @param *src A void* pointer to the data that is to be packed. Note
81 * that strings are to be passed as (char **) - i.e., the caller must
82 * pass the address of the pointer to the string as the void*. This
83 * allows the DSS to use a single interface function, but still allow
84 * the caller to pass multiple strings in a single call.
85 *
86 * @param num A size_t value indicating the number of values that are
87 * to be packed, beginning at the location pointed to by src. A string
88 * value is counted as a single value regardless of length. The values
89 * must be contiguous in memory. Arrays of pointers (e.g., string
90 * arrays) should be contiguous, although (obviously) the data pointed
91 * to need not be contiguous across array entries.
92 *
93 * @param type The type of the data to be packed - must be one of the
94 * DSS defined data types.
95 *
96 * @retval OPAL_SUCCESS The data was packed as requested.
97 *
98 * @retval OPAL_ERROR(s) An appropriate OPAL error code indicating the
99 * problem encountered. This error code should be handled
100 * appropriately.
101 *
102 * @code
103 * opal_buffer_t *buffer;
104 * int32_t src;
105 *
106 * status_code = opal_dss.pack(buffer, &src, 1, OPAL_INT32);
107 * @endcode
108 */
109 typedef int (*opal_dss_pack_fn_t)(opal_buffer_t *buffer, const void *src,
110 int32_t num_values,
111 opal_data_type_t type);
112
113 /**
114 * Unpack values from a buffer.
115 *
116 * The unpack function unpacks the next value (or values) of a
117 * specified type from the specified buffer.
118 *
119 * The buffer must have already been initialized via an OBJ_NEW or
120 * OBJ_CONSTRUCT call (and assumedly filled with some data) -
121 * otherwise, the unpack_value function will return an
122 * error. Providing an unsupported type flag will likewise be reported
123 * as an error, as will specifying a data type that DOES NOT match the
124 * type of the next item in the buffer. An attempt to read beyond the
125 * end of the stored data held in the buffer will also return an
126 * error.
127 *
128 * NOTE: it is possible for the buffer to be corrupted and that
129 * the DSS will *think* there is a proper variable type at the
130 * beginning of an unpack region - but that the value is bogus (e.g., just
131 * a byte field in a string array that so happens to have a value that
132 * matches the specified data type flag). Therefore, the data type error check
133 * is NOT completely safe. This is true for ALL unpack functions.
134 *
135 *
136 * Unpacking values is a "destructive" process - i.e., the values are
137 * removed from the buffer, thus reducing the buffer size. It is
138 * therefore not possible for the caller to re-unpack a value from the
139 * same buffer.
140 *
141 * Warning: The caller is responsible for providing adequate memory
142 * storage for the requested data. The opal_dss_peek() function is
143 * provided to assist in meeting this requirement. As noted below, the user
144 * must provide a parameter indicating the maximum number of values that
145 * can be unpacked into the allocated memory. If more values exist in the
146 * buffer than can fit into the memory storage, then the dss will unpack
147 * what it can fit into that location and return an error code indicating
148 * that the buffer was only partially unpacked.
149 *
150 * Note that any data that was not hard type cast (i.e., not type cast
151 * to a specific size) when packed may lose precision when unpacked by
152 * a non-homogeneous recipient. The DSS will do its best to deal with
153 * heterogeneity issues between the packer and unpacker in such
154 * cases. Sending a number larger than can be handled by the recipient
155 * will return an error code (generated by the DSS upon unpacking) via
156 * the RML upon transmission - the DSS cannot detect such errors
157 * during packing.
158 *
159 * @param *buffer A pointer to the buffer from which the value will be
160 * extracted.
161 *
162 * @param *dest A void* pointer to the memory location into which the
163 * data is to be stored. Note that these values will be stored
164 * contiguously in memory. For strings, this pointer must be to (char
165 * **) to provide a means of supporting multiple string
166 * operations. The DSS unpack function will allocate memory for each
167 * string in the array - the caller must only provide adequate memory
168 * for the array of pointers.
169 *
170 * @param *num A pointer to a int32_t value indicating the maximum
171 * number of values that are to be unpacked, beginning at the location
172 * pointed to by src. This is provided to help protect the caller from
173 * memory overrun. Note that a string
174 * value is counted as a single value regardless of length.
175 *
176 * @note The unpack function will return the actual number of values
177 * unpacked in this location.
178 *
179 * @param type The type of the data to be unpacked - must be one of
180 * the DSS defined data types.
181 *
182 * @retval *max_num_values The number of values actually unpacked. In
183 * most cases, this should match the maximum number provided in the
184 * parameters - but in no case will it exceed the value of this
185 * parameter. Note that if you unpack fewer values than are actually
186 * available, the buffer will be in an unpackable state - the dss will
187 * return an error code to warn of this condition.
188 *
189 * @retval OPAL_SUCCESS The next item in the buffer was successfully
190 * unpacked.
191 *
192 * @retval OPAL_ERROR(s) The unpack function returns an error code
193 * under one of several conditions: (a) the number of values in the
194 * item exceeds the max num provided by the caller; (b) the type of
195 * the next item in the buffer does not match the type specified by
196 * the caller; or (c) the unpack failed due to either an error in the
197 * buffer or an attempt to read past the end of the buffer.
198 *
199 * @code
200 * opal_buffer_t *buffer;
201 * int32_t dest;
202 * char **string_array;
203 * int32_t num_values;
204 *
205 * num_values = 1;
206 * status_code = opal_dss.unpack(buffer, (void*)&dest, &num_values, OPAL_INT32);
207 *
208 * num_values = 5;
209 * string_array = malloc(num_values*sizeof(char *));
210 * status_code = opal_dss.unpack(buffer, (void*)(string_array), &num_values, OPAL_STRING);
211 *
212 * @endcode
213 */
214 typedef int (*opal_dss_unpack_fn_t)(opal_buffer_t *buffer, void *dest,
215 int32_t *max_num_values,
216 opal_data_type_t type);
217
218 /**
219 * Get the type and number of values of the next item in the buffer.
220 *
221 * The peek function looks at the next item in the buffer and returns
222 * both its type and the number of values in the item. This is a
223 * non-destructive function call that does not disturb the buffer, so
224 * it can be called multiple times if desired.
225 *
226 * @param buffer A pointer to the buffer in question.
227 *
228 * @param type A pointer to an opal_data_type_t variable where the
229 * type of the next item in the buffer is to be stored. Caller must
230 * have memory backing this location.
231 *
232 * @param number A pointer to a int32_t variable where the number of
233 * data values in the next item is to be stored. Caller must have
234 * memory backing this location.
235 *
236 * @retval OPAL_SUCCESS Requested info was successfully returned.
237 * @retval OPAL_ERROR(s) An appropriate error code indicating the
238 * problem will be returned. This should be handled appropriately by
239 * the caller.
240 *
241 */
242 typedef int (*opal_dss_peek_next_item_fn_t)(opal_buffer_t *buffer,
243 opal_data_type_t *type,
244 int32_t *number);
245
246 /**
247 * Unload the data payload from a buffer.
248 *
249 * The unload function provides the caller with a pointer to the data
250 * payload within the buffer and the size of that payload. This allows
251 * the user to directly access the payload - typically used in the RML
252 * to unload the payload from the buffer for transmission.
253 *
254 * @note This is a destructive operation. While the payload is
255 * undisturbed, the function will clear the buffer's pointers to the
256 * payload. Thus, the buffer and the payload are completely separated,
257 * leaving the caller free to OBJ_RELEASE the buffer.
258 *
259 * @param buffer A pointer to the buffer whose payload is to be
260 * unloaded.
261 *
262 * @param payload The address to a void* pointer that is to be loaded
263 * with the address of the data payload in the buffer.
264 *
265 * @param size The size (in bytes) of the data payload in the buffer.
266 *
267 * @retval OPAL_SUCCESS The request was succesfully completed.
268 *
269 * @retval OPAL_ERROR(s) An appropriate error code indicating the
270 * problem will be returned. This should be handled appropriately by
271 * the caller.
272 *
273 * @code
274 * opal_buffer_t *buffer;
275 * uint8_t *bytes;
276 * int32_t size;
277 *
278 * status_code = opal_dss.unload(buffer, (void**)(&bytes), &size);
279 * OBJ_RELEASE(buffer);
280 * @endcode
281 */
282 typedef int (*opal_dss_unload_fn_t)(opal_buffer_t *buffer,
283 void **payload,
284 int32_t *size);
285
286 /**
287 * Load a data payload into a buffer.
288 *
289 * The load function allows the caller to replace the payload in a
290 * buffer with one provided by the caller. If a payload already exists
291 * in the buffer, the function will "free" the existing data to
292 * release it, and then replace the data payload with the one provided
293 * by the caller.
294 *
295 * @note The buffer must be allocated in advance via the OBJ_NEW
296 * function call - failing to do so will cause the load function to
297 * return an error code.
298 *
299 * @note The caller is responsible for pre-packing the provided
300 * payload - the load function cannot convert to network byte order
301 * any data contained in the provided payload.
302 *
303 * @param buffer A pointer to the buffer into which lthe payload is to
304 * be loaded.
305 *
306 * @param payload A void* pointer to the payload to be loaded into the
307 * buffer.
308 *
309 * @param size The size (in bytes) of the provided payload.
310 *
311 * @retval OPAL_SUCCESS The request was successfully completed
312 *
313 * @retval OPAL_ERROR(s) An appropriate error code indicating the
314 * problem will be returned. This should be handled appropriately by
315 * the caller.
316 *
317 * @code
318 * opal_buffer_t *buffer;
319 * uint8_t bytes;
320 * int32_t size;
321 *
322 * buffer = OBJ_NEW(opal_buffer_t);
323 * status_code = opal_dss.load(buffer, (void*)(&bytes), size);
324 * @endcode
325 */
326 typedef int (*opal_dss_load_fn_t)(opal_buffer_t *buffer,
327 void *payload,
328 int32_t size);
329
330
331 /**
332 * Copy a payload from one buffer to another
333 * This function will append a copy of the payload in one buffer into
334 * another buffer. If the destination buffer is NOT empty, then the
335 * type of the two buffers MUST match or else an
336 * error will be returned. If the destination buffer IS empty, then
337 * its type will be set to that of the source buffer.
338 * NOTE: This is NOT a destructive procedure - the
339 * source buffer's payload will remain intact, as will any pre-existing
340 * payload in the destination's buffer.
341 */
342 typedef int (*opal_dss_copy_payload_fn_t)(opal_buffer_t *dest,
343 opal_buffer_t *src);
344
345 /**
346 * DSS register function
347 *
348 * This function registers variables associated with the DSS system.
349 */
350 OPAL_DECLSPEC int opal_dss_register_vars (void);
351
352 /**
353 * DSS initialization function.
354 *
355 * In dynamic libraries, declared objects and functions don't get
356 * loaded until called. We need to ensure that the opal_dss function
357 * structure gets loaded, so we provide an "open" call that is
358 * executed as part of the program startup.
359 */
360 OPAL_DECLSPEC int opal_dss_open(void);
361
362 /**
363 * Copy a data value from one location to another.
364 *
365 * Since registered data types can be complex structures, the system
366 * needs some way to know how to copy the data from one location to
367 * another (e.g., for storage in the registry). This function, which
368 * can call other copy functions to build up complex data types, defines
369 * the method for making a copy of the specified data type.
370 *
371 * @param **dest The address of a pointer into which the
372 * address of the resulting data is to be stored.
373 *
374 * @param *src A pointer to the memory location from which the
375 * data is to be copied.
376 *
377 * @param type The type of the data to be copied - must be one of
378 * the DSS defined data types.
379 *
380 * @retval OPAL_SUCCESS The value was successfully copied.
381 *
382 * @retval OPAL_ERROR(s) An appropriate error code.
383 *
384 */
385 typedef int (*opal_dss_copy_fn_t)(void **dest, void *src, opal_data_type_t type);
386
387 /**
388 * Compare two data values.
389 *
390 * Since registered data types can be complex structures, the system
391 * needs some way to know how to compare two data values (e.g., when
392 * trying to order them in some fashion). This function, which
393 * can call other compare functions to build up complex data types, defines
394 * the method for comparing two values of the specified data type.
395 *
396 * @retval -1 Indicates first value is greater than second value
397 * @retval 0 Indicates two values are equal
398 * @retval +1 Indicates second value is greater than first value
399 */
400 typedef int (*opal_dss_compare_fn_t)(const void *value1, const void *value2,
401 opal_data_type_t type);
402
403
404 /**
405 * Print a data value.
406 *
407 * Since registered data types can be complex structures, the system
408 * needs some way to know how to print them (i.e., convert them to a string
409 * representation).
410 *
411 * @retval OPAL_SUCCESS The value was successfully printed.
412 *
413 * @retval OPAL_ERROR(s) An appropriate error code.
414 */
415 typedef int (*opal_dss_print_fn_t)(char **output, char *prefix, void *src, opal_data_type_t type);
416
417
418 /**
419 * Print a data value to an output stream for debugging purposes
420 *
421 * Uses the dss.print command to obtain a string version of the data value
422 * and prints it to the designated output stream.
423 *
424 * @retval OPAL_SUCCESS The value was successfully printed.
425 *
426 * @retval OPAL_ERROR(s) An appropriate error code.
427 */
428 typedef int (*opal_dss_dump_fn_t)(int output_stream, void *src, opal_data_type_t type);
429
430 /**
431 * Register a set of data handling functions.
432 *
433 * * This function registers a set of data type functions for a specific
434 * type. An integer is returned that should be used a an argument to
435 * future invocations of opal_dss.pack(), opal_dss.unpack(), opal_dss.copy(),
436 * and opal_dss.compare, which
437 * will trigger calls to the appropriate functions. This
438 * is most useful when extending the datatypes that the dss can
439 * handle; pack and unpack functions can nest calls to opal_dss.pack()
440 * / opal_dss.unpack(), so defining small pack/unpack functions can be
441 * used recursively to build larger types (e.g., packing/unpacking
442 * structs can use calls to opal_dss.pack()/unpack() to serialize /
443 * deserialize individual members). This is likewise true for the copy
444 * and compare functions.
445 *
446 * @param pack_fn [IN] Function pointer to the pack routine
447 * @param unpack_fn [IN] Function pointer to the unpack routine
448 * @param copy_fn [IN] Function pointer to copy routine
449 * @param compare_fn [IN] Function pointer to compare routine
450 * @param print_fn [IN] Function pointer to print routine
451 * @param structured [IN] Boolean indicator as to whether or not the data is structured. A true
452 * value indicates that this data type is always passed via reference (i.e., a pointer to the
453 * object is passed) as opposed to directly (e.g., the way an int32_t would appear)
454 * @param name [IN] String name for this pair (mainly for debugging)
455 * @param type [OUT] Type number for this registration
456 *
457 * @returns OPAL_SUCCESS upon success
458 *
459 */
460 typedef int (*opal_dss_register_fn_t)(opal_dss_pack_fn_t pack_fn,
461 opal_dss_unpack_fn_t unpack_fn,
462 opal_dss_copy_fn_t copy_fn,
463 opal_dss_compare_fn_t compare_fn,
464 opal_dss_print_fn_t print_fn,
465 bool structured,
466 const char *name, opal_data_type_t *type);
467 /*
468 * This function looks up the string name corresponding to the identified
469 * data type - used for debugging messages.
470 */
471 typedef char* (*opal_dss_lookup_data_type_fn_t)(opal_data_type_t type);
472
473 /*
474 * Dump the data type list - used for debugging to see what has been registered
475 */
476 typedef void (*opal_dss_dump_data_types_fn_t)(int output);
477
478 /* return true if the data type is structured */
479 typedef bool (*opal_dss_structured_fn_t)(opal_data_type_t type);
480
481 /**
482 * Base structure for the DSS
483 *
484 * Base module structure for the DSS - presents the required function
485 * pointers to the calling interface.
486 */
487 struct opal_dss_t {
488 opal_dss_pack_fn_t pack;
489 opal_dss_unpack_fn_t unpack;
490 opal_dss_copy_fn_t copy;
491 opal_dss_compare_fn_t compare;
492 opal_dss_print_fn_t print;
493 opal_dss_structured_fn_t structured;
494 opal_dss_peek_next_item_fn_t peek;
495 opal_dss_unload_fn_t unload;
496 opal_dss_load_fn_t load;
497 opal_dss_copy_payload_fn_t copy_payload;
498 opal_dss_register_fn_t register_type;
499 opal_dss_lookup_data_type_fn_t lookup_data_type;
500 opal_dss_dump_data_types_fn_t dump_data_types;
501 opal_dss_dump_fn_t dump;
502 };
503 typedef struct opal_dss_t opal_dss_t;
504
505 OPAL_DECLSPEC extern opal_dss_t opal_dss; /* holds dss function pointers */
506
507 END_C_DECLS
508
509 #endif /* OPAL_DSS_H */