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   if (!TCR_4(__kmp_init_gtid)) {
230     // This is possible when one of multiple roots initiates early library
231     // termination in a sequential region while other teams are active, and its
232     // child threads are about to end.
233     return;
234   }
235 
236   KC_TRACE(10, ("__kmp_common_destroy_gtid: T#%d called\n", gtid));
237   if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid)) : (!KMP_UBER_GTID(gtid))) {
238 
239     if (TCR_4(__kmp_init_common)) {
240 
241       /* Cannot do this here since not all threads have destroyed their data */
242       /* TCW_4(__kmp_init_common, FALSE); */
243 
244       for (tn = __kmp_threads[gtid]->th.th_pri_head; tn; tn = tn->link) {
245 
246         d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, gtid,
247                                              tn->gbl_addr);
248 
249         KMP_DEBUG_ASSERT(d_tn);
250 
251         if (d_tn->is_vec) {
252           if (d_tn->dt.dtorv != 0) {
253             (void)(*d_tn->dt.dtorv)(tn->par_addr, d_tn->vec_len);
254           }
255           if (d_tn->obj_init != 0) {
256             (void)(*d_tn->dt.dtorv)(d_tn->obj_init, d_tn->vec_len);
257           }
258         } else {
259           if (d_tn->dt.dtor != 0) {
260             (void)(*d_tn->dt.dtor)(tn->par_addr);
261           }
262           if (d_tn->obj_init != 0) {
263             (void)(*d_tn->dt.dtor)(d_tn->obj_init);
264           }
265         }
266       }
267       KC_TRACE(30, ("__kmp_common_destroy_gtid: T#%d threadprivate destructors "
268                     "complete\n",
269                     gtid));
270     }
271   }
272 }
273 
274 #ifdef KMP_TASK_COMMON_DEBUG
275 static void dump_list(void) {
276   int p, q;
277 
278   for (p = 0; p < __kmp_all_nth; ++p) {
279     if (!__kmp_threads[p])
280       continue;
281     for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) {
282       if (__kmp_threads[p]->th.th_pri_common->data[q]) {
283         struct private_common *tn;
284 
285         KC_TRACE(10, ("\tdump_list: gtid:%d addresses\n", p));
286 
287         for (tn = __kmp_threads[p]->th.th_pri_common->data[q]; tn;
288              tn = tn->next) {
289           KC_TRACE(10,
290                    ("\tdump_list: THREADPRIVATE: Serial %p -> Parallel %p\n",
291                     tn->gbl_addr, tn->par_addr));
292         }
293       }
294     }
295   }
296 }
297 #endif /* KMP_TASK_COMMON_DEBUG */
298 
299 // NOTE: this routine is to be called only from the serial part of the program.
300 void kmp_threadprivate_insert_private_data(int gtid, void *pc_addr,
301                                            void *data_addr, size_t pc_size) {
302   struct shared_common **lnk_tn, *d_tn;
303   KMP_DEBUG_ASSERT(__kmp_threads[gtid] &&
304                    __kmp_threads[gtid]->th.th_root->r.r_active == 0);
305 
306   d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, gtid,
307                                        pc_addr);
308 
309   if (d_tn == 0) {
310     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
311 
312     d_tn->gbl_addr = pc_addr;
313     d_tn->pod_init = __kmp_init_common_data(data_addr, pc_size);
314     /*
315             d_tn->obj_init = 0;  // AC: commented out because __kmp_allocate
316        zeroes the memory
317             d_tn->ct.ctor = 0;
318             d_tn->cct.cctor = 0;;
319             d_tn->dt.dtor = 0;
320             d_tn->is_vec = FALSE;
321             d_tn->vec_len = 0L;
322     */
323     d_tn->cmn_size = pc_size;
324 
325     __kmp_acquire_lock(&__kmp_global_lock, gtid);
326 
327     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(pc_addr)]);
328 
329     d_tn->next = *lnk_tn;
330     *lnk_tn = d_tn;
331 
332     __kmp_release_lock(&__kmp_global_lock, gtid);
333   }
334 }
335 
336 struct private_common *kmp_threadprivate_insert(int gtid, void *pc_addr,
337                                                 void *data_addr,
338                                                 size_t pc_size) {
339   struct private_common *tn, **tt;
340   struct shared_common *d_tn;
341 
342   /* +++++++++ START OF CRITICAL SECTION +++++++++ */
343   __kmp_acquire_lock(&__kmp_global_lock, gtid);
344 
345   tn = (struct private_common *)__kmp_allocate(sizeof(struct private_common));
346 
347   tn->gbl_addr = pc_addr;
348 
349   d_tn = __kmp_find_shared_task_common(
350       &__kmp_threadprivate_d_table, gtid,
351       pc_addr); /* Only the MASTER data table exists. */
352 
353   if (d_tn != 0) {
354     /* This threadprivate variable has already been seen. */
355 
356     if (d_tn->pod_init == 0 && d_tn->obj_init == 0) {
357       d_tn->cmn_size = pc_size;
358 
359       if (d_tn->is_vec) {
360         if (d_tn->ct.ctorv != 0) {
361           /* Construct from scratch so no prototype exists */
362           d_tn->obj_init = 0;
363         } else if (d_tn->cct.cctorv != 0) {
364           /* Now data initialize the prototype since it was previously
365            * registered */
366           d_tn->obj_init = (void *)__kmp_allocate(d_tn->cmn_size);
367           (void)(*d_tn->cct.cctorv)(d_tn->obj_init, pc_addr, d_tn->vec_len);
368         } else {
369           d_tn->pod_init = __kmp_init_common_data(data_addr, d_tn->cmn_size);
370         }
371       } else {
372         if (d_tn->ct.ctor != 0) {
373           /* Construct from scratch so no prototype exists */
374           d_tn->obj_init = 0;
375         } else if (d_tn->cct.cctor != 0) {
376           /* Now data initialize the prototype since it was previously
377              registered */
378           d_tn->obj_init = (void *)__kmp_allocate(d_tn->cmn_size);
379           (void)(*d_tn->cct.cctor)(d_tn->obj_init, pc_addr);
380         } else {
381           d_tn->pod_init = __kmp_init_common_data(data_addr, d_tn->cmn_size);
382         }
383       }
384     }
385   } else {
386     struct shared_common **lnk_tn;
387 
388     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
389     d_tn->gbl_addr = pc_addr;
390     d_tn->cmn_size = pc_size;
391     d_tn->pod_init = __kmp_init_common_data(data_addr, pc_size);
392     /*
393             d_tn->obj_init = 0;  // AC: commented out because __kmp_allocate
394        zeroes the memory
395             d_tn->ct.ctor = 0;
396             d_tn->cct.cctor = 0;
397             d_tn->dt.dtor = 0;
398             d_tn->is_vec = FALSE;
399             d_tn->vec_len = 0L;
400     */
401     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(pc_addr)]);
402 
403     d_tn->next = *lnk_tn;
404     *lnk_tn = d_tn;
405   }
406 
407   tn->cmn_size = d_tn->cmn_size;
408 
409   if ((__kmp_foreign_tp) ? (KMP_INITIAL_GTID(gtid)) : (KMP_UBER_GTID(gtid))) {
410     tn->par_addr = (void *)pc_addr;
411   } else {
412     tn->par_addr = (void *)__kmp_allocate(tn->cmn_size);
413   }
414 
415   __kmp_release_lock(&__kmp_global_lock, gtid);
416 /* +++++++++ END OF CRITICAL SECTION +++++++++ */
417 
418 #ifdef USE_CHECKS_COMMON
419   if (pc_size > d_tn->cmn_size) {
420     KC_TRACE(
421         10, ("__kmp_threadprivate_insert: THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC
422              " ,%" KMP_UINTPTR_SPEC ")\n",
423              pc_addr, pc_size, d_tn->cmn_size));
424     KMP_FATAL(TPCommonBlocksInconsist);
425   }
426 #endif /* USE_CHECKS_COMMON */
427 
428   tt = &(__kmp_threads[gtid]->th.th_pri_common->data[KMP_HASH(pc_addr)]);
429 
430 #ifdef KMP_TASK_COMMON_DEBUG
431   if (*tt != 0) {
432     KC_TRACE(
433         10,
434         ("__kmp_threadprivate_insert: WARNING! thread#%d: collision on %p\n",
435          gtid, pc_addr));
436   }
437 #endif
438   tn->next = *tt;
439   *tt = tn;
440 
441 #ifdef KMP_TASK_COMMON_DEBUG
442   KC_TRACE(10,
443            ("__kmp_threadprivate_insert: thread#%d, inserted node %p on list\n",
444             gtid, pc_addr));
445   dump_list();
446 #endif
447 
448   /* Link the node into a simple list */
449 
450   tn->link = __kmp_threads[gtid]->th.th_pri_head;
451   __kmp_threads[gtid]->th.th_pri_head = tn;
452 
453   if ((__kmp_foreign_tp) ? (KMP_INITIAL_GTID(gtid)) : (KMP_UBER_GTID(gtid)))
454     return tn;
455 
456   /* if C++ object with copy constructor, use it;
457    * else if C++ object with constructor, use it for the non-master copies only;
458    * else use pod_init and memcpy
459    *
460    * C++ constructors need to be called once for each non-master thread on
461    * allocate
462    * C++ copy constructors need to be called once for each thread on allocate */
463 
464   /* C++ object with constructors/destructors; don't call constructors for
465      master thread though */
466   if (d_tn->is_vec) {
467     if (d_tn->ct.ctorv != 0) {
468       (void)(*d_tn->ct.ctorv)(tn->par_addr, d_tn->vec_len);
469     } else if (d_tn->cct.cctorv != 0) {
470       (void)(*d_tn->cct.cctorv)(tn->par_addr, d_tn->obj_init, d_tn->vec_len);
471     } else if (tn->par_addr != tn->gbl_addr) {
472       __kmp_copy_common_data(tn->par_addr, d_tn->pod_init);
473     }
474   } else {
475     if (d_tn->ct.ctor != 0) {
476       (void)(*d_tn->ct.ctor)(tn->par_addr);
477     } else if (d_tn->cct.cctor != 0) {
478       (void)(*d_tn->cct.cctor)(tn->par_addr, d_tn->obj_init);
479     } else if (tn->par_addr != tn->gbl_addr) {
480       __kmp_copy_common_data(tn->par_addr, d_tn->pod_init);
481     }
482   }
483   /* !BUILD_OPENMP_C
484       if (tn->par_addr != tn->gbl_addr)
485           __kmp_copy_common_data( tn->par_addr, d_tn->pod_init ); */
486 
487   return tn;
488 }
489 
490 /* ------------------------------------------------------------------------ */
491 /* We are currently parallel, and we know the thread id.                    */
492 /* ------------------------------------------------------------------------ */
493 
494 /*!
495  @ingroup THREADPRIVATE
496 
497  @param loc source location information
498  @param data  pointer to data being privatized
499  @param ctor  pointer to constructor function for data
500  @param cctor  pointer to copy constructor function for data
501  @param dtor  pointer to destructor function for data
502 
503  Register constructors and destructors for thread private data.
504  This function is called when executing in parallel, when we know the thread id.
505 */
506 void __kmpc_threadprivate_register(ident_t *loc, void *data, kmpc_ctor ctor,
507                                    kmpc_cctor cctor, kmpc_dtor dtor) {
508   struct shared_common *d_tn, **lnk_tn;
509 
510   KC_TRACE(10, ("__kmpc_threadprivate_register: called\n"));
511 
512 #ifdef USE_CHECKS_COMMON
513   /* copy constructor must be zero for current code gen (Nov 2002 - jph) */
514   KMP_ASSERT(cctor == 0);
515 #endif /* USE_CHECKS_COMMON */
516 
517   /* Only the global data table exists. */
518   d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, -1, data);
519 
520   if (d_tn == 0) {
521     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
522     d_tn->gbl_addr = data;
523 
524     d_tn->ct.ctor = ctor;
525     d_tn->cct.cctor = cctor;
526     d_tn->dt.dtor = dtor;
527     /*
528             d_tn->is_vec = FALSE;  // AC: commented out because __kmp_allocate
529        zeroes the memory
530             d_tn->vec_len = 0L;
531             d_tn->obj_init = 0;
532             d_tn->pod_init = 0;
533     */
534     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(data)]);
535 
536     d_tn->next = *lnk_tn;
537     *lnk_tn = d_tn;
538   }
539 }
540 
541 void *__kmpc_threadprivate(ident_t *loc, kmp_int32 global_tid, void *data,
542                            size_t size) {
543   void *ret;
544   struct private_common *tn;
545 
546   KC_TRACE(10, ("__kmpc_threadprivate: T#%d called\n", global_tid));
547 
548 #ifdef USE_CHECKS_COMMON
549   if (!__kmp_init_serial)
550     KMP_FATAL(RTLNotInitialized);
551 #endif /* USE_CHECKS_COMMON */
552 
553   if (!__kmp_threads[global_tid]->th.th_root->r.r_active && !__kmp_foreign_tp) {
554     /* The parallel address will NEVER overlap with the data_address */
555     /* dkp: 3rd arg to kmp_threadprivate_insert_private_data() is the
556      * data_address; use data_address = data */
557 
558     KC_TRACE(20, ("__kmpc_threadprivate: T#%d inserting private data\n",
559                   global_tid));
560     kmp_threadprivate_insert_private_data(global_tid, data, data, size);
561 
562     ret = data;
563   } else {
564     KC_TRACE(
565         50,
566         ("__kmpc_threadprivate: T#%d try to find private data at address %p\n",
567          global_tid, data));
568     tn = __kmp_threadprivate_find_task_common(
569         __kmp_threads[global_tid]->th.th_pri_common, global_tid, data);
570 
571     if (tn) {
572       KC_TRACE(20, ("__kmpc_threadprivate: T#%d found data\n", global_tid));
573 #ifdef USE_CHECKS_COMMON
574       if ((size_t)size > tn->cmn_size) {
575         KC_TRACE(10, ("THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC
576                       " ,%" KMP_UINTPTR_SPEC ")\n",
577                       data, size, tn->cmn_size));
578         KMP_FATAL(TPCommonBlocksInconsist);
579       }
580 #endif /* USE_CHECKS_COMMON */
581     } else {
582       /* The parallel address will NEVER overlap with the data_address */
583       /* dkp: 3rd arg to kmp_threadprivate_insert() is the data_address; use
584        * data_address = data */
585       KC_TRACE(20, ("__kmpc_threadprivate: T#%d inserting data\n", global_tid));
586       tn = kmp_threadprivate_insert(global_tid, data, data, size);
587     }
588 
589     ret = tn->par_addr;
590   }
591   KC_TRACE(10, ("__kmpc_threadprivate: T#%d exiting; return value = %p\n",
592                 global_tid, ret));
593 
594   return ret;
595 }
596 
597 /*!
598  @ingroup THREADPRIVATE
599  @param loc source location information
600  @param global_tid  global thread number
601  @param data  pointer to data to privatize
602  @param size  size of data to privatize
603  @param cache  pointer to cache
604  @return pointer to private storage
605 
606  Allocate private storage for threadprivate data.
607 */
608 void *
609 __kmpc_threadprivate_cached(ident_t *loc,
610                             kmp_int32 global_tid, // gtid.
611                             void *data, // Pointer to original global variable.
612                             size_t size, // Size of original global variable.
613                             void ***cache) {
614   KC_TRACE(10, ("__kmpc_threadprivate_cached: T#%d called with cache: %p, "
615                 "address: %p, size: %" KMP_SIZE_T_SPEC "\n",
616                 global_tid, *cache, data, size));
617 
618   if (TCR_PTR(*cache) == 0) {
619     __kmp_acquire_lock(&__kmp_global_lock, global_tid);
620 
621     if (TCR_PTR(*cache) == 0) {
622       __kmp_acquire_bootstrap_lock(&__kmp_tp_cached_lock);
623       __kmp_tp_cached = 1;
624       __kmp_release_bootstrap_lock(&__kmp_tp_cached_lock);
625       void **my_cache;
626       KMP_ITT_IGNORE(
627           my_cache = (void **)__kmp_allocate(
628               sizeof(void *) * __kmp_tp_capacity + sizeof(kmp_cached_addr_t)););
629       // No need to zero the allocated memory; __kmp_allocate does that.
630       KC_TRACE(
631           50,
632           ("__kmpc_threadprivate_cached: T#%d allocated cache at address %p\n",
633            global_tid, my_cache));
634 
635       /* TODO: free all this memory in __kmp_common_destroy using
636        * __kmp_threadpriv_cache_list */
637       /* Add address of mycache to linked list for cleanup later  */
638       kmp_cached_addr_t *tp_cache_addr;
639 
640       tp_cache_addr = (kmp_cached_addr_t *)&my_cache[__kmp_tp_capacity];
641       tp_cache_addr->addr = my_cache;
642       tp_cache_addr->next = __kmp_threadpriv_cache_list;
643       __kmp_threadpriv_cache_list = tp_cache_addr;
644 
645       KMP_MB();
646 
647       TCW_PTR(*cache, my_cache);
648 
649       KMP_MB();
650     }
651 
652     __kmp_release_lock(&__kmp_global_lock, global_tid);
653   }
654 
655   void *ret;
656   if ((ret = TCR_PTR((*cache)[global_tid])) == 0) {
657     ret = __kmpc_threadprivate(loc, global_tid, data, (size_t)size);
658 
659     TCW_PTR((*cache)[global_tid], ret);
660   }
661   KC_TRACE(10,
662            ("__kmpc_threadprivate_cached: T#%d exiting; return value = %p\n",
663             global_tid, ret));
664 
665   return ret;
666 }
667 
668 /*!
669  @ingroup THREADPRIVATE
670  @param loc source location information
671  @param data  pointer to data being privatized
672  @param ctor  pointer to constructor function for data
673  @param cctor  pointer to copy constructor function for data
674  @param dtor  pointer to destructor function for data
675  @param vector_length length of the vector (bytes or elements?)
676  Register vector constructors and destructors for thread private data.
677 */
678 void __kmpc_threadprivate_register_vec(ident_t *loc, void *data,
679                                        kmpc_ctor_vec ctor, kmpc_cctor_vec cctor,
680                                        kmpc_dtor_vec dtor,
681                                        size_t vector_length) {
682   struct shared_common *d_tn, **lnk_tn;
683 
684   KC_TRACE(10, ("__kmpc_threadprivate_register_vec: called\n"));
685 
686 #ifdef USE_CHECKS_COMMON
687   /* copy constructor must be zero for current code gen (Nov 2002 - jph) */
688   KMP_ASSERT(cctor == 0);
689 #endif /* USE_CHECKS_COMMON */
690 
691   d_tn = __kmp_find_shared_task_common(
692       &__kmp_threadprivate_d_table, -1,
693       data); /* Only the global data table exists. */
694 
695   if (d_tn == 0) {
696     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
697     d_tn->gbl_addr = data;
698 
699     d_tn->ct.ctorv = ctor;
700     d_tn->cct.cctorv = cctor;
701     d_tn->dt.dtorv = dtor;
702     d_tn->is_vec = TRUE;
703     d_tn->vec_len = (size_t)vector_length;
704     /*
705             d_tn->obj_init = 0;  // AC: commented out because __kmp_allocate
706        zeroes the memory
707             d_tn->pod_init = 0;
708     */
709     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(data)]);
710 
711     d_tn->next = *lnk_tn;
712     *lnk_tn = d_tn;
713   }
714 }
715