1 /* 2 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana 3 * University Research and Technology 4 * Corporation. All rights reserved. 5 * Copyright (c) 2004-2005 The University of Tennessee and The University 6 * of Tennessee Research Foundation. All rights 7 * reserved. 8 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, 9 * University of Stuttgart. All rights reserved. 10 * Copyright (c) 2004-2005 The Regents of the University of California. 11 * All rights reserved. 12 * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 13 * Copyright (c) 2017 Research Organization for Information Science 14 * and Technology (RIST). All rights reserved. 15 * $COPYRIGHT$ 16 * 17 * Additional copyrights may follow 18 * 19 * $HEADER$ 20 */ 21 22 /** @file 23 * 24 * Implementation for taking care of the attribute that can hang off a comm, 25 * win or datatype. 26 */ 27 28 #ifndef OMPI_ATTRIBUTE_H 29 #define OMPI_ATTRIBUTE_H 30 31 #include <string.h> 32 #include "mpi.h" 33 34 #include "ompi_config.h" 35 #include "ompi/constants.h" 36 #include "opal/class/opal_object.h" 37 #include "opal/class/opal_hash_table.h" 38 39 #define ATTR_HASH_SIZE 10 40 41 /* 42 * Flags for keyvals 43 */ 44 #define OMPI_KEYVAL_PREDEFINED 0x0001 45 #define OMPI_KEYVAL_F77 0x0002 46 #define OMPI_KEYVAL_F77_INT 0x0004 47 48 49 BEGIN_C_DECLS 50 51 enum ompi_attribute_type_t { 52 UNUSED_ATTR = 0, /**< Make the compilers happy when we have to construct 53 * an attribute */ 54 COMM_ATTR, /**< The attribute belongs to a comm object. Starts 55 * with 1 so that we can have it initialized to 0 56 * using memset in the constructor */ 57 TYPE_ATTR, /**< The attribute belongs to datatype object */ 58 WIN_ATTR /**< The attribute belongs to a win object */ 59 }; 60 typedef enum ompi_attribute_type_t ompi_attribute_type_t; 61 62 63 /* Old-style MPI-1 Fortran function pointer declarations for copy and 64 delete. These will only be used here and not in the front end 65 functions. */ 66 67 typedef void (ompi_fint_copy_attr_function)(MPI_Fint *oldobj, 68 MPI_Fint *keyval, 69 MPI_Fint *extra_state, 70 MPI_Fint *attr_in, 71 MPI_Fint *attr_out, 72 ompi_fortran_logical_t *flag, 73 MPI_Fint *ierr); 74 typedef void (ompi_fint_delete_attr_function)(MPI_Fint *obj, 75 MPI_Fint *keyval, 76 MPI_Fint *attr_in, 77 MPI_Fint *extra_state, 78 MPI_Fint *ierr); 79 80 /* New-style MPI-2 Fortran function pointer declarations for copy and 81 delete. These will only be used here and not in the front end 82 functions. */ 83 84 typedef void (ompi_aint_copy_attr_function)(MPI_Fint *oldobj, 85 MPI_Fint *keyval, 86 void *extra_state, 87 void *attr_in, 88 void *attr_out, 89 ompi_fortran_logical_t *flag, 90 MPI_Fint *ierr); 91 typedef void (ompi_aint_delete_attr_function)(MPI_Fint *obj, 92 MPI_Fint *keyval, 93 void *attr_in, 94 void *extra_state, 95 MPI_Fint *ierr); 96 /* 97 * Internally the copy function for all kinds of MPI objects has one more 98 * argument, the pointer to the new object. Therefore, we can do on the 99 * flight modifications of the new communicator based on attributes stored 100 * on the main communicator. 101 */ 102 typedef int (MPI_Comm_internal_copy_attr_function)(MPI_Comm, int, void *, 103 void *, void *, int *, 104 MPI_Comm); 105 typedef int (MPI_Type_internal_copy_attr_function)(MPI_Datatype, int, void *, 106 void *, void *, int *, 107 MPI_Datatype); 108 typedef int (MPI_Win_internal_copy_attr_function)(MPI_Win, int, void *, 109 void *, void *, int *, 110 MPI_Win); 111 112 typedef void (ompi_attribute_keyval_destructor_fn_t)(int); 113 114 /* Union to take care of proper casting of the function pointers 115 passed from the front end functions depending on the type. This 116 will avoid casting function pointers to void* */ 117 118 union ompi_attribute_fn_ptr_union_t { 119 MPI_Comm_delete_attr_function *attr_communicator_delete_fn; 120 MPI_Type_delete_attr_function *attr_datatype_delete_fn; 121 MPI_Win_delete_attr_function *attr_win_delete_fn; 122 123 MPI_Comm_internal_copy_attr_function *attr_communicator_copy_fn; 124 MPI_Type_internal_copy_attr_function *attr_datatype_copy_fn; 125 MPI_Win_internal_copy_attr_function *attr_win_copy_fn; 126 127 /* For Fortran old MPI-1 callback functions */ 128 129 ompi_fint_delete_attr_function *attr_fint_delete_fn; 130 ompi_fint_copy_attr_function *attr_fint_copy_fn; 131 132 /* For Fortran new MPI-2 callback functions */ 133 134 ompi_aint_delete_attr_function *attr_aint_delete_fn; 135 ompi_aint_copy_attr_function *attr_aint_copy_fn; 136 }; 137 138 typedef union ompi_attribute_fn_ptr_union_t ompi_attribute_fn_ptr_union_t; 139 140 141 /** 142 * Union to help convert between Fortran attributes (which must be 143 * stored by value) and C pointers (which is the back-end storage of 144 * all attributes). 145 */ 146 union ompi_attribute_fortran_ptr_t { 147 void *c_ptr; 148 MPI_Fint f_integer; 149 MPI_Aint f_address; 150 }; 151 /** 152 * Convenience typedef 153 */ 154 typedef union ompi_attribute_fortran_ptr_t ompi_attribute_fortran_ptr_t; 155 156 struct ompi_attribute_keyval_t { 157 opal_object_t super; 158 ompi_attribute_type_t attr_type; /**< One of COMM/WIN/DTYPE. This 159 will be used to cast the 160 copy/delete attribute functions 161 properly and error checking */ 162 int attr_flag; /**< flag field: contains "OMPI_KEYVAL_PREDEFINED", 163 "OMPI_KEYVAL_F77" */ 164 ompi_attribute_fn_ptr_union_t copy_attr_fn; /**< Copy function for the 165 attribute */ 166 ompi_attribute_fn_ptr_union_t delete_attr_fn; /**< Delete function for the 167 attribute */ 168 ompi_attribute_fortran_ptr_t extra_state; /**< Extra state of the attribute */ 169 int key; /**< Keep a track of which key this item belongs to, so that 170 the key can be deleted when this object is destroyed */ 171 172 /** Extra state for bindings to hang data on. If non-NULL, will be 173 freed by the C base when the keyval is destroyed. */ 174 void *bindings_extra_state; 175 }; 176 177 typedef struct ompi_attribute_keyval_t ompi_attribute_keyval_t; 178 179 180 /* Functions */ 181 182 183 184 /** 185 * Convenient way to initialize the attribute hash table per MPI-Object 186 */ 187 188 static inline 189 int ompi_attr_hash_init(opal_hash_table_t **hash) 190 { 191 *hash = OBJ_NEW(opal_hash_table_t); 192 if (NULL == *hash) { 193 fprintf(stderr, "Error while creating the local attribute list\n"); 194 return OMPI_ERR_OUT_OF_RESOURCE; 195 } 196 if (OMPI_SUCCESS != opal_hash_table_init(*hash, ATTR_HASH_SIZE)) { 197 return OMPI_ERR_OUT_OF_RESOURCE; 198 } 199 200 return MPI_SUCCESS; 201 } 202 203 /** 204 * Initialize the main attribute hash that stores the keyvals and meta data 205 * 206 * @return OMPI return code 207 */ 208 209 int ompi_attr_init(void); 210 211 /** 212 * Destroy the main attribute hash that stores the keyvals and meta data 213 */ 214 215 int ompi_attr_finalize(void); 216 217 218 /** 219 * Create a new key for use by attribute of Comm/Win/Datatype 220 * 221 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 222 * @param copy_attr_fn Union variable containing the function pointer 223 * to be used in order to copy the attribute (IN) 224 * @param delete_attr_fn Function pointer to be used for deleting the 225 * attribute (IN) 226 * @param key The newly created key is returned here (OUT) 227 * @param extra_state Extra state to hang off/do some special things (IN) 228 * @param flags Flags for the key -- flags contain OMPI_KEYVAL_F77, 229 * OMPI_KEYVAL_PREDEFINED 230 * @param bindings_extra_state Extra state that, if non-NULL, will 231 * automatically be free()'ed by the C base when 232 * the keyval is destroyed. 233 * 234 * NOTE: I have taken the assumption that user cannot modify/delete 235 * any predefined keys or the attributes attached. To accomplish this, 236 * all MPI* calls will have OMPI_KEYVAL_PREDEFINED set as 0. MPI 237 * implementors who will need to play with the predefined keys and 238 * attributes would call the ompi* functions here and not the MPI* 239 * functions, with OMPI_KEYVAL_PREDEFINED set to 1. 240 * END OF NOTE 241 * 242 * NOTE: For the function pointers, you need to create a variable of the 243 * union type "ompi_attribute_fn_ptr_union_t" and assign the proper field. 244 * to be passed into this function 245 * END OF NOTE 246 * 247 * @return OMPI return code 248 249 * 250 */ 251 252 OMPI_DECLSPEC int ompi_attr_create_keyval(ompi_attribute_type_t type, 253 ompi_attribute_fn_ptr_union_t copy_attr_fn, 254 ompi_attribute_fn_ptr_union_t delete_attr_fn, 255 int *key, void *extra_state, int flags, 256 void *bindings_extra_state); 257 258 /** 259 * Same as ompi_attr_create_keyval, but extra_state is a Fortran default integer. 260 */ 261 262 OMPI_DECLSPEC int ompi_attr_create_keyval_fint(ompi_attribute_type_t type, 263 ompi_attribute_fn_ptr_union_t copy_attr_fn, 264 ompi_attribute_fn_ptr_union_t delete_attr_fn, 265 int *key, MPI_Fint extra_state, int flags, 266 void *bindings_extra_state); 267 268 /** 269 * Same as ompi_attr_create_keyval, but extra_state is a Fortran address integer. 270 */ 271 272 OMPI_DECLSPEC int ompi_attr_create_keyval_aint(ompi_attribute_type_t type, 273 ompi_attribute_fn_ptr_union_t copy_attr_fn, 274 ompi_attribute_fn_ptr_union_t delete_attr_fn, 275 int *key, MPI_Aint extra_state, int flags, 276 void *bindings_extra_state); 277 278 /** 279 * Free an attribute keyval 280 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 281 * @param key key, which is set to MPI_KEY_INVALID (IN/OUT) 282 * @return OMPI error code 283 */ 284 285 int ompi_attr_free_keyval(ompi_attribute_type_t type, int *key, 286 bool predefined); 287 288 /** 289 * Set an attribute on the comm/win/datatype in a form valid for C. 290 * 291 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 292 * @param object The actual Comm/Win/Datatype object (IN) 293 * @param attr_hash The attribute hash table hanging on the object(IN/OUT) 294 * @param key Key val for the attribute (IN) 295 * @param attribute The actual attribute pointer (IN) 296 * @param predefined Whether the key is predefined or not 0/1 (IN) 297 * @return OMPI error code 298 * 299 * If (*attr_hash) == NULL, a new hash will be created and 300 * initialized. 301 * 302 * All four of these functions (ompi_attr_set_c(), ompi_attr_set_int(), 303 * ompi_attr_set_fint(), and ompi_attr_set_aint()) 304 * could have been combined into one function that took some kind of 305 * (void*) and an enum to indicate which way to translate the final 306 * representation, but that just seemed to make an already complicated 307 * situation more complicated through yet another layer of 308 * indirection. 309 * 310 * So yes, this is more code, but it's clearer and less error-prone 311 * (read: better) this way. 312 */ 313 int ompi_attr_set_c(ompi_attribute_type_t type, void *object, 314 opal_hash_table_t **attr_hash, 315 int key, void *attribute, bool predefined); 316 317 /** 318 * Set an int predefined attribute in a form valid for C. 319 * 320 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 321 * @param object The actual Comm/Win/Datatype object (IN) 322 * @param attr_hash The attribute hash table hanging on the object(IN/OUT) 323 * @param key Key val for the attribute (IN) 324 * @param attribute The actual attribute value (IN) 325 * @param predefined Whether the key is predefined or not 0/1 (IN) 326 * @return OMPI error code 327 * 328 * If (*attr_hash) == NULL, a new hash will be created and 329 * initialized. 330 * 331 * All four of these functions (ompi_attr_set_c(), ompi_attr_set_int(), 332 * ompi_attr_set_fint(), and ompi_attr_set_aint()) 333 * could have been combined into one function that took some kind of 334 * (void*) and an enum to indicate which way to translate the final 335 * representation, but that just seemed to make an already complicated 336 * situation more complicated through yet another layer of 337 * indirection. 338 * 339 * So yes, this is more code, but it's clearer and less error-prone 340 * (read: better) this way. 341 */ 342 int ompi_attr_set_int(ompi_attribute_type_t type, void *object, 343 opal_hash_table_t **attr_hash, 344 int key, int attribute, bool predefined); 345 346 /** 347 * Set an attribute on the comm/win/datatype in a form valid for 348 * Fortran MPI-1. 349 * 350 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 351 * @param object The actual Comm/Win/Datatype object (IN) 352 * @param attr_hash The attribute hash table hanging on the object(IN/OUT) 353 * @param key Key val for the attribute (IN) 354 * @param attribute The actual attribute pointer (IN) 355 * @param predefined Whether the key is predefined or not 0/1 (IN) 356 * @return OMPI error code 357 * 358 * If (*attr_hash) == NULL, a new hash will be created and 359 * initialized. 360 * 361 * All four of these functions (ompi_attr_set_c(), ompi_attr_set_int(), 362 * ompi_attr_set_fint(), and ompi_attr_set_aint()) 363 * could have been combined into one function that took some kind of 364 * (void*) and an enum to indicate which way to translate the final 365 * representation, but that just seemed to make an already complicated 366 * situation more complicated through yet another layer of 367 * indirection. 368 * 369 * So yes, this is more code, but it's clearer and less error-prone 370 * (read: better) this way. 371 */ 372 OMPI_DECLSPEC int ompi_attr_set_fint(ompi_attribute_type_t type, void *object, 373 opal_hash_table_t **attr_hash, 374 int key, MPI_Fint attribute, 375 bool predefined); 376 377 /** 378 * Set an attribute on the comm/win/datatype in a form valid for 379 * Fortran MPI-2. 380 * 381 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 382 * @param object The actual Comm/Win/Datatype object (IN) 383 * @param attr_hash The attribute hash table hanging on the object(IN/OUT) 384 * @param key Key val for the attribute (IN) 385 * @param attribute The actual attribute pointer (IN) 386 * @param predefined Whether the key is predefined or not 0/1 (IN) 387 * @return OMPI error code 388 * 389 * If (*attr_hash) == NULL, a new hash will be created and 390 * initialized. 391 * 392 * All four of these functions (ompi_attr_set_c(), ompi_attr_set_int(), 393 * ompi_attr_set_fint(), and ompi_attr_set_aint()) 394 * could have been combined into one function that took some kind of 395 * (void*) and an enum to indicate which way to translate the final 396 * representation, but that just seemed to make an already complicated 397 * situation more complicated through yet another layer of 398 * indirection. 399 * 400 * So yes, this is more code, but it's clearer and less error-prone 401 * (read: better) this way. 402 */ 403 OMPI_DECLSPEC int ompi_attr_set_aint(ompi_attribute_type_t type, void *object, 404 opal_hash_table_t **attr_hash, 405 int key, MPI_Aint attribute, 406 bool predefined); 407 408 /** 409 * Get an attribute on the comm/win/datatype in a form valid for C. 410 * 411 * @param attr_hash The attribute hash table hanging on the object(IN) 412 * @param key Key val for the attribute (IN) 413 * @param attribute The actual attribute pointer (OUT) 414 * @param flag Flag whether an attribute is associated 415 * with the key (OUT) 416 * @return OMPI error code 417 * 418 * All three of these functions (ompi_attr_get_c(), 419 * ompi_attr_get_fint(), and ompi_attr_get_aint()) 420 * could have been combined into one function that took some kind of 421 * (void*) and an enum to indicate which way to translate the final 422 * representation, but that just seemed to make an already complicated 423 * situation more complicated through yet another layer of 424 * indirection. 425 * 426 * So yes, this is more code, but it's clearer and less error-prone 427 * (read: better) this way. 428 */ 429 430 int ompi_attr_get_c(opal_hash_table_t *attr_hash, int key, 431 void **attribute, int *flag); 432 433 434 /** 435 * Get an attribute on the comm/win/datatype in a form valid for 436 * Fortran MPI-1. 437 * 438 * @param attr_hash The attribute hash table hanging on the object(IN) 439 * @param key Key val for the attribute (IN) 440 * @param attribute The actual attribute pointer (OUT) 441 * @param flag Flag whether an attribute is associated 442 * with the key (OUT) 443 * @return OMPI error code 444 * 445 * All three of these functions (ompi_attr_get_c(), 446 * ompi_attr_get_fint(), and ompi_attr_get_aint()) 447 * could have been combined into one function that took some kind of 448 * (void*) and an enum to indicate which way to translate the final 449 * representation, but that just seemed to make an already complicated 450 * situation more complicated through yet another layer of 451 * indirection. 452 * 453 * So yes, this is more code, but it's clearer and less error-prone 454 * (read: better) this way. 455 */ 456 457 OMPI_DECLSPEC int ompi_attr_get_fint(opal_hash_table_t *attr_hash, int key, 458 MPI_Fint *attribute, int *flag); 459 460 461 /** 462 * Get an attribute on the comm/win/datatype in a form valid for 463 * Fortran MPI-2. 464 * 465 * @param attr_hash The attribute hash table hanging on the object(IN) 466 * @param key Key val for the attribute (IN) 467 * @param attribute The actual attribute pointer (OUT) 468 * @param flag Flag whether an attribute is associated 469 * with the key (OUT) 470 * @return OMPI error code 471 * 472 * All three of these functions (ompi_attr_get_c(), 473 * ompi_attr_get_fint(), and ompi_attr_get_aint()) 474 * could have been combined into one function that took some kind of 475 * (void*) and an enum to indicate which way to translate the final 476 * representation, but that just seemed to make an already complicated 477 * situation more complicated through yet another layer of 478 * indirection. 479 * 480 * So yes, this is more code, but it's clearer and less error-prone 481 * (read: better) this way. 482 */ 483 484 OMPI_DECLSPEC int ompi_attr_get_aint(opal_hash_table_t *attr_hash, int key, 485 MPI_Aint *attribute, int *flag); 486 487 488 /** 489 * Delete an attribute on the comm/win/datatype 490 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 491 * @param object The actual Comm/Win/Datatype object (IN) 492 * @param attr_hash The attribute hash table hanging on the object(IN) 493 * @param key Key val for the attribute (IN) 494 * @param predefined Whether the key is predefined or not 0/1 (IN) 495 * @return OMPI error code 496 * 497 */ 498 499 int ompi_attr_delete(ompi_attribute_type_t type, void *object, 500 opal_hash_table_t *attr_hash , int key, 501 bool predefined); 502 503 504 /** 505 * This to be used from functions like MPI_*_DUP in order to copy all 506 * the attributes from the old Comm/Win/Dtype object to a new 507 * object. 508 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 509 * @param old_object The old COMM/WIN/DTYPE object (IN) 510 * @param new_object The new COMM/WIN/DTYPE object (IN) 511 * @param oldattr_hash The attribute hash table hanging on old object(IN) 512 * @param newattr_hash The attribute hash table hanging on new object(IN) 513 * @return OMPI error code 514 * 515 */ 516 517 int ompi_attr_copy_all(ompi_attribute_type_t type, void *old_object, 518 void *new_object, opal_hash_table_t *oldattr_hash, 519 opal_hash_table_t *newattr_hash); 520 521 522 /** 523 * This to be used to delete all the attributes from the Comm/Win/Dtype 524 * object in one shot 525 * @param type Type of attribute (COMM/WIN/DTYPE) (IN) 526 * @param object The COMM/WIN/DTYPE object (IN) 527 * @param attr_hash The attribute hash table hanging on the object(IN) 528 * @return OMPI error code 529 * 530 */ 531 532 int ompi_attr_delete_all(ompi_attribute_type_t type, void *object, 533 opal_hash_table_t *attr_hash); 534 535 536 /** 537 * \internal 538 * 539 * Create all the predefined attributes 540 * 541 * @returns OMPI_SUCCESS 542 */ 543 int ompi_attr_create_predefined(void); 544 545 /** 546 * \internal 547 * 548 * Free all the predefined attributes 549 * 550 * @returns OMPI_SUCCESS 551 */ 552 int ompi_attr_free_predefined(void); 553 554 555 END_C_DECLS 556 557 #endif /* OMPI_ATTRIBUTE_H */