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 */