1 /* 2 * kmp_threadprivate.cpp -- OpenMP threadprivate support library 3 */ 4 5 //===----------------------------------------------------------------------===// 6 // 7 // The LLVM Compiler Infrastructure 8 // 9 // This file is dual licensed under the MIT and the University of Illinois Open 10 // Source Licenses. See LICENSE.txt for details. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "kmp.h" 15 #include "kmp_i18n.h" 16 #include "kmp_itt.h" 17 18 #define USE_CHECKS_COMMON 19 20 #define KMP_INLINE_SUBR 1 21 22 void kmp_threadprivate_insert_private_data(int gtid, void *pc_addr, 23 void *data_addr, size_t pc_size); 24 struct private_common *kmp_threadprivate_insert(int gtid, void *pc_addr, 25 void *data_addr, 26 size_t pc_size); 27 28 struct shared_table __kmp_threadprivate_d_table; 29 30 static 31 #ifdef KMP_INLINE_SUBR 32 __forceinline 33 #endif 34 struct private_common * 35 __kmp_threadprivate_find_task_common(struct common_table *tbl, int gtid, 36 void *pc_addr) 37 38 { 39 struct private_common *tn; 40 41 #ifdef KMP_TASK_COMMON_DEBUG 42 KC_TRACE(10, ("__kmp_threadprivate_find_task_common: thread#%d, called with " 43 "address %p\n", 44 gtid, pc_addr)); 45 dump_list(); 46 #endif 47 48 for (tn = tbl->data[KMP_HASH(pc_addr)]; tn; tn = tn->next) { 49 if (tn->gbl_addr == pc_addr) { 50 #ifdef KMP_TASK_COMMON_DEBUG 51 KC_TRACE(10, ("__kmp_threadprivate_find_task_common: thread#%d, found " 52 "node %p on list\n", 53 gtid, pc_addr)); 54 #endif 55 return tn; 56 } 57 } 58 return 0; 59 } 60 61 static 62 #ifdef KMP_INLINE_SUBR 63 __forceinline 64 #endif 65 struct shared_common * 66 __kmp_find_shared_task_common(struct shared_table *tbl, int gtid, 67 void *pc_addr) { 68 struct shared_common *tn; 69 70 for (tn = tbl->data[KMP_HASH(pc_addr)]; tn; tn = tn->next) { 71 if (tn->gbl_addr == pc_addr) { 72 #ifdef KMP_TASK_COMMON_DEBUG 73 KC_TRACE( 74 10, 75 ("__kmp_find_shared_task_common: thread#%d, found node %p on list\n", 76 gtid, pc_addr)); 77 #endif 78 return tn; 79 } 80 } 81 return 0; 82 } 83 84 // Create a template for the data initialized storage. Either the template is 85 // NULL indicating zero fill, or the template is a copy of the original data. 86 static struct private_data *__kmp_init_common_data(void *pc_addr, 87 size_t pc_size) { 88 struct private_data *d; 89 size_t i; 90 char *p; 91 92 d = (struct private_data *)__kmp_allocate(sizeof(struct private_data)); 93 /* 94 d->data = 0; // AC: commented out because __kmp_allocate zeroes the 95 memory 96 d->next = 0; 97 */ 98 d->size = pc_size; 99 d->more = 1; 100 101 p = (char *)pc_addr; 102 103 for (i = pc_size; i > 0; --i) { 104 if (*p++ != '\0') { 105 d->data = __kmp_allocate(pc_size); 106 KMP_MEMCPY(d->data, pc_addr, pc_size); 107 break; 108 } 109 } 110 111 return d; 112 } 113 114 // Initialize the data area from the template. 115 static void __kmp_copy_common_data(void *pc_addr, struct private_data *d) { 116 char *addr = (char *)pc_addr; 117 int i, offset; 118 119 for (offset = 0; d != 0; d = d->next) { 120 for (i = d->more; i > 0; --i) { 121 if (d->data == 0) 122 memset(&addr[offset], '\0', d->size); 123 else 124 KMP_MEMCPY(&addr[offset], d->data, d->size); 125 offset += d->size; 126 } 127 } 128 } 129 130 /* we are called from __kmp_serial_initialize() with __kmp_initz_lock held. */ 131 void __kmp_common_initialize(void) { 132 if (!TCR_4(__kmp_init_common)) { 133 int q; 134 #ifdef KMP_DEBUG 135 int gtid; 136 #endif 137 138 __kmp_threadpriv_cache_list = NULL; 139 140 #ifdef KMP_DEBUG 141 /* verify the uber masters were initialized */ 142 for (gtid = 0; gtid < __kmp_threads_capacity; gtid++) 143 if (__kmp_root[gtid]) { 144 KMP_DEBUG_ASSERT(__kmp_root[gtid]->r.r_uber_thread); 145 for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) 146 KMP_DEBUG_ASSERT( 147 !__kmp_root[gtid]->r.r_uber_thread->th.th_pri_common->data[q]); 148 /* __kmp_root[ gitd ]-> r.r_uber_thread -> 149 * th.th_pri_common -> data[ q ] = 0;*/ 150 } 151 #endif /* KMP_DEBUG */ 152 153 for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) 154 __kmp_threadprivate_d_table.data[q] = 0; 155 156 TCW_4(__kmp_init_common, TRUE); 157 } 158 } 159 160 /* Call all destructors for threadprivate data belonging to all threads. 161 Currently unused! */ 162 void __kmp_common_destroy(void) { 163 if (TCR_4(__kmp_init_common)) { 164 int q; 165 166 TCW_4(__kmp_init_common, FALSE); 167 168 for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) { 169 int gtid; 170 struct private_common *tn; 171 struct shared_common *d_tn; 172 173 /* C++ destructors need to be called once per thread before exiting. 174 Don't call destructors for master thread though unless we used copy 175 constructor */ 176 177 for (d_tn = __kmp_threadprivate_d_table.data[q]; d_tn; 178 d_tn = d_tn->next) { 179 if (d_tn->is_vec) { 180 if (d_tn->dt.dtorv != 0) { 181 for (gtid = 0; gtid < __kmp_all_nth; ++gtid) { 182 if (__kmp_threads[gtid]) { 183 if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid)) 184 : (!KMP_UBER_GTID(gtid))) { 185 tn = __kmp_threadprivate_find_task_common( 186 __kmp_threads[gtid]->th.th_pri_common, gtid, 187 d_tn->gbl_addr); 188 if (tn) { 189 (*d_tn->dt.dtorv)(tn->par_addr, d_tn->vec_len); 190 } 191 } 192 } 193 } 194 if (d_tn->obj_init != 0) { 195 (*d_tn->dt.dtorv)(d_tn->obj_init, d_tn->vec_len); 196 } 197 } 198 } else { 199 if (d_tn->dt.dtor != 0) { 200 for (gtid = 0; gtid < __kmp_all_nth; ++gtid) { 201 if (__kmp_threads[gtid]) { 202 if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid)) 203 : (!KMP_UBER_GTID(gtid))) { 204 tn = __kmp_threadprivate_find_task_common( 205 __kmp_threads[gtid]->th.th_pri_common, gtid, 206 d_tn->gbl_addr); 207 if (tn) { 208 (*d_tn->dt.dtor)(tn->par_addr); 209 } 210 } 211 } 212 } 213 if (d_tn->obj_init != 0) { 214 (*d_tn->dt.dtor)(d_tn->obj_init); 215 } 216 } 217 } 218 } 219 __kmp_threadprivate_d_table.data[q] = 0; 220 } 221 } 222 } 223 224 /* Call all destructors for threadprivate data belonging to this thread */ 225 void __kmp_common_destroy_gtid(int gtid) { 226 struct private_common *tn; 227 struct shared_common *d_tn; 228 229 KC_TRACE(10, ("__kmp_common_destroy_gtid: T#%d called\n", gtid)); 230 if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid)) : (!KMP_UBER_GTID(gtid))) { 231 232 if (TCR_4(__kmp_init_common)) { 233 234 /* Cannot do this here since not all threads have destroyed their data */ 235 /* TCW_4(__kmp_init_common, FALSE); */ 236 237 for (tn = __kmp_threads[gtid]->th.th_pri_head; tn; tn = tn->link) { 238 239 d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, gtid, 240 tn->gbl_addr); 241 242 KMP_DEBUG_ASSERT(d_tn); 243 244 if (d_tn->is_vec) { 245 if (d_tn->dt.dtorv != 0) { 246 (void)(*d_tn->dt.dtorv)(tn->par_addr, d_tn->vec_len); 247 } 248 if (d_tn->obj_init != 0) { 249 (void)(*d_tn->dt.dtorv)(d_tn->obj_init, d_tn->vec_len); 250 } 251 } else { 252 if (d_tn->dt.dtor != 0) { 253 (void)(*d_tn->dt.dtor)(tn->par_addr); 254 } 255 if (d_tn->obj_init != 0) { 256 (void)(*d_tn->dt.dtor)(d_tn->obj_init); 257 } 258 } 259 } 260 KC_TRACE(30, ("__kmp_common_destroy_gtid: T#%d threadprivate destructors " 261 "complete\n", 262 gtid)); 263 } 264 } 265 } 266 267 #ifdef KMP_TASK_COMMON_DEBUG 268 static void dump_list(void) { 269 int p, q; 270 271 for (p = 0; p < __kmp_all_nth; ++p) { 272 if (!__kmp_threads[p]) 273 continue; 274 for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) { 275 if (__kmp_threads[p]->th.th_pri_common->data[q]) { 276 struct private_common *tn; 277 278 KC_TRACE(10, ("\tdump_list: gtid:%d addresses\n", p)); 279 280 for (tn = __kmp_threads[p]->th.th_pri_common->data[q]; tn; 281 tn = tn->next) { 282 KC_TRACE(10, 283 ("\tdump_list: THREADPRIVATE: Serial %p -> Parallel %p\n", 284 tn->gbl_addr, tn->par_addr)); 285 } 286 } 287 } 288 } 289 } 290 #endif /* KMP_TASK_COMMON_DEBUG */ 291 292 // NOTE: this routine is to be called only from the serial part of the program. 293 void kmp_threadprivate_insert_private_data(int gtid, void *pc_addr, 294 void *data_addr, size_t pc_size) { 295 struct shared_common **lnk_tn, *d_tn; 296 KMP_DEBUG_ASSERT(__kmp_threads[gtid] && 297 __kmp_threads[gtid]->th.th_root->r.r_active == 0); 298 299 d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, gtid, 300 pc_addr); 301 302 if (d_tn == 0) { 303 d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common)); 304 305 d_tn->gbl_addr = pc_addr; 306 d_tn->pod_init = __kmp_init_common_data(data_addr, pc_size); 307 /* 308 d_tn->obj_init = 0; // AC: commented out because __kmp_allocate 309 zeroes the memory 310 d_tn->ct.ctor = 0; 311 d_tn->cct.cctor = 0;; 312 d_tn->dt.dtor = 0; 313 d_tn->is_vec = FALSE; 314 d_tn->vec_len = 0L; 315 */ 316 d_tn->cmn_size = pc_size; 317 318 __kmp_acquire_lock(&__kmp_global_lock, gtid); 319 320 lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(pc_addr)]); 321 322 d_tn->next = *lnk_tn; 323 *lnk_tn = d_tn; 324 325 __kmp_release_lock(&__kmp_global_lock, gtid); 326 } 327 } 328 329 struct private_common *kmp_threadprivate_insert(int gtid, void *pc_addr, 330 void *data_addr, 331 size_t pc_size) { 332 struct private_common *tn, **tt; 333 struct shared_common *d_tn; 334 335 /* +++++++++ START OF CRITICAL SECTION +++++++++ */ 336 __kmp_acquire_lock(&__kmp_global_lock, gtid); 337 338 tn = (struct private_common *)__kmp_allocate(sizeof(struct private_common)); 339 340 tn->gbl_addr = pc_addr; 341 342 d_tn = __kmp_find_shared_task_common( 343 &__kmp_threadprivate_d_table, gtid, 344 pc_addr); /* Only the MASTER data table exists. */ 345 346 if (d_tn != 0) { 347 /* This threadprivate variable has already been seen. */ 348 349 if (d_tn->pod_init == 0 && d_tn->obj_init == 0) { 350 d_tn->cmn_size = pc_size; 351 352 if (d_tn->is_vec) { 353 if (d_tn->ct.ctorv != 0) { 354 /* Construct from scratch so no prototype exists */ 355 d_tn->obj_init = 0; 356 } else if (d_tn->cct.cctorv != 0) { 357 /* Now data initialize the prototype since it was previously 358 * registered */ 359 d_tn->obj_init = (void *)__kmp_allocate(d_tn->cmn_size); 360 (void)(*d_tn->cct.cctorv)(d_tn->obj_init, pc_addr, d_tn->vec_len); 361 } else { 362 d_tn->pod_init = __kmp_init_common_data(data_addr, d_tn->cmn_size); 363 } 364 } else { 365 if (d_tn->ct.ctor != 0) { 366 /* Construct from scratch so no prototype exists */ 367 d_tn->obj_init = 0; 368 } else if (d_tn->cct.cctor != 0) { 369 /* Now data initialize the prototype since it was previously 370 registered */ 371 d_tn->obj_init = (void *)__kmp_allocate(d_tn->cmn_size); 372 (void)(*d_tn->cct.cctor)(d_tn->obj_init, pc_addr); 373 } else { 374 d_tn->pod_init = __kmp_init_common_data(data_addr, d_tn->cmn_size); 375 } 376 } 377 } 378 } else { 379 struct shared_common **lnk_tn; 380 381 d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common)); 382 d_tn->gbl_addr = pc_addr; 383 d_tn->cmn_size = pc_size; 384 d_tn->pod_init = __kmp_init_common_data(data_addr, pc_size); 385 /* 386 d_tn->obj_init = 0; // AC: commented out because __kmp_allocate 387 zeroes the memory 388 d_tn->ct.ctor = 0; 389 d_tn->cct.cctor = 0; 390 d_tn->dt.dtor = 0; 391 d_tn->is_vec = FALSE; 392 d_tn->vec_len = 0L; 393 */ 394 lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(pc_addr)]); 395 396 d_tn->next = *lnk_tn; 397 *lnk_tn = d_tn; 398 } 399 400 tn->cmn_size = d_tn->cmn_size; 401 402 if ((__kmp_foreign_tp) ? (KMP_INITIAL_GTID(gtid)) : (KMP_UBER_GTID(gtid))) { 403 tn->par_addr = (void *)pc_addr; 404 } else { 405 tn->par_addr = (void *)__kmp_allocate(tn->cmn_size); 406 } 407 408 __kmp_release_lock(&__kmp_global_lock, gtid); 409 /* +++++++++ END OF CRITICAL SECTION +++++++++ */ 410 411 #ifdef USE_CHECKS_COMMON 412 if (pc_size > d_tn->cmn_size) { 413 KC_TRACE( 414 10, ("__kmp_threadprivate_insert: THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC 415 " ,%" KMP_UINTPTR_SPEC ")\n", 416 pc_addr, pc_size, d_tn->cmn_size)); 417 KMP_FATAL(TPCommonBlocksInconsist); 418 } 419 #endif /* USE_CHECKS_COMMON */ 420 421 tt = &(__kmp_threads[gtid]->th.th_pri_common->data[KMP_HASH(pc_addr)]); 422 423 #ifdef KMP_TASK_COMMON_DEBUG 424 if (*tt != 0) { 425 KC_TRACE( 426 10, 427 ("__kmp_threadprivate_insert: WARNING! thread#%d: collision on %p\n", 428 gtid, pc_addr)); 429 } 430 #endif 431 tn->next = *tt; 432 *tt = tn; 433 434 #ifdef KMP_TASK_COMMON_DEBUG 435 KC_TRACE(10, 436 ("__kmp_threadprivate_insert: thread#%d, inserted node %p on list\n", 437 gtid, pc_addr)); 438 dump_list(); 439 #endif 440 441 /* Link the node into a simple list */ 442 443 tn->link = __kmp_threads[gtid]->th.th_pri_head; 444 __kmp_threads[gtid]->th.th_pri_head = tn; 445 446 if ((__kmp_foreign_tp) ? (KMP_INITIAL_GTID(gtid)) : (KMP_UBER_GTID(gtid))) 447 return tn; 448 449 /* if C++ object with copy constructor, use it; 450 * else if C++ object with constructor, use it for the non-master copies only; 451 * else use pod_init and memcpy 452 * 453 * C++ constructors need to be called once for each non-master thread on 454 * allocate 455 * C++ copy constructors need to be called once for each thread on allocate */ 456 457 /* C++ object with constructors/destructors; don't call constructors for 458 master thread though */ 459 if (d_tn->is_vec) { 460 if (d_tn->ct.ctorv != 0) { 461 (void)(*d_tn->ct.ctorv)(tn->par_addr, d_tn->vec_len); 462 } else if (d_tn->cct.cctorv != 0) { 463 (void)(*d_tn->cct.cctorv)(tn->par_addr, d_tn->obj_init, d_tn->vec_len); 464 } else if (tn->par_addr != tn->gbl_addr) { 465 __kmp_copy_common_data(tn->par_addr, d_tn->pod_init); 466 } 467 } else { 468 if (d_tn->ct.ctor != 0) { 469 (void)(*d_tn->ct.ctor)(tn->par_addr); 470 } else if (d_tn->cct.cctor != 0) { 471 (void)(*d_tn->cct.cctor)(tn->par_addr, d_tn->obj_init); 472 } else if (tn->par_addr != tn->gbl_addr) { 473 __kmp_copy_common_data(tn->par_addr, d_tn->pod_init); 474 } 475 } 476 /* !BUILD_OPENMP_C 477 if (tn->par_addr != tn->gbl_addr) 478 __kmp_copy_common_data( tn->par_addr, d_tn->pod_init ); */ 479 480 return tn; 481 } 482 483 /* ------------------------------------------------------------------------ */ 484 /* We are currently parallel, and we know the thread id. */ 485 /* ------------------------------------------------------------------------ */ 486 487 /*! 488 @ingroup THREADPRIVATE 489 490 @param loc source location information 491 @param data pointer to data being privatized 492 @param ctor pointer to constructor function for data 493 @param cctor pointer to copy constructor function for data 494 @param dtor pointer to destructor function for data 495 496 Register constructors and destructors for thread private data. 497 This function is called when executing in parallel, when we know the thread id. 498 */ 499 void __kmpc_threadprivate_register(ident_t *loc, void *data, kmpc_ctor ctor, 500 kmpc_cctor cctor, kmpc_dtor dtor) { 501 struct shared_common *d_tn, **lnk_tn; 502 503 KC_TRACE(10, ("__kmpc_threadprivate_register: called\n")); 504 505 #ifdef USE_CHECKS_COMMON 506 /* copy constructor must be zero for current code gen (Nov 2002 - jph) */ 507 KMP_ASSERT(cctor == 0); 508 #endif /* USE_CHECKS_COMMON */ 509 510 /* Only the global data table exists. */ 511 d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, -1, data); 512 513 if (d_tn == 0) { 514 d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common)); 515 d_tn->gbl_addr = data; 516 517 d_tn->ct.ctor = ctor; 518 d_tn->cct.cctor = cctor; 519 d_tn->dt.dtor = dtor; 520 /* 521 d_tn->is_vec = FALSE; // AC: commented out because __kmp_allocate 522 zeroes the memory 523 d_tn->vec_len = 0L; 524 d_tn->obj_init = 0; 525 d_tn->pod_init = 0; 526 */ 527 lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(data)]); 528 529 d_tn->next = *lnk_tn; 530 *lnk_tn = d_tn; 531 } 532 } 533 534 void *__kmpc_threadprivate(ident_t *loc, kmp_int32 global_tid, void *data, 535 size_t size) { 536 void *ret; 537 struct private_common *tn; 538 539 KC_TRACE(10, ("__kmpc_threadprivate: T#%d called\n", global_tid)); 540 541 #ifdef USE_CHECKS_COMMON 542 if (!__kmp_init_serial) 543 KMP_FATAL(RTLNotInitialized); 544 #endif /* USE_CHECKS_COMMON */ 545 546 if (!__kmp_threads[global_tid]->th.th_root->r.r_active && !__kmp_foreign_tp) { 547 /* The parallel address will NEVER overlap with the data_address */ 548 /* dkp: 3rd arg to kmp_threadprivate_insert_private_data() is the 549 * data_address; use data_address = data */ 550 551 KC_TRACE(20, ("__kmpc_threadprivate: T#%d inserting private data\n", 552 global_tid)); 553 kmp_threadprivate_insert_private_data(global_tid, data, data, size); 554 555 ret = data; 556 } else { 557 KC_TRACE( 558 50, 559 ("__kmpc_threadprivate: T#%d try to find private data at address %p\n", 560 global_tid, data)); 561 tn = __kmp_threadprivate_find_task_common( 562 __kmp_threads[global_tid]->th.th_pri_common, global_tid, data); 563 564 if (tn) { 565 KC_TRACE(20, ("__kmpc_threadprivate: T#%d found data\n", global_tid)); 566 #ifdef USE_CHECKS_COMMON 567 if ((size_t)size > tn->cmn_size) { 568 KC_TRACE(10, ("THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC 569 " ,%" KMP_UINTPTR_SPEC ")\n", 570 data, size, tn->cmn_size)); 571 KMP_FATAL(TPCommonBlocksInconsist); 572 } 573 #endif /* USE_CHECKS_COMMON */ 574 } else { 575 /* The parallel address will NEVER overlap with the data_address */ 576 /* dkp: 3rd arg to kmp_threadprivate_insert() is the data_address; use 577 * data_address = data */ 578 KC_TRACE(20, ("__kmpc_threadprivate: T#%d inserting data\n", global_tid)); 579 tn = kmp_threadprivate_insert(global_tid, data, data, size); 580 } 581 582 ret = tn->par_addr; 583 } 584 KC_TRACE(10, ("__kmpc_threadprivate: T#%d exiting; return value = %p\n", 585 global_tid, ret)); 586 587 return ret; 588 } 589 590 /*! 591 @ingroup THREADPRIVATE 592 @param loc source location information 593 @param global_tid global thread number 594 @param data pointer to data to privatize 595 @param size size of data to privatize 596 @param cache pointer to cache 597 @return pointer to private storage 598 599 Allocate private storage for threadprivate data. 600 */ 601 void * 602 __kmpc_threadprivate_cached(ident_t *loc, 603 kmp_int32 global_tid, // gtid. 604 void *data, // Pointer to original global variable. 605 size_t size, // Size of original global variable. 606 void ***cache) { 607 KC_TRACE(10, ("__kmpc_threadprivate_cached: T#%d called with cache: %p, " 608 "address: %p, size: %" KMP_SIZE_T_SPEC "\n", 609 global_tid, *cache, data, size)); 610 611 if (TCR_PTR(*cache) == 0) { 612 __kmp_acquire_lock(&__kmp_global_lock, global_tid); 613 614 if (TCR_PTR(*cache) == 0) { 615 __kmp_acquire_bootstrap_lock(&__kmp_tp_cached_lock); 616 __kmp_tp_cached = 1; 617 __kmp_release_bootstrap_lock(&__kmp_tp_cached_lock); 618 void **my_cache; 619 KMP_ITT_IGNORE( 620 my_cache = (void **)__kmp_allocate( 621 sizeof(void *) * __kmp_tp_capacity + sizeof(kmp_cached_addr_t));); 622 // No need to zero the allocated memory; __kmp_allocate does that. 623 KC_TRACE( 624 50, 625 ("__kmpc_threadprivate_cached: T#%d allocated cache at address %p\n", 626 global_tid, my_cache)); 627 628 /* TODO: free all this memory in __kmp_common_destroy using 629 * __kmp_threadpriv_cache_list */ 630 /* Add address of mycache to linked list for cleanup later */ 631 kmp_cached_addr_t *tp_cache_addr; 632 633 tp_cache_addr = (kmp_cached_addr_t *)&my_cache[__kmp_tp_capacity]; 634 tp_cache_addr->addr = my_cache; 635 tp_cache_addr->next = __kmp_threadpriv_cache_list; 636 __kmp_threadpriv_cache_list = tp_cache_addr; 637 638 KMP_MB(); 639 640 TCW_PTR(*cache, my_cache); 641 642 KMP_MB(); 643 } 644 645 __kmp_release_lock(&__kmp_global_lock, global_tid); 646 } 647 648 void *ret; 649 if ((ret = TCR_PTR((*cache)[global_tid])) == 0) { 650 ret = __kmpc_threadprivate(loc, global_tid, data, (size_t)size); 651 652 TCW_PTR((*cache)[global_tid], ret); 653 } 654 KC_TRACE(10, 655 ("__kmpc_threadprivate_cached: T#%d exiting; return value = %p\n", 656 global_tid, ret)); 657 658 return ret; 659 } 660 661 /*! 662 @ingroup THREADPRIVATE 663 @param loc source location information 664 @param data pointer to data being privatized 665 @param ctor pointer to constructor function for data 666 @param cctor pointer to copy constructor function for data 667 @param dtor pointer to destructor function for data 668 @param vector_length length of the vector (bytes or elements?) 669 Register vector constructors and destructors for thread private data. 670 */ 671 void __kmpc_threadprivate_register_vec(ident_t *loc, void *data, 672 kmpc_ctor_vec ctor, kmpc_cctor_vec cctor, 673 kmpc_dtor_vec dtor, 674 size_t vector_length) { 675 struct shared_common *d_tn, **lnk_tn; 676 677 KC_TRACE(10, ("__kmpc_threadprivate_register_vec: called\n")); 678 679 #ifdef USE_CHECKS_COMMON 680 /* copy constructor must be zero for current code gen (Nov 2002 - jph) */ 681 KMP_ASSERT(cctor == 0); 682 #endif /* USE_CHECKS_COMMON */ 683 684 d_tn = __kmp_find_shared_task_common( 685 &__kmp_threadprivate_d_table, -1, 686 data); /* Only the global data table exists. */ 687 688 if (d_tn == 0) { 689 d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common)); 690 d_tn->gbl_addr = data; 691 692 d_tn->ct.ctorv = ctor; 693 d_tn->cct.cctorv = cctor; 694 d_tn->dt.dtorv = dtor; 695 d_tn->is_vec = TRUE; 696 d_tn->vec_len = (size_t)vector_length; 697 /* 698 d_tn->obj_init = 0; // AC: commented out because __kmp_allocate 699 zeroes the memory 700 d_tn->pod_init = 0; 701 */ 702 lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(data)]); 703 704 d_tn->next = *lnk_tn; 705 *lnk_tn = d_tn; 706 } 707 } 708