17cc577a4SJonathan Peyton /*
2de4749b7SJonathan Peyton  * kmp_threadprivate.cpp -- OpenMP threadprivate support library
37cc577a4SJonathan Peyton  */
47cc577a4SJonathan Peyton 
57cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
67cc577a4SJonathan Peyton //
757b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
857b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
957b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
107cc577a4SJonathan Peyton //
117cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
127cc577a4SJonathan Peyton 
137cc577a4SJonathan Peyton #include "kmp.h"
147cc577a4SJonathan Peyton #include "kmp_i18n.h"
153041982dSJonathan Peyton #include "kmp_itt.h"
167cc577a4SJonathan Peyton 
177cc577a4SJonathan Peyton #define USE_CHECKS_COMMON
187cc577a4SJonathan Peyton 
197cc577a4SJonathan Peyton #define KMP_INLINE_SUBR 1
207cc577a4SJonathan Peyton 
213041982dSJonathan Peyton void kmp_threadprivate_insert_private_data(int gtid, void *pc_addr,
223041982dSJonathan Peyton                                            void *data_addr, size_t pc_size);
233041982dSJonathan Peyton struct private_common *kmp_threadprivate_insert(int gtid, void *pc_addr,
243041982dSJonathan Peyton                                                 void *data_addr,
253041982dSJonathan Peyton                                                 size_t pc_size);
267cc577a4SJonathan Peyton 
277cc577a4SJonathan Peyton struct shared_table __kmp_threadprivate_d_table;
287cc577a4SJonathan Peyton 
297cc577a4SJonathan Peyton static
307cc577a4SJonathan Peyton #ifdef KMP_INLINE_SUBR
317cc577a4SJonathan Peyton     __forceinline
327cc577a4SJonathan Peyton #endif
337cc577a4SJonathan Peyton     struct private_common *
__kmp_threadprivate_find_task_common(struct common_table * tbl,int gtid,void * pc_addr)343041982dSJonathan Peyton     __kmp_threadprivate_find_task_common(struct common_table *tbl, int gtid,
353041982dSJonathan Peyton                                          void *pc_addr)
367cc577a4SJonathan Peyton 
377cc577a4SJonathan Peyton {
387cc577a4SJonathan Peyton   struct private_common *tn;
397cc577a4SJonathan Peyton 
407cc577a4SJonathan Peyton #ifdef KMP_TASK_COMMON_DEBUG
413041982dSJonathan Peyton   KC_TRACE(10, ("__kmp_threadprivate_find_task_common: thread#%d, called with "
423041982dSJonathan Peyton                 "address %p\n",
437cc577a4SJonathan Peyton                 gtid, pc_addr));
447cc577a4SJonathan Peyton   dump_list();
457cc577a4SJonathan Peyton #endif
467cc577a4SJonathan Peyton 
477cc577a4SJonathan Peyton   for (tn = tbl->data[KMP_HASH(pc_addr)]; tn; tn = tn->next) {
487cc577a4SJonathan Peyton     if (tn->gbl_addr == pc_addr) {
497cc577a4SJonathan Peyton #ifdef KMP_TASK_COMMON_DEBUG
503041982dSJonathan Peyton       KC_TRACE(10, ("__kmp_threadprivate_find_task_common: thread#%d, found "
513041982dSJonathan Peyton                     "node %p on list\n",
527cc577a4SJonathan Peyton                     gtid, pc_addr));
537cc577a4SJonathan Peyton #endif
547cc577a4SJonathan Peyton       return tn;
557cc577a4SJonathan Peyton     }
567cc577a4SJonathan Peyton   }
577cc577a4SJonathan Peyton   return 0;
587cc577a4SJonathan Peyton }
597cc577a4SJonathan Peyton 
607cc577a4SJonathan Peyton static
617cc577a4SJonathan Peyton #ifdef KMP_INLINE_SUBR
627cc577a4SJonathan Peyton     __forceinline
637cc577a4SJonathan Peyton #endif
647cc577a4SJonathan Peyton     struct shared_common *
__kmp_find_shared_task_common(struct shared_table * tbl,int gtid,void * pc_addr)653041982dSJonathan Peyton     __kmp_find_shared_task_common(struct shared_table *tbl, int gtid,
663041982dSJonathan Peyton                                   void *pc_addr) {
677cc577a4SJonathan Peyton   struct shared_common *tn;
687cc577a4SJonathan Peyton 
697cc577a4SJonathan Peyton   for (tn = tbl->data[KMP_HASH(pc_addr)]; tn; tn = tn->next) {
707cc577a4SJonathan Peyton     if (tn->gbl_addr == pc_addr) {
717cc577a4SJonathan Peyton #ifdef KMP_TASK_COMMON_DEBUG
723041982dSJonathan Peyton       KC_TRACE(
733041982dSJonathan Peyton           10,
743041982dSJonathan Peyton           ("__kmp_find_shared_task_common: thread#%d, found node %p on list\n",
757cc577a4SJonathan Peyton            gtid, pc_addr));
767cc577a4SJonathan Peyton #endif
777cc577a4SJonathan Peyton       return tn;
787cc577a4SJonathan Peyton     }
797cc577a4SJonathan Peyton   }
807cc577a4SJonathan Peyton   return 0;
817cc577a4SJonathan Peyton }
827cc577a4SJonathan Peyton 
833041982dSJonathan Peyton // Create a template for the data initialized storage. Either the template is
843041982dSJonathan Peyton // NULL indicating zero fill, or the template is a copy of the original data.
__kmp_init_common_data(void * pc_addr,size_t pc_size)853041982dSJonathan Peyton static struct private_data *__kmp_init_common_data(void *pc_addr,
863041982dSJonathan Peyton                                                    size_t pc_size) {
877cc577a4SJonathan Peyton   struct private_data *d;
887cc577a4SJonathan Peyton   size_t i;
897cc577a4SJonathan Peyton   char *p;
907cc577a4SJonathan Peyton 
917cc577a4SJonathan Peyton   d = (struct private_data *)__kmp_allocate(sizeof(struct private_data));
927cc577a4SJonathan Peyton   /*
933041982dSJonathan Peyton       d->data = 0;  // AC: commented out because __kmp_allocate zeroes the
943041982dSJonathan Peyton      memory
957cc577a4SJonathan Peyton       d->next = 0;
967cc577a4SJonathan Peyton   */
977cc577a4SJonathan Peyton   d->size = pc_size;
987cc577a4SJonathan Peyton   d->more = 1;
997cc577a4SJonathan Peyton 
1007cc577a4SJonathan Peyton   p = (char *)pc_addr;
1017cc577a4SJonathan Peyton 
1027cc577a4SJonathan Peyton   for (i = pc_size; i > 0; --i) {
1037cc577a4SJonathan Peyton     if (*p++ != '\0') {
1047cc577a4SJonathan Peyton       d->data = __kmp_allocate(pc_size);
1057cc577a4SJonathan Peyton       KMP_MEMCPY(d->data, pc_addr, pc_size);
1067cc577a4SJonathan Peyton       break;
1077cc577a4SJonathan Peyton     }
1087cc577a4SJonathan Peyton   }
1097cc577a4SJonathan Peyton 
1107cc577a4SJonathan Peyton   return d;
1117cc577a4SJonathan Peyton }
1127cc577a4SJonathan Peyton 
1133041982dSJonathan Peyton // Initialize the data area from the template.
__kmp_copy_common_data(void * pc_addr,struct private_data * d)1143041982dSJonathan Peyton static void __kmp_copy_common_data(void *pc_addr, struct private_data *d) {
1157cc577a4SJonathan Peyton   char *addr = (char *)pc_addr;
1167cc577a4SJonathan Peyton 
1176b316febSTerry Wilmarth   for (size_t offset = 0; d != 0; d = d->next) {
1186b316febSTerry Wilmarth     for (int i = d->more; i > 0; --i) {
1197cc577a4SJonathan Peyton       if (d->data == 0)
1207cc577a4SJonathan Peyton         memset(&addr[offset], '\0', d->size);
1217cc577a4SJonathan Peyton       else
1227cc577a4SJonathan Peyton         KMP_MEMCPY(&addr[offset], d->data, d->size);
1237cc577a4SJonathan Peyton       offset += d->size;
1247cc577a4SJonathan Peyton     }
1257cc577a4SJonathan Peyton   }
1267cc577a4SJonathan Peyton }
1277cc577a4SJonathan Peyton 
1287cc577a4SJonathan Peyton /* we are called from __kmp_serial_initialize() with __kmp_initz_lock held. */
__kmp_common_initialize(void)1293041982dSJonathan Peyton void __kmp_common_initialize(void) {
1307cc577a4SJonathan Peyton   if (!TCR_4(__kmp_init_common)) {
1317cc577a4SJonathan Peyton     int q;
1327cc577a4SJonathan Peyton #ifdef KMP_DEBUG
1337cc577a4SJonathan Peyton     int gtid;
1347cc577a4SJonathan Peyton #endif
1357cc577a4SJonathan Peyton 
1367cc577a4SJonathan Peyton     __kmp_threadpriv_cache_list = NULL;
1377cc577a4SJonathan Peyton 
1387cc577a4SJonathan Peyton #ifdef KMP_DEBUG
1397cc577a4SJonathan Peyton     /* verify the uber masters were initialized */
1407cc577a4SJonathan Peyton     for (gtid = 0; gtid < __kmp_threads_capacity; gtid++)
1417cc577a4SJonathan Peyton       if (__kmp_root[gtid]) {
1427cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(__kmp_root[gtid]->r.r_uber_thread);
1437cc577a4SJonathan Peyton         for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q)
1443041982dSJonathan Peyton           KMP_DEBUG_ASSERT(
1453041982dSJonathan Peyton               !__kmp_root[gtid]->r.r_uber_thread->th.th_pri_common->data[q]);
1463041982dSJonathan Peyton         /*                    __kmp_root[ gitd ]-> r.r_uber_thread ->
1473041982dSJonathan Peyton          * th.th_pri_common -> data[ q ] = 0;*/
1487cc577a4SJonathan Peyton       }
1497cc577a4SJonathan Peyton #endif /* KMP_DEBUG */
1507cc577a4SJonathan Peyton 
1517cc577a4SJonathan Peyton     for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q)
1527cc577a4SJonathan Peyton       __kmp_threadprivate_d_table.data[q] = 0;
1537cc577a4SJonathan Peyton 
1547cc577a4SJonathan Peyton     TCW_4(__kmp_init_common, TRUE);
1557cc577a4SJonathan Peyton   }
1567cc577a4SJonathan Peyton }
1577cc577a4SJonathan Peyton 
1587cc577a4SJonathan Peyton /* Call all destructors for threadprivate data belonging to all threads.
1597cc577a4SJonathan Peyton    Currently unused! */
__kmp_common_destroy(void)1603041982dSJonathan Peyton void __kmp_common_destroy(void) {
1617cc577a4SJonathan Peyton   if (TCR_4(__kmp_init_common)) {
1627cc577a4SJonathan Peyton     int q;
1637cc577a4SJonathan Peyton 
1647cc577a4SJonathan Peyton     TCW_4(__kmp_init_common, FALSE);
1657cc577a4SJonathan Peyton 
1667cc577a4SJonathan Peyton     for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) {
1677cc577a4SJonathan Peyton       int gtid;
1687cc577a4SJonathan Peyton       struct private_common *tn;
1697cc577a4SJonathan Peyton       struct shared_common *d_tn;
1707cc577a4SJonathan Peyton 
1713041982dSJonathan Peyton       /* C++ destructors need to be called once per thread before exiting.
172*97d000cfStlwilmar          Don't call destructors for primary thread though unless we used copy
1733041982dSJonathan Peyton          constructor */
1747cc577a4SJonathan Peyton 
1753041982dSJonathan Peyton       for (d_tn = __kmp_threadprivate_d_table.data[q]; d_tn;
1763041982dSJonathan Peyton            d_tn = d_tn->next) {
1777cc577a4SJonathan Peyton         if (d_tn->is_vec) {
1787cc577a4SJonathan Peyton           if (d_tn->dt.dtorv != 0) {
1797cc577a4SJonathan Peyton             for (gtid = 0; gtid < __kmp_all_nth; ++gtid) {
1807cc577a4SJonathan Peyton               if (__kmp_threads[gtid]) {
1813041982dSJonathan Peyton                 if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid))
1823041982dSJonathan Peyton                                        : (!KMP_UBER_GTID(gtid))) {
1833041982dSJonathan Peyton                   tn = __kmp_threadprivate_find_task_common(
1843041982dSJonathan Peyton                       __kmp_threads[gtid]->th.th_pri_common, gtid,
1853041982dSJonathan Peyton                       d_tn->gbl_addr);
1867cc577a4SJonathan Peyton                   if (tn) {
1877cc577a4SJonathan Peyton                     (*d_tn->dt.dtorv)(tn->par_addr, d_tn->vec_len);
1887cc577a4SJonathan Peyton                   }
1897cc577a4SJonathan Peyton                 }
1907cc577a4SJonathan Peyton               }
1917cc577a4SJonathan Peyton             }
1927cc577a4SJonathan Peyton             if (d_tn->obj_init != 0) {
1937cc577a4SJonathan Peyton               (*d_tn->dt.dtorv)(d_tn->obj_init, d_tn->vec_len);
1947cc577a4SJonathan Peyton             }
1957cc577a4SJonathan Peyton           }
1967cc577a4SJonathan Peyton         } else {
1977cc577a4SJonathan Peyton           if (d_tn->dt.dtor != 0) {
1987cc577a4SJonathan Peyton             for (gtid = 0; gtid < __kmp_all_nth; ++gtid) {
1997cc577a4SJonathan Peyton               if (__kmp_threads[gtid]) {
2003041982dSJonathan Peyton                 if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid))
2013041982dSJonathan Peyton                                        : (!KMP_UBER_GTID(gtid))) {
2023041982dSJonathan Peyton                   tn = __kmp_threadprivate_find_task_common(
2033041982dSJonathan Peyton                       __kmp_threads[gtid]->th.th_pri_common, gtid,
2043041982dSJonathan Peyton                       d_tn->gbl_addr);
2057cc577a4SJonathan Peyton                   if (tn) {
2067cc577a4SJonathan Peyton                     (*d_tn->dt.dtor)(tn->par_addr);
2077cc577a4SJonathan Peyton                   }
2087cc577a4SJonathan Peyton                 }
2097cc577a4SJonathan Peyton               }
2107cc577a4SJonathan Peyton             }
2117cc577a4SJonathan Peyton             if (d_tn->obj_init != 0) {
2127cc577a4SJonathan Peyton               (*d_tn->dt.dtor)(d_tn->obj_init);
2137cc577a4SJonathan Peyton             }
2147cc577a4SJonathan Peyton           }
2157cc577a4SJonathan Peyton         }
2167cc577a4SJonathan Peyton       }
2177cc577a4SJonathan Peyton       __kmp_threadprivate_d_table.data[q] = 0;
2187cc577a4SJonathan Peyton     }
2197cc577a4SJonathan Peyton   }
2207cc577a4SJonathan Peyton }
2217cc577a4SJonathan Peyton 
2227cc577a4SJonathan Peyton /* Call all destructors for threadprivate data belonging to this thread */
__kmp_common_destroy_gtid(int gtid)2233041982dSJonathan Peyton void __kmp_common_destroy_gtid(int gtid) {
2247cc577a4SJonathan Peyton   struct private_common *tn;
2257cc577a4SJonathan Peyton   struct shared_common *d_tn;
2267cc577a4SJonathan Peyton 
227f0a1c65fSJonas Hahnfeld   if (!TCR_4(__kmp_init_gtid)) {
228f0a1c65fSJonas Hahnfeld     // This is possible when one of multiple roots initiates early library
229f0a1c65fSJonas Hahnfeld     // termination in a sequential region while other teams are active, and its
230f0a1c65fSJonas Hahnfeld     // child threads are about to end.
231f0a1c65fSJonas Hahnfeld     return;
232f0a1c65fSJonas Hahnfeld   }
233f0a1c65fSJonas Hahnfeld 
2347cc577a4SJonathan Peyton   KC_TRACE(10, ("__kmp_common_destroy_gtid: T#%d called\n", gtid));
2353041982dSJonathan Peyton   if ((__kmp_foreign_tp) ? (!KMP_INITIAL_GTID(gtid)) : (!KMP_UBER_GTID(gtid))) {
2367cc577a4SJonathan Peyton 
2377cc577a4SJonathan Peyton     if (TCR_4(__kmp_init_common)) {
2387cc577a4SJonathan Peyton 
2397cc577a4SJonathan Peyton       /* Cannot do this here since not all threads have destroyed their data */
2407cc577a4SJonathan Peyton       /* TCW_4(__kmp_init_common, FALSE); */
2417cc577a4SJonathan Peyton 
2427cc577a4SJonathan Peyton       for (tn = __kmp_threads[gtid]->th.th_pri_head; tn; tn = tn->link) {
2437cc577a4SJonathan Peyton 
2443041982dSJonathan Peyton         d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, gtid,
2453041982dSJonathan Peyton                                              tn->gbl_addr);
246917f8421SAndreyChurbanov         if (d_tn == NULL)
247917f8421SAndreyChurbanov           continue;
2487cc577a4SJonathan Peyton         if (d_tn->is_vec) {
2497cc577a4SJonathan Peyton           if (d_tn->dt.dtorv != 0) {
2507cc577a4SJonathan Peyton             (void)(*d_tn->dt.dtorv)(tn->par_addr, d_tn->vec_len);
2517cc577a4SJonathan Peyton           }
2527cc577a4SJonathan Peyton           if (d_tn->obj_init != 0) {
2537cc577a4SJonathan Peyton             (void)(*d_tn->dt.dtorv)(d_tn->obj_init, d_tn->vec_len);
2547cc577a4SJonathan Peyton           }
2557cc577a4SJonathan Peyton         } else {
2567cc577a4SJonathan Peyton           if (d_tn->dt.dtor != 0) {
2577cc577a4SJonathan Peyton             (void)(*d_tn->dt.dtor)(tn->par_addr);
2587cc577a4SJonathan Peyton           }
2597cc577a4SJonathan Peyton           if (d_tn->obj_init != 0) {
2607cc577a4SJonathan Peyton             (void)(*d_tn->dt.dtor)(d_tn->obj_init);
2617cc577a4SJonathan Peyton           }
2627cc577a4SJonathan Peyton         }
2637cc577a4SJonathan Peyton       }
2643041982dSJonathan Peyton       KC_TRACE(30, ("__kmp_common_destroy_gtid: T#%d threadprivate destructors "
2653041982dSJonathan Peyton                     "complete\n",
2667cc577a4SJonathan Peyton                     gtid));
2677cc577a4SJonathan Peyton     }
2687cc577a4SJonathan Peyton   }
2697cc577a4SJonathan Peyton }
2707cc577a4SJonathan Peyton 
2717cc577a4SJonathan Peyton #ifdef KMP_TASK_COMMON_DEBUG
dump_list(void)2723041982dSJonathan Peyton static void dump_list(void) {
2737cc577a4SJonathan Peyton   int p, q;
2747cc577a4SJonathan Peyton 
2757cc577a4SJonathan Peyton   for (p = 0; p < __kmp_all_nth; ++p) {
2763041982dSJonathan Peyton     if (!__kmp_threads[p])
2773041982dSJonathan Peyton       continue;
2787cc577a4SJonathan Peyton     for (q = 0; q < KMP_HASH_TABLE_SIZE; ++q) {
2797cc577a4SJonathan Peyton       if (__kmp_threads[p]->th.th_pri_common->data[q]) {
2807cc577a4SJonathan Peyton         struct private_common *tn;
2817cc577a4SJonathan Peyton 
2827cc577a4SJonathan Peyton         KC_TRACE(10, ("\tdump_list: gtid:%d addresses\n", p));
2837cc577a4SJonathan Peyton 
2843041982dSJonathan Peyton         for (tn = __kmp_threads[p]->th.th_pri_common->data[q]; tn;
2853041982dSJonathan Peyton              tn = tn->next) {
2863041982dSJonathan Peyton           KC_TRACE(10,
2873041982dSJonathan Peyton                    ("\tdump_list: THREADPRIVATE: Serial %p -> Parallel %p\n",
2887cc577a4SJonathan Peyton                     tn->gbl_addr, tn->par_addr));
2897cc577a4SJonathan Peyton         }
2907cc577a4SJonathan Peyton       }
2917cc577a4SJonathan Peyton     }
2927cc577a4SJonathan Peyton   }
2937cc577a4SJonathan Peyton }
2947cc577a4SJonathan Peyton #endif /* KMP_TASK_COMMON_DEBUG */
2957cc577a4SJonathan Peyton 
2963041982dSJonathan Peyton // NOTE: this routine is to be called only from the serial part of the program.
kmp_threadprivate_insert_private_data(int gtid,void * pc_addr,void * data_addr,size_t pc_size)2973041982dSJonathan Peyton void kmp_threadprivate_insert_private_data(int gtid, void *pc_addr,
2983041982dSJonathan Peyton                                            void *data_addr, size_t pc_size) {
2997cc577a4SJonathan Peyton   struct shared_common **lnk_tn, *d_tn;
3007cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_threads[gtid] &&
3017cc577a4SJonathan Peyton                    __kmp_threads[gtid]->th.th_root->r.r_active == 0);
3027cc577a4SJonathan Peyton 
3033041982dSJonathan Peyton   d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, gtid,
3043041982dSJonathan Peyton                                        pc_addr);
3057cc577a4SJonathan Peyton 
3067cc577a4SJonathan Peyton   if (d_tn == 0) {
3077cc577a4SJonathan Peyton     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
3087cc577a4SJonathan Peyton 
3097cc577a4SJonathan Peyton     d_tn->gbl_addr = pc_addr;
3107cc577a4SJonathan Peyton     d_tn->pod_init = __kmp_init_common_data(data_addr, pc_size);
3117cc577a4SJonathan Peyton     /*
3123041982dSJonathan Peyton             d_tn->obj_init = 0;  // AC: commented out because __kmp_allocate
3133041982dSJonathan Peyton        zeroes the memory
3147cc577a4SJonathan Peyton             d_tn->ct.ctor = 0;
3157cc577a4SJonathan Peyton             d_tn->cct.cctor = 0;;
3167cc577a4SJonathan Peyton             d_tn->dt.dtor = 0;
3177cc577a4SJonathan Peyton             d_tn->is_vec = FALSE;
3187cc577a4SJonathan Peyton             d_tn->vec_len = 0L;
3197cc577a4SJonathan Peyton     */
3207cc577a4SJonathan Peyton     d_tn->cmn_size = pc_size;
3217cc577a4SJonathan Peyton 
3227cc577a4SJonathan Peyton     __kmp_acquire_lock(&__kmp_global_lock, gtid);
3237cc577a4SJonathan Peyton 
3247cc577a4SJonathan Peyton     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(pc_addr)]);
3257cc577a4SJonathan Peyton 
3267cc577a4SJonathan Peyton     d_tn->next = *lnk_tn;
3277cc577a4SJonathan Peyton     *lnk_tn = d_tn;
3287cc577a4SJonathan Peyton 
3297cc577a4SJonathan Peyton     __kmp_release_lock(&__kmp_global_lock, gtid);
3307cc577a4SJonathan Peyton   }
3317cc577a4SJonathan Peyton }
3327cc577a4SJonathan Peyton 
kmp_threadprivate_insert(int gtid,void * pc_addr,void * data_addr,size_t pc_size)3333041982dSJonathan Peyton struct private_common *kmp_threadprivate_insert(int gtid, void *pc_addr,
3343041982dSJonathan Peyton                                                 void *data_addr,
3353041982dSJonathan Peyton                                                 size_t pc_size) {
3367cc577a4SJonathan Peyton   struct private_common *tn, **tt;
3377cc577a4SJonathan Peyton   struct shared_common *d_tn;
3387cc577a4SJonathan Peyton 
3397cc577a4SJonathan Peyton   /* +++++++++ START OF CRITICAL SECTION +++++++++ */
3407cc577a4SJonathan Peyton   __kmp_acquire_lock(&__kmp_global_lock, gtid);
3417cc577a4SJonathan Peyton 
3427cc577a4SJonathan Peyton   tn = (struct private_common *)__kmp_allocate(sizeof(struct private_common));
3437cc577a4SJonathan Peyton 
3447cc577a4SJonathan Peyton   tn->gbl_addr = pc_addr;
3457cc577a4SJonathan Peyton 
3463041982dSJonathan Peyton   d_tn = __kmp_find_shared_task_common(
3473041982dSJonathan Peyton       &__kmp_threadprivate_d_table, gtid,
3483041982dSJonathan Peyton       pc_addr); /* Only the MASTER data table exists. */
3497cc577a4SJonathan Peyton 
3507cc577a4SJonathan Peyton   if (d_tn != 0) {
3517cc577a4SJonathan Peyton     /* This threadprivate variable has already been seen. */
3527cc577a4SJonathan Peyton 
3537cc577a4SJonathan Peyton     if (d_tn->pod_init == 0 && d_tn->obj_init == 0) {
3547cc577a4SJonathan Peyton       d_tn->cmn_size = pc_size;
3557cc577a4SJonathan Peyton 
3567cc577a4SJonathan Peyton       if (d_tn->is_vec) {
3577cc577a4SJonathan Peyton         if (d_tn->ct.ctorv != 0) {
3587cc577a4SJonathan Peyton           /* Construct from scratch so no prototype exists */
3597cc577a4SJonathan Peyton           d_tn->obj_init = 0;
3603041982dSJonathan Peyton         } else if (d_tn->cct.cctorv != 0) {
3613041982dSJonathan Peyton           /* Now data initialize the prototype since it was previously
3623041982dSJonathan Peyton            * registered */
3637cc577a4SJonathan Peyton           d_tn->obj_init = (void *)__kmp_allocate(d_tn->cmn_size);
3647cc577a4SJonathan Peyton           (void)(*d_tn->cct.cctorv)(d_tn->obj_init, pc_addr, d_tn->vec_len);
3653041982dSJonathan Peyton         } else {
3667cc577a4SJonathan Peyton           d_tn->pod_init = __kmp_init_common_data(data_addr, d_tn->cmn_size);
3677cc577a4SJonathan Peyton         }
3687cc577a4SJonathan Peyton       } else {
3697cc577a4SJonathan Peyton         if (d_tn->ct.ctor != 0) {
3707cc577a4SJonathan Peyton           /* Construct from scratch so no prototype exists */
3717cc577a4SJonathan Peyton           d_tn->obj_init = 0;
3723041982dSJonathan Peyton         } else if (d_tn->cct.cctor != 0) {
3733041982dSJonathan Peyton           /* Now data initialize the prototype since it was previously
3743041982dSJonathan Peyton              registered */
3757cc577a4SJonathan Peyton           d_tn->obj_init = (void *)__kmp_allocate(d_tn->cmn_size);
3767cc577a4SJonathan Peyton           (void)(*d_tn->cct.cctor)(d_tn->obj_init, pc_addr);
3773041982dSJonathan Peyton         } else {
3787cc577a4SJonathan Peyton           d_tn->pod_init = __kmp_init_common_data(data_addr, d_tn->cmn_size);
3797cc577a4SJonathan Peyton         }
3807cc577a4SJonathan Peyton       }
3817cc577a4SJonathan Peyton     }
3823041982dSJonathan Peyton   } else {
3837cc577a4SJonathan Peyton     struct shared_common **lnk_tn;
3847cc577a4SJonathan Peyton 
3857cc577a4SJonathan Peyton     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
3867cc577a4SJonathan Peyton     d_tn->gbl_addr = pc_addr;
3877cc577a4SJonathan Peyton     d_tn->cmn_size = pc_size;
3887cc577a4SJonathan Peyton     d_tn->pod_init = __kmp_init_common_data(data_addr, pc_size);
3897cc577a4SJonathan Peyton     /*
3903041982dSJonathan Peyton             d_tn->obj_init = 0;  // AC: commented out because __kmp_allocate
3913041982dSJonathan Peyton        zeroes the memory
3927cc577a4SJonathan Peyton             d_tn->ct.ctor = 0;
3937cc577a4SJonathan Peyton             d_tn->cct.cctor = 0;
3947cc577a4SJonathan Peyton             d_tn->dt.dtor = 0;
3957cc577a4SJonathan Peyton             d_tn->is_vec = FALSE;
3967cc577a4SJonathan Peyton             d_tn->vec_len = 0L;
3977cc577a4SJonathan Peyton     */
3987cc577a4SJonathan Peyton     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(pc_addr)]);
3997cc577a4SJonathan Peyton 
4007cc577a4SJonathan Peyton     d_tn->next = *lnk_tn;
4017cc577a4SJonathan Peyton     *lnk_tn = d_tn;
4027cc577a4SJonathan Peyton   }
4037cc577a4SJonathan Peyton 
4047cc577a4SJonathan Peyton   tn->cmn_size = d_tn->cmn_size;
4057cc577a4SJonathan Peyton 
4067cc577a4SJonathan Peyton   if ((__kmp_foreign_tp) ? (KMP_INITIAL_GTID(gtid)) : (KMP_UBER_GTID(gtid))) {
4077cc577a4SJonathan Peyton     tn->par_addr = (void *)pc_addr;
4083041982dSJonathan Peyton   } else {
4097cc577a4SJonathan Peyton     tn->par_addr = (void *)__kmp_allocate(tn->cmn_size);
4107cc577a4SJonathan Peyton   }
4117cc577a4SJonathan Peyton 
4127cc577a4SJonathan Peyton   __kmp_release_lock(&__kmp_global_lock, gtid);
4137cc577a4SJonathan Peyton   /* +++++++++ END OF CRITICAL SECTION +++++++++ */
4147cc577a4SJonathan Peyton 
4157cc577a4SJonathan Peyton #ifdef USE_CHECKS_COMMON
4167cc577a4SJonathan Peyton   if (pc_size > d_tn->cmn_size) {
4173041982dSJonathan Peyton     KC_TRACE(
4183041982dSJonathan Peyton         10, ("__kmp_threadprivate_insert: THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC
4193041982dSJonathan Peyton              " ,%" KMP_UINTPTR_SPEC ")\n",
4207cc577a4SJonathan Peyton              pc_addr, pc_size, d_tn->cmn_size));
4217cc577a4SJonathan Peyton     KMP_FATAL(TPCommonBlocksInconsist);
4227cc577a4SJonathan Peyton   }
4237cc577a4SJonathan Peyton #endif /* USE_CHECKS_COMMON */
4247cc577a4SJonathan Peyton 
4257cc577a4SJonathan Peyton   tt = &(__kmp_threads[gtid]->th.th_pri_common->data[KMP_HASH(pc_addr)]);
4267cc577a4SJonathan Peyton 
4277cc577a4SJonathan Peyton #ifdef KMP_TASK_COMMON_DEBUG
4287cc577a4SJonathan Peyton   if (*tt != 0) {
4293041982dSJonathan Peyton     KC_TRACE(
4303041982dSJonathan Peyton         10,
4313041982dSJonathan Peyton         ("__kmp_threadprivate_insert: WARNING! thread#%d: collision on %p\n",
4327cc577a4SJonathan Peyton          gtid, pc_addr));
4337cc577a4SJonathan Peyton   }
4347cc577a4SJonathan Peyton #endif
4357cc577a4SJonathan Peyton   tn->next = *tt;
4367cc577a4SJonathan Peyton   *tt = tn;
4377cc577a4SJonathan Peyton 
4387cc577a4SJonathan Peyton #ifdef KMP_TASK_COMMON_DEBUG
4393041982dSJonathan Peyton   KC_TRACE(10,
4403041982dSJonathan Peyton            ("__kmp_threadprivate_insert: thread#%d, inserted node %p on list\n",
4417cc577a4SJonathan Peyton             gtid, pc_addr));
4427cc577a4SJonathan Peyton   dump_list();
4437cc577a4SJonathan Peyton #endif
4447cc577a4SJonathan Peyton 
4457cc577a4SJonathan Peyton   /* Link the node into a simple list */
4467cc577a4SJonathan Peyton 
4477cc577a4SJonathan Peyton   tn->link = __kmp_threads[gtid]->th.th_pri_head;
4487cc577a4SJonathan Peyton   __kmp_threads[gtid]->th.th_pri_head = tn;
4497cc577a4SJonathan Peyton 
4507cc577a4SJonathan Peyton   if ((__kmp_foreign_tp) ? (KMP_INITIAL_GTID(gtid)) : (KMP_UBER_GTID(gtid)))
4517cc577a4SJonathan Peyton     return tn;
4527cc577a4SJonathan Peyton 
4533041982dSJonathan Peyton   /* if C++ object with copy constructor, use it;
454*97d000cfStlwilmar    * else if C++ object with constructor, use it for the non-primary thread
455*97d000cfStlwilmar      copies only;
4567cc577a4SJonathan Peyton    * else use pod_init and memcpy
4577cc577a4SJonathan Peyton    *
458*97d000cfStlwilmar    * C++ constructors need to be called once for each non-primary thread on
4593041982dSJonathan Peyton    * allocate
4603041982dSJonathan Peyton    * C++ copy constructors need to be called once for each thread on allocate */
4617cc577a4SJonathan Peyton 
4623041982dSJonathan Peyton   /* C++ object with constructors/destructors; don't call constructors for
463*97d000cfStlwilmar      primary thread though */
4647cc577a4SJonathan Peyton   if (d_tn->is_vec) {
4657cc577a4SJonathan Peyton     if (d_tn->ct.ctorv != 0) {
4667cc577a4SJonathan Peyton       (void)(*d_tn->ct.ctorv)(tn->par_addr, d_tn->vec_len);
4677cc577a4SJonathan Peyton     } else if (d_tn->cct.cctorv != 0) {
4687cc577a4SJonathan Peyton       (void)(*d_tn->cct.cctorv)(tn->par_addr, d_tn->obj_init, d_tn->vec_len);
4697cc577a4SJonathan Peyton     } else if (tn->par_addr != tn->gbl_addr) {
4707cc577a4SJonathan Peyton       __kmp_copy_common_data(tn->par_addr, d_tn->pod_init);
4717cc577a4SJonathan Peyton     }
4727cc577a4SJonathan Peyton   } else {
4737cc577a4SJonathan Peyton     if (d_tn->ct.ctor != 0) {
4747cc577a4SJonathan Peyton       (void)(*d_tn->ct.ctor)(tn->par_addr);
4757cc577a4SJonathan Peyton     } else if (d_tn->cct.cctor != 0) {
4767cc577a4SJonathan Peyton       (void)(*d_tn->cct.cctor)(tn->par_addr, d_tn->obj_init);
4777cc577a4SJonathan Peyton     } else if (tn->par_addr != tn->gbl_addr) {
4787cc577a4SJonathan Peyton       __kmp_copy_common_data(tn->par_addr, d_tn->pod_init);
4797cc577a4SJonathan Peyton     }
4807cc577a4SJonathan Peyton   }
4817cc577a4SJonathan Peyton   /* !BUILD_OPENMP_C
4827cc577a4SJonathan Peyton       if (tn->par_addr != tn->gbl_addr)
4837cc577a4SJonathan Peyton           __kmp_copy_common_data( tn->par_addr, d_tn->pod_init ); */
4847cc577a4SJonathan Peyton 
4857cc577a4SJonathan Peyton   return tn;
4867cc577a4SJonathan Peyton }
4877cc577a4SJonathan Peyton 
4887cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
4897cc577a4SJonathan Peyton /* We are currently parallel, and we know the thread id.                    */
4907cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
4917cc577a4SJonathan Peyton 
4927cc577a4SJonathan Peyton /*!
4937cc577a4SJonathan Peyton  @ingroup THREADPRIVATE
4947cc577a4SJonathan Peyton 
4957cc577a4SJonathan Peyton  @param loc source location information
4967cc577a4SJonathan Peyton  @param data  pointer to data being privatized
4977cc577a4SJonathan Peyton  @param ctor  pointer to constructor function for data
4987cc577a4SJonathan Peyton  @param cctor  pointer to copy constructor function for data
4997cc577a4SJonathan Peyton  @param dtor  pointer to destructor function for data
5007cc577a4SJonathan Peyton 
5017cc577a4SJonathan Peyton  Register constructors and destructors for thread private data.
5027cc577a4SJonathan Peyton  This function is called when executing in parallel, when we know the thread id.
5037cc577a4SJonathan Peyton */
__kmpc_threadprivate_register(ident_t * loc,void * data,kmpc_ctor ctor,kmpc_cctor cctor,kmpc_dtor dtor)5043041982dSJonathan Peyton void __kmpc_threadprivate_register(ident_t *loc, void *data, kmpc_ctor ctor,
5053041982dSJonathan Peyton                                    kmpc_cctor cctor, kmpc_dtor dtor) {
5067cc577a4SJonathan Peyton   struct shared_common *d_tn, **lnk_tn;
5077cc577a4SJonathan Peyton 
5087cc577a4SJonathan Peyton   KC_TRACE(10, ("__kmpc_threadprivate_register: called\n"));
5097cc577a4SJonathan Peyton 
5107cc577a4SJonathan Peyton #ifdef USE_CHECKS_COMMON
5117cc577a4SJonathan Peyton   /* copy constructor must be zero for current code gen (Nov 2002 - jph) */
5127cc577a4SJonathan Peyton   KMP_ASSERT(cctor == 0);
5137cc577a4SJonathan Peyton #endif /* USE_CHECKS_COMMON */
5147cc577a4SJonathan Peyton 
5157cc577a4SJonathan Peyton   /* Only the global data table exists. */
5167cc577a4SJonathan Peyton   d_tn = __kmp_find_shared_task_common(&__kmp_threadprivate_d_table, -1, data);
5177cc577a4SJonathan Peyton 
5187cc577a4SJonathan Peyton   if (d_tn == 0) {
5197cc577a4SJonathan Peyton     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
5207cc577a4SJonathan Peyton     d_tn->gbl_addr = data;
5217cc577a4SJonathan Peyton 
5227cc577a4SJonathan Peyton     d_tn->ct.ctor = ctor;
5237cc577a4SJonathan Peyton     d_tn->cct.cctor = cctor;
5247cc577a4SJonathan Peyton     d_tn->dt.dtor = dtor;
5257cc577a4SJonathan Peyton     /*
5263041982dSJonathan Peyton             d_tn->is_vec = FALSE;  // AC: commented out because __kmp_allocate
5273041982dSJonathan Peyton        zeroes the memory
5287cc577a4SJonathan Peyton             d_tn->vec_len = 0L;
5297cc577a4SJonathan Peyton             d_tn->obj_init = 0;
5307cc577a4SJonathan Peyton             d_tn->pod_init = 0;
5317cc577a4SJonathan Peyton     */
5327cc577a4SJonathan Peyton     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(data)]);
5337cc577a4SJonathan Peyton 
5347cc577a4SJonathan Peyton     d_tn->next = *lnk_tn;
5357cc577a4SJonathan Peyton     *lnk_tn = d_tn;
5367cc577a4SJonathan Peyton   }
5377cc577a4SJonathan Peyton }
5387cc577a4SJonathan Peyton 
__kmpc_threadprivate(ident_t * loc,kmp_int32 global_tid,void * data,size_t size)5393041982dSJonathan Peyton void *__kmpc_threadprivate(ident_t *loc, kmp_int32 global_tid, void *data,
5403041982dSJonathan Peyton                            size_t size) {
5417cc577a4SJonathan Peyton   void *ret;
5427cc577a4SJonathan Peyton   struct private_common *tn;
5437cc577a4SJonathan Peyton 
5447cc577a4SJonathan Peyton   KC_TRACE(10, ("__kmpc_threadprivate: T#%d called\n", global_tid));
5457cc577a4SJonathan Peyton 
5467cc577a4SJonathan Peyton #ifdef USE_CHECKS_COMMON
5477cc577a4SJonathan Peyton   if (!__kmp_init_serial)
5487cc577a4SJonathan Peyton     KMP_FATAL(RTLNotInitialized);
5497cc577a4SJonathan Peyton #endif /* USE_CHECKS_COMMON */
5507cc577a4SJonathan Peyton 
5517cc577a4SJonathan Peyton   if (!__kmp_threads[global_tid]->th.th_root->r.r_active && !__kmp_foreign_tp) {
5527cc577a4SJonathan Peyton     /* The parallel address will NEVER overlap with the data_address */
5533041982dSJonathan Peyton     /* dkp: 3rd arg to kmp_threadprivate_insert_private_data() is the
5543041982dSJonathan Peyton      * data_address; use data_address = data */
5557cc577a4SJonathan Peyton 
5563041982dSJonathan Peyton     KC_TRACE(20, ("__kmpc_threadprivate: T#%d inserting private data\n",
5573041982dSJonathan Peyton                   global_tid));
5587cc577a4SJonathan Peyton     kmp_threadprivate_insert_private_data(global_tid, data, data, size);
5597cc577a4SJonathan Peyton 
5607cc577a4SJonathan Peyton     ret = data;
5613041982dSJonathan Peyton   } else {
5623041982dSJonathan Peyton     KC_TRACE(
5633041982dSJonathan Peyton         50,
5643041982dSJonathan Peyton         ("__kmpc_threadprivate: T#%d try to find private data at address %p\n",
5657cc577a4SJonathan Peyton          global_tid, data));
5663041982dSJonathan Peyton     tn = __kmp_threadprivate_find_task_common(
5673041982dSJonathan Peyton         __kmp_threads[global_tid]->th.th_pri_common, global_tid, data);
5687cc577a4SJonathan Peyton 
5697cc577a4SJonathan Peyton     if (tn) {
5707cc577a4SJonathan Peyton       KC_TRACE(20, ("__kmpc_threadprivate: T#%d found data\n", global_tid));
5717cc577a4SJonathan Peyton #ifdef USE_CHECKS_COMMON
5727cc577a4SJonathan Peyton       if ((size_t)size > tn->cmn_size) {
5733041982dSJonathan Peyton         KC_TRACE(10, ("THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC
5743041982dSJonathan Peyton                       " ,%" KMP_UINTPTR_SPEC ")\n",
5757cc577a4SJonathan Peyton                       data, size, tn->cmn_size));
5767cc577a4SJonathan Peyton         KMP_FATAL(TPCommonBlocksInconsist);
5777cc577a4SJonathan Peyton       }
5787cc577a4SJonathan Peyton #endif /* USE_CHECKS_COMMON */
5793041982dSJonathan Peyton     } else {
5807cc577a4SJonathan Peyton       /* The parallel address will NEVER overlap with the data_address */
5813041982dSJonathan Peyton       /* dkp: 3rd arg to kmp_threadprivate_insert() is the data_address; use
5823041982dSJonathan Peyton        * data_address = data */
5837cc577a4SJonathan Peyton       KC_TRACE(20, ("__kmpc_threadprivate: T#%d inserting data\n", global_tid));
5847cc577a4SJonathan Peyton       tn = kmp_threadprivate_insert(global_tid, data, data, size);
5857cc577a4SJonathan Peyton     }
5867cc577a4SJonathan Peyton 
5877cc577a4SJonathan Peyton     ret = tn->par_addr;
5887cc577a4SJonathan Peyton   }
5897cc577a4SJonathan Peyton   KC_TRACE(10, ("__kmpc_threadprivate: T#%d exiting; return value = %p\n",
5907cc577a4SJonathan Peyton                 global_tid, ret));
5917cc577a4SJonathan Peyton 
5927cc577a4SJonathan Peyton   return ret;
5937cc577a4SJonathan Peyton }
5947cc577a4SJonathan Peyton 
__kmp_find_cache(void * data)5959e9333aaSAndrey Churbanov static kmp_cached_addr_t *__kmp_find_cache(void *data) {
5969e9333aaSAndrey Churbanov   kmp_cached_addr_t *ptr = __kmp_threadpriv_cache_list;
5979e9333aaSAndrey Churbanov   while (ptr && ptr->data != data)
5989e9333aaSAndrey Churbanov     ptr = ptr->next;
5999e9333aaSAndrey Churbanov   return ptr;
6009e9333aaSAndrey Churbanov }
6019e9333aaSAndrey Churbanov 
6027cc577a4SJonathan Peyton /*!
6037cc577a4SJonathan Peyton  @ingroup THREADPRIVATE
6047cc577a4SJonathan Peyton  @param loc source location information
6057cc577a4SJonathan Peyton  @param global_tid  global thread number
6067cc577a4SJonathan Peyton  @param data  pointer to data to privatize
6077cc577a4SJonathan Peyton  @param size  size of data to privatize
6087cc577a4SJonathan Peyton  @param cache  pointer to cache
6097cc577a4SJonathan Peyton  @return pointer to private storage
6107cc577a4SJonathan Peyton 
6117cc577a4SJonathan Peyton  Allocate private storage for threadprivate data.
6127cc577a4SJonathan Peyton */
6137cc577a4SJonathan Peyton void *
__kmpc_threadprivate_cached(ident_t * loc,kmp_int32 global_tid,void * data,size_t size,void *** cache)6143041982dSJonathan Peyton __kmpc_threadprivate_cached(ident_t *loc,
6157cc577a4SJonathan Peyton                             kmp_int32 global_tid, // gtid.
6167cc577a4SJonathan Peyton                             void *data, // Pointer to original global variable.
6177cc577a4SJonathan Peyton                             size_t size, // Size of original global variable.
6183041982dSJonathan Peyton                             void ***cache) {
6193041982dSJonathan Peyton   KC_TRACE(10, ("__kmpc_threadprivate_cached: T#%d called with cache: %p, "
6203041982dSJonathan Peyton                 "address: %p, size: %" KMP_SIZE_T_SPEC "\n",
6217cc577a4SJonathan Peyton                 global_tid, *cache, data, size));
6227cc577a4SJonathan Peyton 
6237cc577a4SJonathan Peyton   if (TCR_PTR(*cache) == 0) {
6247cc577a4SJonathan Peyton     __kmp_acquire_lock(&__kmp_global_lock, global_tid);
6257cc577a4SJonathan Peyton 
6267cc577a4SJonathan Peyton     if (TCR_PTR(*cache) == 0) {
6277cc577a4SJonathan Peyton       __kmp_acquire_bootstrap_lock(&__kmp_tp_cached_lock);
6289e9333aaSAndrey Churbanov       // Compiler often passes in NULL cache, even if it's already been created
6297cc577a4SJonathan Peyton       void **my_cache;
6309e9333aaSAndrey Churbanov       kmp_cached_addr_t *tp_cache_addr;
6319e9333aaSAndrey Churbanov       // Look for an existing cache
6329e9333aaSAndrey Churbanov       tp_cache_addr = __kmp_find_cache(data);
6339e9333aaSAndrey Churbanov       if (!tp_cache_addr) { // Cache was never created; do it now
6349e9333aaSAndrey Churbanov         __kmp_tp_cached = 1;
6359e9333aaSAndrey Churbanov         KMP_ITT_IGNORE(my_cache = (void **)__kmp_allocate(
6369e9333aaSAndrey Churbanov                            sizeof(void *) * __kmp_tp_capacity +
6379e9333aaSAndrey Churbanov                            sizeof(kmp_cached_addr_t)););
6387cc577a4SJonathan Peyton         // No need to zero the allocated memory; __kmp_allocate does that.
6399e9333aaSAndrey Churbanov         KC_TRACE(50, ("__kmpc_threadprivate_cached: T#%d allocated cache at "
6409e9333aaSAndrey Churbanov                       "address %p\n",
6417cc577a4SJonathan Peyton                       global_tid, my_cache));
6423041982dSJonathan Peyton         /* TODO: free all this memory in __kmp_common_destroy using
6433041982dSJonathan Peyton          * __kmp_threadpriv_cache_list */
6447cc577a4SJonathan Peyton         /* Add address of mycache to linked list for cleanup later  */
6457cc577a4SJonathan Peyton         tp_cache_addr = (kmp_cached_addr_t *)&my_cache[__kmp_tp_capacity];
6467cc577a4SJonathan Peyton         tp_cache_addr->addr = my_cache;
6479e9333aaSAndrey Churbanov         tp_cache_addr->data = data;
6489e9333aaSAndrey Churbanov         tp_cache_addr->compiler_cache = cache;
6497cc577a4SJonathan Peyton         tp_cache_addr->next = __kmp_threadpriv_cache_list;
6507cc577a4SJonathan Peyton         __kmp_threadpriv_cache_list = tp_cache_addr;
6519e9333aaSAndrey Churbanov       } else { // A cache was already created; use it
6529e9333aaSAndrey Churbanov         my_cache = tp_cache_addr->addr;
6539e9333aaSAndrey Churbanov         tp_cache_addr->compiler_cache = cache;
6549e9333aaSAndrey Churbanov       }
6557cc577a4SJonathan Peyton       KMP_MB();
6567cc577a4SJonathan Peyton 
6577cc577a4SJonathan Peyton       TCW_PTR(*cache, my_cache);
6589e9333aaSAndrey Churbanov       __kmp_release_bootstrap_lock(&__kmp_tp_cached_lock);
6597cc577a4SJonathan Peyton 
6607cc577a4SJonathan Peyton       KMP_MB();
6617cc577a4SJonathan Peyton     }
6627cc577a4SJonathan Peyton     __kmp_release_lock(&__kmp_global_lock, global_tid);
6637cc577a4SJonathan Peyton   }
6647cc577a4SJonathan Peyton 
6657cc577a4SJonathan Peyton   void *ret;
6667cc577a4SJonathan Peyton   if ((ret = TCR_PTR((*cache)[global_tid])) == 0) {
6677cc577a4SJonathan Peyton     ret = __kmpc_threadprivate(loc, global_tid, data, (size_t)size);
6687cc577a4SJonathan Peyton 
6697cc577a4SJonathan Peyton     TCW_PTR((*cache)[global_tid], ret);
6707cc577a4SJonathan Peyton   }
6713041982dSJonathan Peyton   KC_TRACE(10,
6723041982dSJonathan Peyton            ("__kmpc_threadprivate_cached: T#%d exiting; return value = %p\n",
6737cc577a4SJonathan Peyton             global_tid, ret));
6747cc577a4SJonathan Peyton   return ret;
6757cc577a4SJonathan Peyton }
6767cc577a4SJonathan Peyton 
6779e9333aaSAndrey Churbanov // This function should only be called when both __kmp_tp_cached_lock and
6789e9333aaSAndrey Churbanov // kmp_forkjoin_lock are held.
__kmp_threadprivate_resize_cache(int newCapacity)6799e9333aaSAndrey Churbanov void __kmp_threadprivate_resize_cache(int newCapacity) {
6809e9333aaSAndrey Churbanov   KC_TRACE(10, ("__kmp_threadprivate_resize_cache: called with size: %d\n",
6819e9333aaSAndrey Churbanov                 newCapacity));
6829e9333aaSAndrey Churbanov 
6839e9333aaSAndrey Churbanov   kmp_cached_addr_t *ptr = __kmp_threadpriv_cache_list;
6849e9333aaSAndrey Churbanov 
6859e9333aaSAndrey Churbanov   while (ptr) {
6869e9333aaSAndrey Churbanov     if (ptr->data) { // this location has an active cache; resize it
6879e9333aaSAndrey Churbanov       void **my_cache;
6889e9333aaSAndrey Churbanov       KMP_ITT_IGNORE(my_cache =
6899e9333aaSAndrey Churbanov                          (void **)__kmp_allocate(sizeof(void *) * newCapacity +
6909e9333aaSAndrey Churbanov                                                  sizeof(kmp_cached_addr_t)););
6919e9333aaSAndrey Churbanov       // No need to zero the allocated memory; __kmp_allocate does that.
6929e9333aaSAndrey Churbanov       KC_TRACE(50, ("__kmp_threadprivate_resize_cache: allocated cache at %p\n",
6939e9333aaSAndrey Churbanov                     my_cache));
6949e9333aaSAndrey Churbanov       // Now copy old cache into new cache
6959e9333aaSAndrey Churbanov       void **old_cache = ptr->addr;
6969e9333aaSAndrey Churbanov       for (int i = 0; i < __kmp_tp_capacity; ++i) {
6979e9333aaSAndrey Churbanov         my_cache[i] = old_cache[i];
6989e9333aaSAndrey Churbanov       }
6999e9333aaSAndrey Churbanov 
7009e9333aaSAndrey Churbanov       // Add address of new my_cache to linked list for cleanup later
7019e9333aaSAndrey Churbanov       kmp_cached_addr_t *tp_cache_addr;
7029e9333aaSAndrey Churbanov       tp_cache_addr = (kmp_cached_addr_t *)&my_cache[newCapacity];
7039e9333aaSAndrey Churbanov       tp_cache_addr->addr = my_cache;
7049e9333aaSAndrey Churbanov       tp_cache_addr->data = ptr->data;
7059e9333aaSAndrey Churbanov       tp_cache_addr->compiler_cache = ptr->compiler_cache;
7069e9333aaSAndrey Churbanov       tp_cache_addr->next = __kmp_threadpriv_cache_list;
7079e9333aaSAndrey Churbanov       __kmp_threadpriv_cache_list = tp_cache_addr;
7089e9333aaSAndrey Churbanov 
7099e9333aaSAndrey Churbanov       // Copy new cache to compiler's location: We can copy directly
7109e9333aaSAndrey Churbanov       // to (*compiler_cache) if compiler guarantees it will keep
7119e9333aaSAndrey Churbanov       // using the same location for the cache. This is not yet true
7129e9333aaSAndrey Churbanov       // for some compilers, in which case we have to check if
7139e9333aaSAndrey Churbanov       // compiler_cache is still pointing at old cache, and if so, we
7149e9333aaSAndrey Churbanov       // can point it at the new cache with an atomic compare&swap
7159e9333aaSAndrey Churbanov       // operation. (Old method will always work, but we should shift
7169e9333aaSAndrey Churbanov       // to new method (commented line below) when Intel and Clang
7179e9333aaSAndrey Churbanov       // compilers use new method.)
7189e9333aaSAndrey Churbanov       (void)KMP_COMPARE_AND_STORE_PTR(tp_cache_addr->compiler_cache, old_cache,
7199e9333aaSAndrey Churbanov                                       my_cache);
7209e9333aaSAndrey Churbanov       // TCW_PTR(*(tp_cache_addr->compiler_cache), my_cache);
7219e9333aaSAndrey Churbanov 
7229e9333aaSAndrey Churbanov       // If the store doesn't happen here, the compiler's old behavior will
7239e9333aaSAndrey Churbanov       // inevitably call __kmpc_threadprivate_cache with a new location for the
7249e9333aaSAndrey Churbanov       // cache, and that function will store the resized cache there at that
7259e9333aaSAndrey Churbanov       // point.
7269e9333aaSAndrey Churbanov 
7279e9333aaSAndrey Churbanov       // Nullify old cache's data pointer so we skip it next time
7289e9333aaSAndrey Churbanov       ptr->data = NULL;
7299e9333aaSAndrey Churbanov     }
7309e9333aaSAndrey Churbanov     ptr = ptr->next;
7319e9333aaSAndrey Churbanov   }
7329e9333aaSAndrey Churbanov   // After all caches are resized, update __kmp_tp_capacity to the new size
7339e9333aaSAndrey Churbanov   *(volatile int *)&__kmp_tp_capacity = newCapacity;
7349e9333aaSAndrey Churbanov }
7359e9333aaSAndrey Churbanov 
7367cc577a4SJonathan Peyton /*!
7377cc577a4SJonathan Peyton  @ingroup THREADPRIVATE
7387cc577a4SJonathan Peyton  @param loc source location information
7397cc577a4SJonathan Peyton  @param data  pointer to data being privatized
7407cc577a4SJonathan Peyton  @param ctor  pointer to constructor function for data
7417cc577a4SJonathan Peyton  @param cctor  pointer to copy constructor function for data
7427cc577a4SJonathan Peyton  @param dtor  pointer to destructor function for data
7437cc577a4SJonathan Peyton  @param vector_length length of the vector (bytes or elements?)
7447cc577a4SJonathan Peyton  Register vector constructors and destructors for thread private data.
7457cc577a4SJonathan Peyton */
__kmpc_threadprivate_register_vec(ident_t * loc,void * data,kmpc_ctor_vec ctor,kmpc_cctor_vec cctor,kmpc_dtor_vec dtor,size_t vector_length)7463041982dSJonathan Peyton void __kmpc_threadprivate_register_vec(ident_t *loc, void *data,
7473041982dSJonathan Peyton                                        kmpc_ctor_vec ctor, kmpc_cctor_vec cctor,
7483041982dSJonathan Peyton                                        kmpc_dtor_vec dtor,
7493041982dSJonathan Peyton                                        size_t vector_length) {
7507cc577a4SJonathan Peyton   struct shared_common *d_tn, **lnk_tn;
7517cc577a4SJonathan Peyton 
7527cc577a4SJonathan Peyton   KC_TRACE(10, ("__kmpc_threadprivate_register_vec: called\n"));
7537cc577a4SJonathan Peyton 
7547cc577a4SJonathan Peyton #ifdef USE_CHECKS_COMMON
7557cc577a4SJonathan Peyton   /* copy constructor must be zero for current code gen (Nov 2002 - jph) */
7567cc577a4SJonathan Peyton   KMP_ASSERT(cctor == 0);
7577cc577a4SJonathan Peyton #endif /* USE_CHECKS_COMMON */
7587cc577a4SJonathan Peyton 
7593041982dSJonathan Peyton   d_tn = __kmp_find_shared_task_common(
7603041982dSJonathan Peyton       &__kmp_threadprivate_d_table, -1,
7613041982dSJonathan Peyton       data); /* Only the global data table exists. */
7627cc577a4SJonathan Peyton 
7637cc577a4SJonathan Peyton   if (d_tn == 0) {
7647cc577a4SJonathan Peyton     d_tn = (struct shared_common *)__kmp_allocate(sizeof(struct shared_common));
7657cc577a4SJonathan Peyton     d_tn->gbl_addr = data;
7667cc577a4SJonathan Peyton 
7677cc577a4SJonathan Peyton     d_tn->ct.ctorv = ctor;
7687cc577a4SJonathan Peyton     d_tn->cct.cctorv = cctor;
7697cc577a4SJonathan Peyton     d_tn->dt.dtorv = dtor;
7707cc577a4SJonathan Peyton     d_tn->is_vec = TRUE;
7717cc577a4SJonathan Peyton     d_tn->vec_len = (size_t)vector_length;
7729e9333aaSAndrey Churbanov     // d_tn->obj_init = 0;  // AC: __kmp_allocate zeroes the memory
7739e9333aaSAndrey Churbanov     // d_tn->pod_init = 0;
7747cc577a4SJonathan Peyton     lnk_tn = &(__kmp_threadprivate_d_table.data[KMP_HASH(data)]);
7757cc577a4SJonathan Peyton 
7767cc577a4SJonathan Peyton     d_tn->next = *lnk_tn;
7777cc577a4SJonathan Peyton     *lnk_tn = d_tn;
7787cc577a4SJonathan Peyton   }
7797cc577a4SJonathan Peyton }
7809e9333aaSAndrey Churbanov 
__kmp_cleanup_threadprivate_caches()7819e9333aaSAndrey Churbanov void __kmp_cleanup_threadprivate_caches() {
7829e9333aaSAndrey Churbanov   kmp_cached_addr_t *ptr = __kmp_threadpriv_cache_list;
7839e9333aaSAndrey Churbanov 
7849e9333aaSAndrey Churbanov   while (ptr) {
7859e9333aaSAndrey Churbanov     void **cache = ptr->addr;
7869e9333aaSAndrey Churbanov     __kmp_threadpriv_cache_list = ptr->next;
7879e9333aaSAndrey Churbanov     if (*ptr->compiler_cache)
7889e9333aaSAndrey Churbanov       *ptr->compiler_cache = NULL;
7899e9333aaSAndrey Churbanov     ptr->compiler_cache = NULL;
7909e9333aaSAndrey Churbanov     ptr->data = NULL;
7919e9333aaSAndrey Churbanov     ptr->addr = NULL;
7929e9333aaSAndrey Churbanov     ptr->next = NULL;
7939e9333aaSAndrey Churbanov     // Threadprivate data pointed at by cache entries are destroyed at end of
7949e9333aaSAndrey Churbanov     // __kmp_launch_thread with __kmp_common_destroy_gtid.
7959e9333aaSAndrey Churbanov     __kmp_free(cache); // implicitly frees ptr too
7969e9333aaSAndrey Churbanov     ptr = __kmp_threadpriv_cache_list;
7979e9333aaSAndrey Churbanov   }
7989e9333aaSAndrey Churbanov }
799