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