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