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