xref: /freebsd-src/contrib/llvm-project/openmp/runtime/src/kmp_csupport.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * kmp_csupport.cpp -- kfront linkage support for OpenMP.
30b57cec5SDimitry Andric  */
40b57cec5SDimitry Andric 
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #define __KMP_IMP
140b57cec5SDimitry Andric #include "omp.h" /* extern "C" declarations of user-visible routines */
150b57cec5SDimitry Andric #include "kmp.h"
160b57cec5SDimitry Andric #include "kmp_error.h"
170b57cec5SDimitry Andric #include "kmp_i18n.h"
180b57cec5SDimitry Andric #include "kmp_itt.h"
190b57cec5SDimitry Andric #include "kmp_lock.h"
200b57cec5SDimitry Andric #include "kmp_stats.h"
21*0fca6ea1SDimitry Andric #include "kmp_utils.h"
220b57cec5SDimitry Andric #include "ompt-specific.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #define MAX_MESSAGE 512
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric // flags will be used in future, e.g. to implement openmp_strict library
270b57cec5SDimitry Andric // restrictions
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric /*!
300b57cec5SDimitry Andric  * @ingroup STARTUP_SHUTDOWN
310b57cec5SDimitry Andric  * @param loc   in   source location information
320b57cec5SDimitry Andric  * @param flags in   for future use (currently ignored)
330b57cec5SDimitry Andric  *
340b57cec5SDimitry Andric  * Initialize the runtime library. This call is optional; if it is not made then
350b57cec5SDimitry Andric  * it will be implicitly called by attempts to use other library functions.
360b57cec5SDimitry Andric  */
370b57cec5SDimitry Andric void __kmpc_begin(ident_t *loc, kmp_int32 flags) {
380b57cec5SDimitry Andric   // By default __kmpc_begin() is no-op.
390b57cec5SDimitry Andric   char *env;
400b57cec5SDimitry Andric   if ((env = getenv("KMP_INITIAL_THREAD_BIND")) != NULL &&
410b57cec5SDimitry Andric       __kmp_str_match_true(env)) {
420b57cec5SDimitry Andric     __kmp_middle_initialize();
43fe6060f1SDimitry Andric     __kmp_assign_root_init_mask();
440b57cec5SDimitry Andric     KC_TRACE(10, ("__kmpc_begin: middle initialization called\n"));
450b57cec5SDimitry Andric   } else if (__kmp_ignore_mppbeg() == FALSE) {
460b57cec5SDimitry Andric     // By default __kmp_ignore_mppbeg() returns TRUE.
470b57cec5SDimitry Andric     __kmp_internal_begin();
480b57cec5SDimitry Andric     KC_TRACE(10, ("__kmpc_begin: called\n"));
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric /*!
530b57cec5SDimitry Andric  * @ingroup STARTUP_SHUTDOWN
540b57cec5SDimitry Andric  * @param loc source location information
550b57cec5SDimitry Andric  *
560b57cec5SDimitry Andric  * Shutdown the runtime library. This is also optional, and even if called will
570b57cec5SDimitry Andric  * not do anything unless the `KMP_IGNORE_MPPEND` environment variable is set to
580b57cec5SDimitry Andric  * zero.
590b57cec5SDimitry Andric  */
600b57cec5SDimitry Andric void __kmpc_end(ident_t *loc) {
610b57cec5SDimitry Andric   // By default, __kmp_ignore_mppend() returns TRUE which makes __kmpc_end()
620b57cec5SDimitry Andric   // call no-op. However, this can be overridden with KMP_IGNORE_MPPEND
630b57cec5SDimitry Andric   // environment variable. If KMP_IGNORE_MPPEND is 0, __kmp_ignore_mppend()
640b57cec5SDimitry Andric   // returns FALSE and __kmpc_end() will unregister this root (it can cause
650b57cec5SDimitry Andric   // library shut down).
660b57cec5SDimitry Andric   if (__kmp_ignore_mppend() == FALSE) {
670b57cec5SDimitry Andric     KC_TRACE(10, ("__kmpc_end: called\n"));
680b57cec5SDimitry Andric     KA_TRACE(30, ("__kmpc_end\n"));
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric     __kmp_internal_end_thread(-1);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric #if KMP_OS_WINDOWS && OMPT_SUPPORT
730b57cec5SDimitry Andric   // Normal exit process on Windows does not allow worker threads of the final
740b57cec5SDimitry Andric   // parallel region to finish reporting their events, so shutting down the
750b57cec5SDimitry Andric   // library here fixes the issue at least for the cases where __kmpc_end() is
760b57cec5SDimitry Andric   // placed properly.
770b57cec5SDimitry Andric   if (ompt_enabled.enabled)
780b57cec5SDimitry Andric     __kmp_internal_end_library(__kmp_gtid_get_specific());
790b57cec5SDimitry Andric #endif
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric /*!
830b57cec5SDimitry Andric @ingroup THREAD_STATES
840b57cec5SDimitry Andric @param loc Source location information.
850b57cec5SDimitry Andric @return The global thread index of the active thread.
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric This function can be called in any context.
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric If the runtime has ony been entered at the outermost level from a
900b57cec5SDimitry Andric single (necessarily non-OpenMP<sup>*</sup>) thread, then the thread number is
910b57cec5SDimitry Andric that which would be returned by omp_get_thread_num() in the outermost
920b57cec5SDimitry Andric active parallel construct. (Or zero if there is no active parallel
93fe6060f1SDimitry Andric construct, since the primary thread is necessarily thread zero).
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric If multiple non-OpenMP threads all enter an OpenMP construct then this
960b57cec5SDimitry Andric will be a unique thread identifier among all the threads created by
975ffd83dbSDimitry Andric the OpenMP runtime (but the value cannot be defined in terms of
980b57cec5SDimitry Andric OpenMP thread ids returned by omp_get_thread_num()).
990b57cec5SDimitry Andric */
1000b57cec5SDimitry Andric kmp_int32 __kmpc_global_thread_num(ident_t *loc) {
1010b57cec5SDimitry Andric   kmp_int32 gtid = __kmp_entry_gtid();
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_global_thread_num: T#%d\n", gtid));
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   return gtid;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric /*!
1090b57cec5SDimitry Andric @ingroup THREAD_STATES
1100b57cec5SDimitry Andric @param loc Source location information.
1110b57cec5SDimitry Andric @return The number of threads under control of the OpenMP<sup>*</sup> runtime
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric This function can be called in any context.
1140b57cec5SDimitry Andric It returns the total number of threads under the control of the OpenMP runtime.
1150b57cec5SDimitry Andric That is not a number that can be determined by any OpenMP standard calls, since
1160b57cec5SDimitry Andric the library may be called from more than one non-OpenMP thread, and this
1170b57cec5SDimitry Andric reflects the total over all such calls. Similarly the runtime maintains
1180b57cec5SDimitry Andric underlying threads even when they are not active (since the cost of creating
1190b57cec5SDimitry Andric and destroying OS threads is high), this call counts all such threads even if
1200b57cec5SDimitry Andric they are not waiting for work.
1210b57cec5SDimitry Andric */
1220b57cec5SDimitry Andric kmp_int32 __kmpc_global_num_threads(ident_t *loc) {
1230b57cec5SDimitry Andric   KC_TRACE(10,
1240b57cec5SDimitry Andric            ("__kmpc_global_num_threads: num_threads = %d\n", __kmp_all_nth));
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   return TCR_4(__kmp_all_nth);
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric /*!
1300b57cec5SDimitry Andric @ingroup THREAD_STATES
1310b57cec5SDimitry Andric @param loc Source location information.
1320b57cec5SDimitry Andric @return The thread number of the calling thread in the innermost active parallel
1330b57cec5SDimitry Andric construct.
1340b57cec5SDimitry Andric */
1350b57cec5SDimitry Andric kmp_int32 __kmpc_bound_thread_num(ident_t *loc) {
1360b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_bound_thread_num: called\n"));
1370b57cec5SDimitry Andric   return __kmp_tid_from_gtid(__kmp_entry_gtid());
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric /*!
1410b57cec5SDimitry Andric @ingroup THREAD_STATES
1420b57cec5SDimitry Andric @param loc Source location information.
1430b57cec5SDimitry Andric @return The number of threads in the innermost active parallel construct.
1440b57cec5SDimitry Andric */
1450b57cec5SDimitry Andric kmp_int32 __kmpc_bound_num_threads(ident_t *loc) {
1460b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_bound_num_threads: called\n"));
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   return __kmp_entry_thread()->th.th_team->t.t_nproc;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric /*!
1520b57cec5SDimitry Andric  * @ingroup DEPRECATED
1530b57cec5SDimitry Andric  * @param loc location description
1540b57cec5SDimitry Andric  *
1550b57cec5SDimitry Andric  * This function need not be called. It always returns TRUE.
1560b57cec5SDimitry Andric  */
1570b57cec5SDimitry Andric kmp_int32 __kmpc_ok_to_fork(ident_t *loc) {
1580b57cec5SDimitry Andric #ifndef KMP_DEBUG
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   return TRUE;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric #else
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   const char *semi2;
1650b57cec5SDimitry Andric   const char *semi3;
1660b57cec5SDimitry Andric   int line_no;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   if (__kmp_par_range == 0) {
1690b57cec5SDimitry Andric     return TRUE;
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric   semi2 = loc->psource;
1720b57cec5SDimitry Andric   if (semi2 == NULL) {
1730b57cec5SDimitry Andric     return TRUE;
1740b57cec5SDimitry Andric   }
1750b57cec5SDimitry Andric   semi2 = strchr(semi2, ';');
1760b57cec5SDimitry Andric   if (semi2 == NULL) {
1770b57cec5SDimitry Andric     return TRUE;
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric   semi2 = strchr(semi2 + 1, ';');
1800b57cec5SDimitry Andric   if (semi2 == NULL) {
1810b57cec5SDimitry Andric     return TRUE;
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric   if (__kmp_par_range_filename[0]) {
1840b57cec5SDimitry Andric     const char *name = semi2 - 1;
1850b57cec5SDimitry Andric     while ((name > loc->psource) && (*name != '/') && (*name != ';')) {
1860b57cec5SDimitry Andric       name--;
1870b57cec5SDimitry Andric     }
1880b57cec5SDimitry Andric     if ((*name == '/') || (*name == ';')) {
1890b57cec5SDimitry Andric       name++;
1900b57cec5SDimitry Andric     }
1910b57cec5SDimitry Andric     if (strncmp(__kmp_par_range_filename, name, semi2 - name)) {
1920b57cec5SDimitry Andric       return __kmp_par_range < 0;
1930b57cec5SDimitry Andric     }
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric   semi3 = strchr(semi2 + 1, ';');
1960b57cec5SDimitry Andric   if (__kmp_par_range_routine[0]) {
1970b57cec5SDimitry Andric     if ((semi3 != NULL) && (semi3 > semi2) &&
1980b57cec5SDimitry Andric         (strncmp(__kmp_par_range_routine, semi2 + 1, semi3 - semi2 - 1))) {
1990b57cec5SDimitry Andric       return __kmp_par_range < 0;
2000b57cec5SDimitry Andric     }
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric   if (KMP_SSCANF(semi3 + 1, "%d", &line_no) == 1) {
2030b57cec5SDimitry Andric     if ((line_no >= __kmp_par_range_lb) && (line_no <= __kmp_par_range_ub)) {
2040b57cec5SDimitry Andric       return __kmp_par_range > 0;
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric     return __kmp_par_range < 0;
2070b57cec5SDimitry Andric   }
2080b57cec5SDimitry Andric   return TRUE;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric #endif /* KMP_DEBUG */
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric /*!
2140b57cec5SDimitry Andric @ingroup THREAD_STATES
2150b57cec5SDimitry Andric @param loc Source location information.
2160b57cec5SDimitry Andric @return 1 if this thread is executing inside an active parallel region, zero if
2170b57cec5SDimitry Andric not.
2180b57cec5SDimitry Andric */
2190b57cec5SDimitry Andric kmp_int32 __kmpc_in_parallel(ident_t *loc) {
2200b57cec5SDimitry Andric   return __kmp_entry_thread()->th.th_root->r.r_active;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric /*!
2240b57cec5SDimitry Andric @ingroup PARALLEL
2250b57cec5SDimitry Andric @param loc source location information
2260b57cec5SDimitry Andric @param global_tid global thread number
2270b57cec5SDimitry Andric @param num_threads number of threads requested for this parallel construct
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric Set the number of threads to be used by the next fork spawned by this thread.
2300b57cec5SDimitry Andric This call is only required if the parallel construct has a `num_threads` clause.
2310b57cec5SDimitry Andric */
2320b57cec5SDimitry Andric void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid,
2330b57cec5SDimitry Andric                              kmp_int32 num_threads) {
2340b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_push_num_threads: enter T#%d num_threads=%d\n",
2350b57cec5SDimitry Andric                 global_tid, num_threads));
236e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
2370b57cec5SDimitry Andric   __kmp_push_num_threads(loc, global_tid, num_threads);
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
240*0fca6ea1SDimitry Andric void __kmpc_push_num_threads_strict(ident_t *loc, kmp_int32 global_tid,
241*0fca6ea1SDimitry Andric                                     kmp_int32 num_threads, int severity,
242*0fca6ea1SDimitry Andric                                     const char *message) {
243*0fca6ea1SDimitry Andric   __kmp_push_num_threads(loc, global_tid, num_threads);
244*0fca6ea1SDimitry Andric   __kmp_set_strict_num_threads(loc, global_tid, severity, message);
245*0fca6ea1SDimitry Andric }
246*0fca6ea1SDimitry Andric 
247*0fca6ea1SDimitry Andric /*!
248*0fca6ea1SDimitry Andric @ingroup PARALLEL
249*0fca6ea1SDimitry Andric @param loc source location information
250*0fca6ea1SDimitry Andric @param global_tid global thread number
251*0fca6ea1SDimitry Andric @param list_length number of entries in the num_threads_list array
252*0fca6ea1SDimitry Andric @param num_threads_list array of numbers of threads requested for this parallel
253*0fca6ea1SDimitry Andric construct and subsequent nested parallel constructs
254*0fca6ea1SDimitry Andric 
255*0fca6ea1SDimitry Andric Set the number of threads to be used by the next fork spawned by this thread,
256*0fca6ea1SDimitry Andric and some nested forks as well.
257*0fca6ea1SDimitry Andric This call is only required if the parallel construct has a `num_threads` clause
258*0fca6ea1SDimitry Andric that has a list of integers as the argument.
259*0fca6ea1SDimitry Andric */
260*0fca6ea1SDimitry Andric void __kmpc_push_num_threads_list(ident_t *loc, kmp_int32 global_tid,
261*0fca6ea1SDimitry Andric                                   kmp_uint32 list_length,
262*0fca6ea1SDimitry Andric                                   kmp_int32 *num_threads_list) {
263*0fca6ea1SDimitry Andric   KA_TRACE(20, ("__kmpc_push_num_threads_list: enter T#%d num_threads_list=",
264*0fca6ea1SDimitry Andric                 global_tid));
265*0fca6ea1SDimitry Andric   KA_TRACE(20, ("%d", num_threads_list[0]));
266*0fca6ea1SDimitry Andric #ifdef KMP_DEBUG
267*0fca6ea1SDimitry Andric   for (kmp_uint32 i = 1; i < list_length; ++i)
268*0fca6ea1SDimitry Andric     KA_TRACE(20, (", %d", num_threads_list[i]));
269*0fca6ea1SDimitry Andric #endif
270*0fca6ea1SDimitry Andric   KA_TRACE(20, ("/n"));
271*0fca6ea1SDimitry Andric 
272*0fca6ea1SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
273*0fca6ea1SDimitry Andric   __kmp_push_num_threads_list(loc, global_tid, list_length, num_threads_list);
274*0fca6ea1SDimitry Andric }
275*0fca6ea1SDimitry Andric 
276*0fca6ea1SDimitry Andric void __kmpc_push_num_threads_list_strict(ident_t *loc, kmp_int32 global_tid,
277*0fca6ea1SDimitry Andric                                          kmp_uint32 list_length,
278*0fca6ea1SDimitry Andric                                          kmp_int32 *num_threads_list,
279*0fca6ea1SDimitry Andric                                          int severity, const char *message) {
280*0fca6ea1SDimitry Andric   __kmp_push_num_threads_list(loc, global_tid, list_length, num_threads_list);
281*0fca6ea1SDimitry Andric   __kmp_set_strict_num_threads(loc, global_tid, severity, message);
282*0fca6ea1SDimitry Andric }
283*0fca6ea1SDimitry Andric 
2840b57cec5SDimitry Andric void __kmpc_pop_num_threads(ident_t *loc, kmp_int32 global_tid) {
2850b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_pop_num_threads: enter\n"));
2860b57cec5SDimitry Andric   /* the num_threads are automatically popped */
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 global_tid,
2900b57cec5SDimitry Andric                            kmp_int32 proc_bind) {
2910b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_push_proc_bind: enter T#%d proc_bind=%d\n", global_tid,
2920b57cec5SDimitry Andric                 proc_bind));
293e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
2940b57cec5SDimitry Andric   __kmp_push_proc_bind(loc, global_tid, (kmp_proc_bind_t)proc_bind);
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric /*!
2980b57cec5SDimitry Andric @ingroup PARALLEL
2990b57cec5SDimitry Andric @param loc  source location information
3000b57cec5SDimitry Andric @param argc  total number of arguments in the ellipsis
3010b57cec5SDimitry Andric @param microtask  pointer to callback routine consisting of outlined parallel
3020b57cec5SDimitry Andric construct
3030b57cec5SDimitry Andric @param ...  pointers to shared variables that aren't global
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric Do the actual fork and call the microtask in the relevant number of threads.
3060b57cec5SDimitry Andric */
3070b57cec5SDimitry Andric void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, ...) {
3080b57cec5SDimitry Andric   int gtid = __kmp_entry_gtid();
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric #if (KMP_STATS_ENABLED)
3110b57cec5SDimitry Andric   // If we were in a serial region, then stop the serial timer, record
3120b57cec5SDimitry Andric   // the event, and start parallel region timer
3130b57cec5SDimitry Andric   stats_state_e previous_state = KMP_GET_THREAD_STATE();
3140b57cec5SDimitry Andric   if (previous_state == stats_state_e::SERIAL_REGION) {
3150b57cec5SDimitry Andric     KMP_EXCHANGE_PARTITIONED_TIMER(OMP_parallel_overhead);
3160b57cec5SDimitry Andric   } else {
3170b57cec5SDimitry Andric     KMP_PUSH_PARTITIONED_TIMER(OMP_parallel_overhead);
3180b57cec5SDimitry Andric   }
3190b57cec5SDimitry Andric   int inParallel = __kmpc_in_parallel(loc);
3200b57cec5SDimitry Andric   if (inParallel) {
3210b57cec5SDimitry Andric     KMP_COUNT_BLOCK(OMP_NESTED_PARALLEL);
3220b57cec5SDimitry Andric   } else {
3230b57cec5SDimitry Andric     KMP_COUNT_BLOCK(OMP_PARALLEL);
3240b57cec5SDimitry Andric   }
3250b57cec5SDimitry Andric #endif
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   // maybe to save thr_state is enough here
3280b57cec5SDimitry Andric   {
3290b57cec5SDimitry Andric     va_list ap;
3300b57cec5SDimitry Andric     va_start(ap, microtask);
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric #if OMPT_SUPPORT
3330b57cec5SDimitry Andric     ompt_frame_t *ompt_frame;
3340b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
3350b57cec5SDimitry Andric       kmp_info_t *master_th = __kmp_threads[gtid];
336349cc55cSDimitry Andric       ompt_frame = &master_th->th.th_current_task->ompt_task_info.frame;
3370b57cec5SDimitry Andric       ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
3380b57cec5SDimitry Andric     }
339e8d8bef9SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(gtid);
3400b57cec5SDimitry Andric #endif
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric #if INCLUDE_SSC_MARKS
3430b57cec5SDimitry Andric     SSC_MARK_FORKING();
3440b57cec5SDimitry Andric #endif
3450b57cec5SDimitry Andric     __kmp_fork_call(loc, gtid, fork_context_intel, argc,
3460b57cec5SDimitry Andric                     VOLATILE_CAST(microtask_t) microtask, // "wrapped" task
3470b57cec5SDimitry Andric                     VOLATILE_CAST(launch_t) __kmp_invoke_task_func,
34816794618SDimitry Andric                     kmp_va_addr_of(ap));
3490b57cec5SDimitry Andric #if INCLUDE_SSC_MARKS
3500b57cec5SDimitry Andric     SSC_MARK_JOINING();
3510b57cec5SDimitry Andric #endif
3520b57cec5SDimitry Andric     __kmp_join_call(loc, gtid
3530b57cec5SDimitry Andric #if OMPT_SUPPORT
3540b57cec5SDimitry Andric                     ,
3550b57cec5SDimitry Andric                     fork_context_intel
3560b57cec5SDimitry Andric #endif
3570b57cec5SDimitry Andric     );
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric     va_end(ap);
360349cc55cSDimitry Andric 
361349cc55cSDimitry Andric #if OMPT_SUPPORT
362349cc55cSDimitry Andric     if (ompt_enabled.enabled) {
363349cc55cSDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
364349cc55cSDimitry Andric     }
365349cc55cSDimitry Andric #endif
3660b57cec5SDimitry Andric   }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric #if KMP_STATS_ENABLED
3690b57cec5SDimitry Andric   if (previous_state == stats_state_e::SERIAL_REGION) {
3700b57cec5SDimitry Andric     KMP_EXCHANGE_PARTITIONED_TIMER(OMP_serial);
371e8d8bef9SDimitry Andric     KMP_SET_THREAD_STATE(previous_state);
3720b57cec5SDimitry Andric   } else {
3730b57cec5SDimitry Andric     KMP_POP_PARTITIONED_TIMER();
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric #endif // KMP_STATS_ENABLED
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric /*!
3790b57cec5SDimitry Andric @ingroup PARALLEL
3800b57cec5SDimitry Andric @param loc  source location information
381bdd1243dSDimitry Andric @param microtask  pointer to callback routine consisting of outlined parallel
382bdd1243dSDimitry Andric construct
383bdd1243dSDimitry Andric @param cond  condition for running in parallel
384bdd1243dSDimitry Andric @param args  struct of pointers to shared variables that aren't global
385bdd1243dSDimitry Andric 
386bdd1243dSDimitry Andric Perform a fork only if the condition is true.
387bdd1243dSDimitry Andric */
388bdd1243dSDimitry Andric void __kmpc_fork_call_if(ident_t *loc, kmp_int32 argc, kmpc_micro microtask,
389bdd1243dSDimitry Andric                          kmp_int32 cond, void *args) {
390bdd1243dSDimitry Andric   int gtid = __kmp_entry_gtid();
391bdd1243dSDimitry Andric   if (cond) {
392bdd1243dSDimitry Andric     if (args)
393bdd1243dSDimitry Andric       __kmpc_fork_call(loc, argc, microtask, args);
394bdd1243dSDimitry Andric     else
395bdd1243dSDimitry Andric       __kmpc_fork_call(loc, argc, microtask);
396bdd1243dSDimitry Andric   } else {
397bdd1243dSDimitry Andric     __kmpc_serialized_parallel(loc, gtid);
398bdd1243dSDimitry Andric 
3995f757f3fSDimitry Andric #if OMPT_SUPPORT
4005f757f3fSDimitry Andric     void *exit_frame_ptr;
4015f757f3fSDimitry Andric #endif
4025f757f3fSDimitry Andric 
403bdd1243dSDimitry Andric     if (args)
4045f757f3fSDimitry Andric       __kmp_invoke_microtask(VOLATILE_CAST(microtask_t) microtask, gtid,
4055f757f3fSDimitry Andric                              /*npr=*/0,
4065f757f3fSDimitry Andric                              /*argc=*/1, &args
4075f757f3fSDimitry Andric #if OMPT_SUPPORT
4085f757f3fSDimitry Andric                              ,
4095f757f3fSDimitry Andric                              &exit_frame_ptr
4105f757f3fSDimitry Andric #endif
4115f757f3fSDimitry Andric       );
412bdd1243dSDimitry Andric     else
4135f757f3fSDimitry Andric       __kmp_invoke_microtask(VOLATILE_CAST(microtask_t) microtask, gtid,
4145f757f3fSDimitry Andric                              /*npr=*/0,
4155f757f3fSDimitry Andric                              /*argc=*/0,
4165f757f3fSDimitry Andric                              /*args=*/nullptr
4175f757f3fSDimitry Andric #if OMPT_SUPPORT
4185f757f3fSDimitry Andric                              ,
4195f757f3fSDimitry Andric                              &exit_frame_ptr
4205f757f3fSDimitry Andric #endif
4215f757f3fSDimitry Andric       );
422bdd1243dSDimitry Andric 
423bdd1243dSDimitry Andric     __kmpc_end_serialized_parallel(loc, gtid);
424bdd1243dSDimitry Andric   }
425bdd1243dSDimitry Andric }
426bdd1243dSDimitry Andric 
427bdd1243dSDimitry Andric /*!
428bdd1243dSDimitry Andric @ingroup PARALLEL
429bdd1243dSDimitry Andric @param loc source location information
4300b57cec5SDimitry Andric @param global_tid global thread number
4310b57cec5SDimitry Andric @param num_teams number of teams requested for the teams construct
4320b57cec5SDimitry Andric @param num_threads number of threads per team requested for the teams construct
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric Set the number of teams to be used by the teams construct.
4350b57cec5SDimitry Andric This call is only required if the teams construct has a `num_teams` clause
4360b57cec5SDimitry Andric or a `thread_limit` clause (or both).
4370b57cec5SDimitry Andric */
4380b57cec5SDimitry Andric void __kmpc_push_num_teams(ident_t *loc, kmp_int32 global_tid,
4390b57cec5SDimitry Andric                            kmp_int32 num_teams, kmp_int32 num_threads) {
4400b57cec5SDimitry Andric   KA_TRACE(20,
4410b57cec5SDimitry Andric            ("__kmpc_push_num_teams: enter T#%d num_teams=%d num_threads=%d\n",
4420b57cec5SDimitry Andric             global_tid, num_teams, num_threads));
443e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
4440b57cec5SDimitry Andric   __kmp_push_num_teams(loc, global_tid, num_teams, num_threads);
4450b57cec5SDimitry Andric }
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric /*!
4480b57cec5SDimitry Andric @ingroup PARALLEL
4490b57cec5SDimitry Andric @param loc source location information
450fe6060f1SDimitry Andric @param global_tid global thread number
4515f757f3fSDimitry Andric @param thread_limit limit on number of threads which can be created within the
4525f757f3fSDimitry Andric current task
4535f757f3fSDimitry Andric 
4545f757f3fSDimitry Andric Set the thread_limit for the current task
4555f757f3fSDimitry Andric This call is there to support `thread_limit` clause on the `target` construct
4565f757f3fSDimitry Andric */
4575f757f3fSDimitry Andric void __kmpc_set_thread_limit(ident_t *loc, kmp_int32 global_tid,
4585f757f3fSDimitry Andric                              kmp_int32 thread_limit) {
4595f757f3fSDimitry Andric   __kmp_assert_valid_gtid(global_tid);
4605f757f3fSDimitry Andric   kmp_info_t *thread = __kmp_threads[global_tid];
4615f757f3fSDimitry Andric   if (thread_limit > 0)
4625f757f3fSDimitry Andric     thread->th.th_current_task->td_icvs.task_thread_limit = thread_limit;
4635f757f3fSDimitry Andric }
4645f757f3fSDimitry Andric 
4655f757f3fSDimitry Andric /*!
4665f757f3fSDimitry Andric @ingroup PARALLEL
4675f757f3fSDimitry Andric @param loc source location information
4685f757f3fSDimitry Andric @param global_tid global thread number
46981ad6265SDimitry Andric @param num_teams_lb lower bound on number of teams requested for the teams
470fe6060f1SDimitry Andric construct
47181ad6265SDimitry Andric @param num_teams_ub upper bound on number of teams requested for the teams
472fe6060f1SDimitry Andric construct
473fe6060f1SDimitry Andric @param num_threads number of threads per team requested for the teams construct
474fe6060f1SDimitry Andric 
475fe6060f1SDimitry Andric Set the number of teams to be used by the teams construct. The number of initial
476fe6060f1SDimitry Andric teams cretaed will be greater than or equal to the lower bound and less than or
477fe6060f1SDimitry Andric equal to the upper bound.
478fe6060f1SDimitry Andric This call is only required if the teams construct has a `num_teams` clause
479fe6060f1SDimitry Andric or a `thread_limit` clause (or both).
480fe6060f1SDimitry Andric */
481fe6060f1SDimitry Andric void __kmpc_push_num_teams_51(ident_t *loc, kmp_int32 global_tid,
482fe6060f1SDimitry Andric                               kmp_int32 num_teams_lb, kmp_int32 num_teams_ub,
483fe6060f1SDimitry Andric                               kmp_int32 num_threads) {
484fe6060f1SDimitry Andric   KA_TRACE(20, ("__kmpc_push_num_teams_51: enter T#%d num_teams_lb=%d"
485fe6060f1SDimitry Andric                 " num_teams_ub=%d num_threads=%d\n",
486fe6060f1SDimitry Andric                 global_tid, num_teams_lb, num_teams_ub, num_threads));
487fe6060f1SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
488fe6060f1SDimitry Andric   __kmp_push_num_teams_51(loc, global_tid, num_teams_lb, num_teams_ub,
489fe6060f1SDimitry Andric                           num_threads);
490fe6060f1SDimitry Andric }
491fe6060f1SDimitry Andric 
492fe6060f1SDimitry Andric /*!
493fe6060f1SDimitry Andric @ingroup PARALLEL
494fe6060f1SDimitry Andric @param loc  source location information
4950b57cec5SDimitry Andric @param argc  total number of arguments in the ellipsis
4960b57cec5SDimitry Andric @param microtask  pointer to callback routine consisting of outlined teams
4970b57cec5SDimitry Andric construct
4980b57cec5SDimitry Andric @param ...  pointers to shared variables that aren't global
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric Do the actual fork and call the microtask in the relevant number of threads.
5010b57cec5SDimitry Andric */
5020b57cec5SDimitry Andric void __kmpc_fork_teams(ident_t *loc, kmp_int32 argc, kmpc_micro microtask,
5030b57cec5SDimitry Andric                        ...) {
5040b57cec5SDimitry Andric   int gtid = __kmp_entry_gtid();
5050b57cec5SDimitry Andric   kmp_info_t *this_thr = __kmp_threads[gtid];
5060b57cec5SDimitry Andric   va_list ap;
5070b57cec5SDimitry Andric   va_start(ap, microtask);
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric #if KMP_STATS_ENABLED
5100b57cec5SDimitry Andric   KMP_COUNT_BLOCK(OMP_TEAMS);
5110b57cec5SDimitry Andric   stats_state_e previous_state = KMP_GET_THREAD_STATE();
5120b57cec5SDimitry Andric   if (previous_state == stats_state_e::SERIAL_REGION) {
5130b57cec5SDimitry Andric     KMP_EXCHANGE_PARTITIONED_TIMER(OMP_teams_overhead);
5140b57cec5SDimitry Andric   } else {
5150b57cec5SDimitry Andric     KMP_PUSH_PARTITIONED_TIMER(OMP_teams_overhead);
5160b57cec5SDimitry Andric   }
5170b57cec5SDimitry Andric #endif
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   // remember teams entry point and nesting level
5200b57cec5SDimitry Andric   this_thr->th.th_teams_microtask = microtask;
5210b57cec5SDimitry Andric   this_thr->th.th_teams_level =
5220b57cec5SDimitry Andric       this_thr->th.th_team->t.t_level; // AC: can be >0 on host
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric #if OMPT_SUPPORT
5250b57cec5SDimitry Andric   kmp_team_t *parent_team = this_thr->th.th_team;
5260b57cec5SDimitry Andric   int tid = __kmp_tid_from_gtid(gtid);
5270b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
5280b57cec5SDimitry Andric     parent_team->t.t_implicit_task_taskdata[tid]
5290b57cec5SDimitry Andric         .ompt_task_info.frame.enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(gtid);
5320b57cec5SDimitry Andric #endif
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   // check if __kmpc_push_num_teams called, set default number of teams
5350b57cec5SDimitry Andric   // otherwise
5360b57cec5SDimitry Andric   if (this_thr->th.th_teams_size.nteams == 0) {
5370b57cec5SDimitry Andric     __kmp_push_num_teams(loc, gtid, 0, 0);
5380b57cec5SDimitry Andric   }
5390b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this_thr->th.th_set_nproc >= 1);
5400b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this_thr->th.th_teams_size.nteams >= 1);
5410b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this_thr->th.th_teams_size.nth >= 1);
5420b57cec5SDimitry Andric 
54316794618SDimitry Andric   __kmp_fork_call(
54416794618SDimitry Andric       loc, gtid, fork_context_intel, argc,
54516794618SDimitry Andric       VOLATILE_CAST(microtask_t) __kmp_teams_master, // "wrapped" task
54616794618SDimitry Andric       VOLATILE_CAST(launch_t) __kmp_invoke_teams_master, kmp_va_addr_of(ap));
5470b57cec5SDimitry Andric   __kmp_join_call(loc, gtid
5480b57cec5SDimitry Andric #if OMPT_SUPPORT
5490b57cec5SDimitry Andric                   ,
5500b57cec5SDimitry Andric                   fork_context_intel
5510b57cec5SDimitry Andric #endif
5520b57cec5SDimitry Andric   );
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric   // Pop current CG root off list
5550b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this_thr->th.th_cg_roots);
5560b57cec5SDimitry Andric   kmp_cg_root_t *tmp = this_thr->th.th_cg_roots;
5570b57cec5SDimitry Andric   this_thr->th.th_cg_roots = tmp->up;
5580b57cec5SDimitry Andric   KA_TRACE(100, ("__kmpc_fork_teams: Thread %p popping node %p and moving up"
5590b57cec5SDimitry Andric                  " to node %p. cg_nthreads was %d\n",
5600b57cec5SDimitry Andric                  this_thr, tmp, this_thr->th.th_cg_roots, tmp->cg_nthreads));
5610b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(tmp->cg_nthreads);
5620b57cec5SDimitry Andric   int i = tmp->cg_nthreads--;
5630b57cec5SDimitry Andric   if (i == 1) { // check is we are the last thread in CG (not always the case)
5640b57cec5SDimitry Andric     __kmp_free(tmp);
5650b57cec5SDimitry Andric   }
5660b57cec5SDimitry Andric   // Restore current task's thread_limit from CG root
5670b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this_thr->th.th_cg_roots);
5680b57cec5SDimitry Andric   this_thr->th.th_current_task->td_icvs.thread_limit =
5690b57cec5SDimitry Andric       this_thr->th.th_cg_roots->cg_thread_limit;
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   this_thr->th.th_teams_microtask = NULL;
5720b57cec5SDimitry Andric   this_thr->th.th_teams_level = 0;
5730b57cec5SDimitry Andric   *(kmp_int64 *)(&this_thr->th.th_teams_size) = 0L;
5740b57cec5SDimitry Andric   va_end(ap);
5750b57cec5SDimitry Andric #if KMP_STATS_ENABLED
5760b57cec5SDimitry Andric   if (previous_state == stats_state_e::SERIAL_REGION) {
5770b57cec5SDimitry Andric     KMP_EXCHANGE_PARTITIONED_TIMER(OMP_serial);
578e8d8bef9SDimitry Andric     KMP_SET_THREAD_STATE(previous_state);
5790b57cec5SDimitry Andric   } else {
5800b57cec5SDimitry Andric     KMP_POP_PARTITIONED_TIMER();
5810b57cec5SDimitry Andric   }
5820b57cec5SDimitry Andric #endif // KMP_STATS_ENABLED
5830b57cec5SDimitry Andric }
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric // I don't think this function should ever have been exported.
5860b57cec5SDimitry Andric // The __kmpc_ prefix was misapplied.  I'm fairly certain that no generated
5870b57cec5SDimitry Andric // openmp code ever called it, but it's been exported from the RTL for so
5880b57cec5SDimitry Andric // long that I'm afraid to remove the definition.
5890b57cec5SDimitry Andric int __kmpc_invoke_task_func(int gtid) { return __kmp_invoke_task_func(gtid); }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric /*!
5920b57cec5SDimitry Andric @ingroup PARALLEL
5930b57cec5SDimitry Andric @param loc  source location information
5940b57cec5SDimitry Andric @param global_tid  global thread number
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric Enter a serialized parallel construct. This interface is used to handle a
5970b57cec5SDimitry Andric conditional parallel region, like this,
5980b57cec5SDimitry Andric @code
5990b57cec5SDimitry Andric #pragma omp parallel if (condition)
6000b57cec5SDimitry Andric @endcode
6010b57cec5SDimitry Andric when the condition is false.
6020b57cec5SDimitry Andric */
6030b57cec5SDimitry Andric void __kmpc_serialized_parallel(ident_t *loc, kmp_int32 global_tid) {
6040b57cec5SDimitry Andric   // The implementation is now in kmp_runtime.cpp so that it can share static
6050b57cec5SDimitry Andric   // functions with kmp_fork_call since the tasks to be done are similar in
6060b57cec5SDimitry Andric   // each case.
607e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
6080b57cec5SDimitry Andric #if OMPT_SUPPORT
6090b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(global_tid);
6100b57cec5SDimitry Andric #endif
6110b57cec5SDimitry Andric   __kmp_serialized_parallel(loc, global_tid);
6120b57cec5SDimitry Andric }
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric /*!
6150b57cec5SDimitry Andric @ingroup PARALLEL
6160b57cec5SDimitry Andric @param loc  source location information
6170b57cec5SDimitry Andric @param global_tid  global thread number
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric Leave a serialized parallel construct.
6200b57cec5SDimitry Andric */
6210b57cec5SDimitry Andric void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32 global_tid) {
6220b57cec5SDimitry Andric   kmp_internal_control_t *top;
6230b57cec5SDimitry Andric   kmp_info_t *this_thr;
6240b57cec5SDimitry Andric   kmp_team_t *serial_team;
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric   KC_TRACE(10,
6270b57cec5SDimitry Andric            ("__kmpc_end_serialized_parallel: called by T#%d\n", global_tid));
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric   /* skip all this code for autopar serialized loops since it results in
6300b57cec5SDimitry Andric      unacceptable overhead */
6310b57cec5SDimitry Andric   if (loc != NULL && (loc->flags & KMP_IDENT_AUTOPAR))
6320b57cec5SDimitry Andric     return;
6330b57cec5SDimitry Andric 
6340b57cec5SDimitry Andric   // Not autopar code
635e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
6360b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
6370b57cec5SDimitry Andric     __kmp_parallel_initialize();
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric   this_thr = __kmp_threads[global_tid];
6420b57cec5SDimitry Andric   serial_team = this_thr->th.th_serial_team;
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric   kmp_task_team_t *task_team = this_thr->th.th_task_team;
6450b57cec5SDimitry Andric   // we need to wait for the proxy tasks before finishing the thread
64604eeddc0SDimitry Andric   if (task_team != NULL && (task_team->tt.tt_found_proxy_tasks ||
64704eeddc0SDimitry Andric                             task_team->tt.tt_hidden_helper_task_encountered))
6480b57cec5SDimitry Andric     __kmp_task_team_wait(this_thr, serial_team USE_ITT_BUILD_ARG(NULL));
6490b57cec5SDimitry Andric 
6500b57cec5SDimitry Andric   KMP_MB();
6510b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(serial_team);
6520b57cec5SDimitry Andric   KMP_ASSERT(serial_team->t.t_serialized);
6530b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this_thr->th.th_team == serial_team);
6540b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(serial_team != this_thr->th.th_root->r.r_root_team);
6550b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(serial_team->t.t_threads);
6560b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(serial_team->t.t_threads[0] == this_thr);
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric #if OMPT_SUPPORT
6590b57cec5SDimitry Andric   if (ompt_enabled.enabled &&
6600b57cec5SDimitry Andric       this_thr->th.ompt_thread_info.state != ompt_state_overhead) {
6610b57cec5SDimitry Andric     OMPT_CUR_TASK_INFO(this_thr)->frame.exit_frame = ompt_data_none;
6620b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_implicit_task) {
6630b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
6640b57cec5SDimitry Andric           ompt_scope_end, NULL, OMPT_CUR_TASK_DATA(this_thr), 1,
6650b57cec5SDimitry Andric           OMPT_CUR_TASK_INFO(this_thr)->thread_num, ompt_task_implicit);
6660b57cec5SDimitry Andric     }
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric     // reset clear the task id only after unlinking the task
6690b57cec5SDimitry Andric     ompt_data_t *parent_task_data;
6700b57cec5SDimitry Andric     __ompt_get_task_info_internal(1, NULL, &parent_task_data, NULL, NULL, NULL);
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_parallel_end) {
6730b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_parallel_end)(
6740b57cec5SDimitry Andric           &(serial_team->t.ompt_team_info.parallel_data), parent_task_data,
675489b1cf2SDimitry Andric           ompt_parallel_invoker_program | ompt_parallel_team,
676489b1cf2SDimitry Andric           OMPT_LOAD_RETURN_ADDRESS(global_tid));
6770b57cec5SDimitry Andric     }
6780b57cec5SDimitry Andric     __ompt_lw_taskteam_unlink(this_thr);
6790b57cec5SDimitry Andric     this_thr->th.ompt_thread_info.state = ompt_state_overhead;
6800b57cec5SDimitry Andric   }
6810b57cec5SDimitry Andric #endif
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   /* If necessary, pop the internal control stack values and replace the team
6840b57cec5SDimitry Andric    * values */
6850b57cec5SDimitry Andric   top = serial_team->t.t_control_stack_top;
6860b57cec5SDimitry Andric   if (top && top->serial_nesting_level == serial_team->t.t_serialized) {
6870b57cec5SDimitry Andric     copy_icvs(&serial_team->t.t_threads[0]->th.th_current_task->td_icvs, top);
6880b57cec5SDimitry Andric     serial_team->t.t_control_stack_top = top->next;
6890b57cec5SDimitry Andric     __kmp_free(top);
6900b57cec5SDimitry Andric   }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   /* pop dispatch buffers stack */
6930b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(serial_team->t.t_dispatch->th_disp_buffer);
6940b57cec5SDimitry Andric   {
6950b57cec5SDimitry Andric     dispatch_private_info_t *disp_buffer =
6960b57cec5SDimitry Andric         serial_team->t.t_dispatch->th_disp_buffer;
6970b57cec5SDimitry Andric     serial_team->t.t_dispatch->th_disp_buffer =
6980b57cec5SDimitry Andric         serial_team->t.t_dispatch->th_disp_buffer->next;
6990b57cec5SDimitry Andric     __kmp_free(disp_buffer);
7000b57cec5SDimitry Andric   }
701*0fca6ea1SDimitry Andric 
702*0fca6ea1SDimitry Andric   /* pop the task team stack */
703*0fca6ea1SDimitry Andric   if (serial_team->t.t_serialized > 1) {
704*0fca6ea1SDimitry Andric     __kmp_pop_task_team_node(this_thr, serial_team);
705*0fca6ea1SDimitry Andric   }
706*0fca6ea1SDimitry Andric 
7070b57cec5SDimitry Andric   this_thr->th.th_def_allocator = serial_team->t.t_def_allocator; // restore
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric   --serial_team->t.t_serialized;
7100b57cec5SDimitry Andric   if (serial_team->t.t_serialized == 0) {
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric     /* return to the parallel section */
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric #if KMP_ARCH_X86 || KMP_ARCH_X86_64
7150b57cec5SDimitry Andric     if (__kmp_inherit_fp_control && serial_team->t.t_fp_control_saved) {
7160b57cec5SDimitry Andric       __kmp_clear_x87_fpu_status_word();
7170b57cec5SDimitry Andric       __kmp_load_x87_fpu_control_word(&serial_team->t.t_x87_fpu_control_word);
7180b57cec5SDimitry Andric       __kmp_load_mxcsr(&serial_team->t.t_mxcsr);
7190b57cec5SDimitry Andric     }
7200b57cec5SDimitry Andric #endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
7210b57cec5SDimitry Andric 
722349cc55cSDimitry Andric     __kmp_pop_current_task_from_thread(this_thr);
723fe6060f1SDimitry Andric #if OMPD_SUPPORT
724fe6060f1SDimitry Andric     if (ompd_state & OMPD_ENABLE_BP)
725fe6060f1SDimitry Andric       ompd_bp_parallel_end();
726fe6060f1SDimitry Andric #endif
727fe6060f1SDimitry Andric 
7280b57cec5SDimitry Andric     this_thr->th.th_team = serial_team->t.t_parent;
7290b57cec5SDimitry Andric     this_thr->th.th_info.ds.ds_tid = serial_team->t.t_master_tid;
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric     /* restore values cached in the thread */
7320b57cec5SDimitry Andric     this_thr->th.th_team_nproc = serial_team->t.t_parent->t.t_nproc; /*  JPH */
7330b57cec5SDimitry Andric     this_thr->th.th_team_master =
7340b57cec5SDimitry Andric         serial_team->t.t_parent->t.t_threads[0]; /* JPH */
7350b57cec5SDimitry Andric     this_thr->th.th_team_serialized = this_thr->th.th_team->t.t_serialized;
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric     /* TODO the below shouldn't need to be adjusted for serialized teams */
7380b57cec5SDimitry Andric     this_thr->th.th_dispatch =
7390b57cec5SDimitry Andric         &this_thr->th.th_team->t.t_dispatch[serial_team->t.t_master_tid];
7400b57cec5SDimitry Andric 
7410b57cec5SDimitry Andric     KMP_ASSERT(this_thr->th.th_current_task->td_flags.executing == 0);
7420b57cec5SDimitry Andric     this_thr->th.th_current_task->td_flags.executing = 1;
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric     if (__kmp_tasking_mode != tskm_immediate_exec) {
745*0fca6ea1SDimitry Andric       // Restore task state from serial team structure
746*0fca6ea1SDimitry Andric       KMP_DEBUG_ASSERT(serial_team->t.t_primary_task_state == 0 ||
747*0fca6ea1SDimitry Andric                        serial_team->t.t_primary_task_state == 1);
748*0fca6ea1SDimitry Andric       this_thr->th.th_task_state =
749*0fca6ea1SDimitry Andric           (kmp_uint8)serial_team->t.t_primary_task_state;
7500b57cec5SDimitry Andric       // Copy the task team from the new child / old parent team to the thread.
7510b57cec5SDimitry Andric       this_thr->th.th_task_team =
7520b57cec5SDimitry Andric           this_thr->th.th_team->t.t_task_team[this_thr->th.th_task_state];
7530b57cec5SDimitry Andric       KA_TRACE(20,
7540b57cec5SDimitry Andric                ("__kmpc_end_serialized_parallel: T#%d restoring task_team %p / "
7550b57cec5SDimitry Andric                 "team %p\n",
7560b57cec5SDimitry Andric                 global_tid, this_thr->th.th_task_team, this_thr->th.th_team));
7570b57cec5SDimitry Andric     }
758fcaf7f86SDimitry Andric #if KMP_AFFINITY_SUPPORTED
759bdd1243dSDimitry Andric     if (this_thr->th.th_team->t.t_level == 0 && __kmp_affinity.flags.reset) {
760fcaf7f86SDimitry Andric       __kmp_reset_root_init_mask(global_tid);
761fcaf7f86SDimitry Andric     }
762fcaf7f86SDimitry Andric #endif
7630b57cec5SDimitry Andric   } else {
7640b57cec5SDimitry Andric     if (__kmp_tasking_mode != tskm_immediate_exec) {
7650b57cec5SDimitry Andric       KA_TRACE(20, ("__kmpc_end_serialized_parallel: T#%d decreasing nesting "
7660b57cec5SDimitry Andric                     "depth of serial team %p to %d\n",
7670b57cec5SDimitry Andric                     global_tid, serial_team, serial_team->t.t_serialized));
7680b57cec5SDimitry Andric     }
7690b57cec5SDimitry Andric   }
7700b57cec5SDimitry Andric 
771349cc55cSDimitry Andric   serial_team->t.t_level--;
7720b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
7730b57cec5SDimitry Andric     __kmp_pop_parallel(global_tid, NULL);
7740b57cec5SDimitry Andric #if OMPT_SUPPORT
7750b57cec5SDimitry Andric   if (ompt_enabled.enabled)
7760b57cec5SDimitry Andric     this_thr->th.ompt_thread_info.state =
7770b57cec5SDimitry Andric         ((this_thr->th.th_team_serialized) ? ompt_state_work_serial
7780b57cec5SDimitry Andric                                            : ompt_state_work_parallel);
7790b57cec5SDimitry Andric #endif
7800b57cec5SDimitry Andric }
7810b57cec5SDimitry Andric 
7820b57cec5SDimitry Andric /*!
7830b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
7840b57cec5SDimitry Andric @param loc  source location information.
7850b57cec5SDimitry Andric 
7860b57cec5SDimitry Andric Execute <tt>flush</tt>. This is implemented as a full memory fence. (Though
7870b57cec5SDimitry Andric depending on the memory ordering convention obeyed by the compiler
7880b57cec5SDimitry Andric even that may not be necessary).
7890b57cec5SDimitry Andric */
7900b57cec5SDimitry Andric void __kmpc_flush(ident_t *loc) {
7910b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_flush: called\n"));
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   /* need explicit __mf() here since use volatile instead in library */
794bdd1243dSDimitry Andric   KMP_MFENCE(); /* Flush all pending memory write invalidates.  */
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
7970b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_flush) {
7980b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_flush)(
7990b57cec5SDimitry Andric         __ompt_get_thread_data_internal(), OMPT_GET_RETURN_ADDRESS(0));
8000b57cec5SDimitry Andric   }
8010b57cec5SDimitry Andric #endif
8020b57cec5SDimitry Andric }
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric /* -------------------------------------------------------------------------- */
8050b57cec5SDimitry Andric /*!
8060b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
8070b57cec5SDimitry Andric @param loc source location information
8080b57cec5SDimitry Andric @param global_tid thread id.
8090b57cec5SDimitry Andric 
8100b57cec5SDimitry Andric Execute a barrier.
8110b57cec5SDimitry Andric */
8120b57cec5SDimitry Andric void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid) {
8130b57cec5SDimitry Andric   KMP_COUNT_BLOCK(OMP_BARRIER);
8140b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_barrier: called T#%d\n", global_tid));
815e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
8180b57cec5SDimitry Andric     __kmp_parallel_initialize();
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
8230b57cec5SDimitry Andric     if (loc == 0) {
8240b57cec5SDimitry Andric       KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
8250b57cec5SDimitry Andric     }
8260b57cec5SDimitry Andric     __kmp_check_barrier(global_tid, ct_barrier, loc);
8270b57cec5SDimitry Andric   }
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric #if OMPT_SUPPORT
8300b57cec5SDimitry Andric   ompt_frame_t *ompt_frame;
8310b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
8320b57cec5SDimitry Andric     __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
8330b57cec5SDimitry Andric     if (ompt_frame->enter_frame.ptr == NULL)
8340b57cec5SDimitry Andric       ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
8350b57cec5SDimitry Andric   }
836e8d8bef9SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(global_tid);
8370b57cec5SDimitry Andric #endif
8380b57cec5SDimitry Andric   __kmp_threads[global_tid]->th.th_ident = loc;
8390b57cec5SDimitry Andric   // TODO: explicit barrier_wait_id:
8400b57cec5SDimitry Andric   //   this function is called when 'barrier' directive is present or
8410b57cec5SDimitry Andric   //   implicit barrier at the end of a worksharing construct.
8420b57cec5SDimitry Andric   // 1) better to add a per-thread barrier counter to a thread data structure
8430b57cec5SDimitry Andric   // 2) set to 0 when a new team is created
8440b57cec5SDimitry Andric   // 4) no sync is required
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric   __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
8470b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
8480b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
8490b57cec5SDimitry Andric     ompt_frame->enter_frame = ompt_data_none;
8500b57cec5SDimitry Andric   }
8510b57cec5SDimitry Andric #endif
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric /* The BARRIER for a MASTER section is always explicit   */
8550b57cec5SDimitry Andric /*!
8560b57cec5SDimitry Andric @ingroup WORK_SHARING
8570b57cec5SDimitry Andric @param loc  source location information.
8580b57cec5SDimitry Andric @param global_tid  global thread number .
8590b57cec5SDimitry Andric @return 1 if this thread should execute the <tt>master</tt> block, 0 otherwise.
8600b57cec5SDimitry Andric */
8610b57cec5SDimitry Andric kmp_int32 __kmpc_master(ident_t *loc, kmp_int32 global_tid) {
8620b57cec5SDimitry Andric   int status = 0;
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_master: called T#%d\n", global_tid));
865e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
8660b57cec5SDimitry Andric 
8670b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
8680b57cec5SDimitry Andric     __kmp_parallel_initialize();
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric   if (KMP_MASTER_GTID(global_tid)) {
8730b57cec5SDimitry Andric     KMP_COUNT_BLOCK(OMP_MASTER);
8740b57cec5SDimitry Andric     KMP_PUSH_PARTITIONED_TIMER(OMP_master);
8750b57cec5SDimitry Andric     status = 1;
8760b57cec5SDimitry Andric   }
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
8790b57cec5SDimitry Andric   if (status) {
880e8d8bef9SDimitry Andric     if (ompt_enabled.ompt_callback_masked) {
8810b57cec5SDimitry Andric       kmp_info_t *this_thr = __kmp_threads[global_tid];
8820b57cec5SDimitry Andric       kmp_team_t *team = this_thr->th.th_team;
8830b57cec5SDimitry Andric 
8840b57cec5SDimitry Andric       int tid = __kmp_tid_from_gtid(global_tid);
885e8d8bef9SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_masked)(
8860b57cec5SDimitry Andric           ompt_scope_begin, &(team->t.ompt_team_info.parallel_data),
8870b57cec5SDimitry Andric           &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
8880b57cec5SDimitry Andric           OMPT_GET_RETURN_ADDRESS(0));
8890b57cec5SDimitry Andric     }
8900b57cec5SDimitry Andric   }
8910b57cec5SDimitry Andric #endif
8920b57cec5SDimitry Andric 
8930b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
8940b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
8950b57cec5SDimitry Andric     if (status)
8960b57cec5SDimitry Andric       __kmp_push_sync(global_tid, ct_master, loc, NULL, 0);
8970b57cec5SDimitry Andric     else
8980b57cec5SDimitry Andric       __kmp_check_sync(global_tid, ct_master, loc, NULL, 0);
8990b57cec5SDimitry Andric #else
9000b57cec5SDimitry Andric     if (status)
9010b57cec5SDimitry Andric       __kmp_push_sync(global_tid, ct_master, loc, NULL);
9020b57cec5SDimitry Andric     else
9030b57cec5SDimitry Andric       __kmp_check_sync(global_tid, ct_master, loc, NULL);
9040b57cec5SDimitry Andric #endif
9050b57cec5SDimitry Andric   }
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric   return status;
9080b57cec5SDimitry Andric }
9090b57cec5SDimitry Andric 
9100b57cec5SDimitry Andric /*!
9110b57cec5SDimitry Andric @ingroup WORK_SHARING
9120b57cec5SDimitry Andric @param loc  source location information.
9130b57cec5SDimitry Andric @param global_tid  global thread number .
9140b57cec5SDimitry Andric 
9150b57cec5SDimitry Andric Mark the end of a <tt>master</tt> region. This should only be called by the
9160b57cec5SDimitry Andric thread that executes the <tt>master</tt> region.
9170b57cec5SDimitry Andric */
9180b57cec5SDimitry Andric void __kmpc_end_master(ident_t *loc, kmp_int32 global_tid) {
9190b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_end_master: called T#%d\n", global_tid));
920e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
9210b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(KMP_MASTER_GTID(global_tid));
9220b57cec5SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
9230b57cec5SDimitry Andric 
9240b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
9250b57cec5SDimitry Andric   kmp_info_t *this_thr = __kmp_threads[global_tid];
9260b57cec5SDimitry Andric   kmp_team_t *team = this_thr->th.th_team;
927e8d8bef9SDimitry Andric   if (ompt_enabled.ompt_callback_masked) {
9280b57cec5SDimitry Andric     int tid = __kmp_tid_from_gtid(global_tid);
929e8d8bef9SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_masked)(
9300b57cec5SDimitry Andric         ompt_scope_end, &(team->t.ompt_team_info.parallel_data),
9310b57cec5SDimitry Andric         &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
9320b57cec5SDimitry Andric         OMPT_GET_RETURN_ADDRESS(0));
9330b57cec5SDimitry Andric   }
9340b57cec5SDimitry Andric #endif
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
9370b57cec5SDimitry Andric     if (KMP_MASTER_GTID(global_tid))
9380b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_master, loc);
9390b57cec5SDimitry Andric   }
9400b57cec5SDimitry Andric }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric /*!
9430b57cec5SDimitry Andric @ingroup WORK_SHARING
9440b57cec5SDimitry Andric @param loc  source location information.
945fe6060f1SDimitry Andric @param global_tid  global thread number.
946fe6060f1SDimitry Andric @param filter result of evaluating filter clause on thread global_tid, or zero
947fe6060f1SDimitry Andric if no filter clause present
948fe6060f1SDimitry Andric @return 1 if this thread should execute the <tt>masked</tt> block, 0 otherwise.
949fe6060f1SDimitry Andric */
950fe6060f1SDimitry Andric kmp_int32 __kmpc_masked(ident_t *loc, kmp_int32 global_tid, kmp_int32 filter) {
951fe6060f1SDimitry Andric   int status = 0;
952fe6060f1SDimitry Andric   int tid;
953fe6060f1SDimitry Andric   KC_TRACE(10, ("__kmpc_masked: called T#%d\n", global_tid));
954fe6060f1SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
955fe6060f1SDimitry Andric 
956fe6060f1SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
957fe6060f1SDimitry Andric     __kmp_parallel_initialize();
958fe6060f1SDimitry Andric 
959fe6060f1SDimitry Andric   __kmp_resume_if_soft_paused();
960fe6060f1SDimitry Andric 
961fe6060f1SDimitry Andric   tid = __kmp_tid_from_gtid(global_tid);
962fe6060f1SDimitry Andric   if (tid == filter) {
963fe6060f1SDimitry Andric     KMP_COUNT_BLOCK(OMP_MASKED);
964fe6060f1SDimitry Andric     KMP_PUSH_PARTITIONED_TIMER(OMP_masked);
965fe6060f1SDimitry Andric     status = 1;
966fe6060f1SDimitry Andric   }
967fe6060f1SDimitry Andric 
968fe6060f1SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
969fe6060f1SDimitry Andric   if (status) {
970fe6060f1SDimitry Andric     if (ompt_enabled.ompt_callback_masked) {
971fe6060f1SDimitry Andric       kmp_info_t *this_thr = __kmp_threads[global_tid];
972fe6060f1SDimitry Andric       kmp_team_t *team = this_thr->th.th_team;
973fe6060f1SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_masked)(
974fe6060f1SDimitry Andric           ompt_scope_begin, &(team->t.ompt_team_info.parallel_data),
975fe6060f1SDimitry Andric           &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
976fe6060f1SDimitry Andric           OMPT_GET_RETURN_ADDRESS(0));
977fe6060f1SDimitry Andric     }
978fe6060f1SDimitry Andric   }
979fe6060f1SDimitry Andric #endif
980fe6060f1SDimitry Andric 
981fe6060f1SDimitry Andric   if (__kmp_env_consistency_check) {
982fe6060f1SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
983fe6060f1SDimitry Andric     if (status)
984fe6060f1SDimitry Andric       __kmp_push_sync(global_tid, ct_masked, loc, NULL, 0);
985fe6060f1SDimitry Andric     else
986fe6060f1SDimitry Andric       __kmp_check_sync(global_tid, ct_masked, loc, NULL, 0);
987fe6060f1SDimitry Andric #else
988fe6060f1SDimitry Andric     if (status)
989fe6060f1SDimitry Andric       __kmp_push_sync(global_tid, ct_masked, loc, NULL);
990fe6060f1SDimitry Andric     else
991fe6060f1SDimitry Andric       __kmp_check_sync(global_tid, ct_masked, loc, NULL);
992fe6060f1SDimitry Andric #endif
993fe6060f1SDimitry Andric   }
994fe6060f1SDimitry Andric 
995fe6060f1SDimitry Andric   return status;
996fe6060f1SDimitry Andric }
997fe6060f1SDimitry Andric 
998fe6060f1SDimitry Andric /*!
999fe6060f1SDimitry Andric @ingroup WORK_SHARING
1000fe6060f1SDimitry Andric @param loc  source location information.
1001fe6060f1SDimitry Andric @param global_tid  global thread number .
1002fe6060f1SDimitry Andric 
1003fe6060f1SDimitry Andric Mark the end of a <tt>masked</tt> region. This should only be called by the
1004fe6060f1SDimitry Andric thread that executes the <tt>masked</tt> region.
1005fe6060f1SDimitry Andric */
1006fe6060f1SDimitry Andric void __kmpc_end_masked(ident_t *loc, kmp_int32 global_tid) {
1007fe6060f1SDimitry Andric   KC_TRACE(10, ("__kmpc_end_masked: called T#%d\n", global_tid));
1008fe6060f1SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
1009fe6060f1SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
1010fe6060f1SDimitry Andric 
1011fe6060f1SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
1012fe6060f1SDimitry Andric   kmp_info_t *this_thr = __kmp_threads[global_tid];
1013fe6060f1SDimitry Andric   kmp_team_t *team = this_thr->th.th_team;
1014fe6060f1SDimitry Andric   if (ompt_enabled.ompt_callback_masked) {
1015fe6060f1SDimitry Andric     int tid = __kmp_tid_from_gtid(global_tid);
1016fe6060f1SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_masked)(
1017fe6060f1SDimitry Andric         ompt_scope_end, &(team->t.ompt_team_info.parallel_data),
1018fe6060f1SDimitry Andric         &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1019fe6060f1SDimitry Andric         OMPT_GET_RETURN_ADDRESS(0));
1020fe6060f1SDimitry Andric   }
1021fe6060f1SDimitry Andric #endif
1022fe6060f1SDimitry Andric 
1023fe6060f1SDimitry Andric   if (__kmp_env_consistency_check) {
1024fe6060f1SDimitry Andric     __kmp_pop_sync(global_tid, ct_masked, loc);
1025fe6060f1SDimitry Andric   }
1026fe6060f1SDimitry Andric }
1027fe6060f1SDimitry Andric 
1028fe6060f1SDimitry Andric /*!
1029fe6060f1SDimitry Andric @ingroup WORK_SHARING
1030fe6060f1SDimitry Andric @param loc  source location information.
10310b57cec5SDimitry Andric @param gtid  global thread number.
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric Start execution of an <tt>ordered</tt> construct.
10340b57cec5SDimitry Andric */
10350b57cec5SDimitry Andric void __kmpc_ordered(ident_t *loc, kmp_int32 gtid) {
10360b57cec5SDimitry Andric   int cid = 0;
10370b57cec5SDimitry Andric   kmp_info_t *th;
10380b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_ordered: called T#%d\n", gtid));
1041e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
10420b57cec5SDimitry Andric 
10430b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
10440b57cec5SDimitry Andric     __kmp_parallel_initialize();
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric #if USE_ITT_BUILD
10490b57cec5SDimitry Andric   __kmp_itt_ordered_prep(gtid);
10500b57cec5SDimitry Andric // TODO: ordered_wait_id
10510b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
10520b57cec5SDimitry Andric 
10530b57cec5SDimitry Andric   th = __kmp_threads[gtid];
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
10560b57cec5SDimitry Andric   kmp_team_t *team;
10570b57cec5SDimitry Andric   ompt_wait_id_t lck;
10580b57cec5SDimitry Andric   void *codeptr_ra;
10590b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(gtid);
1060e8d8bef9SDimitry Andric   if (ompt_enabled.enabled) {
10610b57cec5SDimitry Andric     team = __kmp_team_from_gtid(gtid);
10620b57cec5SDimitry Andric     lck = (ompt_wait_id_t)(uintptr_t)&team->t.t_ordered.dt.t_value;
10630b57cec5SDimitry Andric     /* OMPT state update */
10640b57cec5SDimitry Andric     th->th.ompt_thread_info.wait_id = lck;
10650b57cec5SDimitry Andric     th->th.ompt_thread_info.state = ompt_state_wait_ordered;
10660b57cec5SDimitry Andric 
10670b57cec5SDimitry Andric     /* OMPT event callback */
10680b57cec5SDimitry Andric     codeptr_ra = OMPT_LOAD_RETURN_ADDRESS(gtid);
10690b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquire) {
10700b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
10710b57cec5SDimitry Andric           ompt_mutex_ordered, omp_lock_hint_none, kmp_mutex_impl_spin, lck,
10720b57cec5SDimitry Andric           codeptr_ra);
10730b57cec5SDimitry Andric     }
10740b57cec5SDimitry Andric   }
10750b57cec5SDimitry Andric #endif
10760b57cec5SDimitry Andric 
10770b57cec5SDimitry Andric   if (th->th.th_dispatch->th_deo_fcn != 0)
10780b57cec5SDimitry Andric     (*th->th.th_dispatch->th_deo_fcn)(&gtid, &cid, loc);
10790b57cec5SDimitry Andric   else
10800b57cec5SDimitry Andric     __kmp_parallel_deo(&gtid, &cid, loc);
10810b57cec5SDimitry Andric 
10820b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
10830b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
10840b57cec5SDimitry Andric     /* OMPT state update */
10850b57cec5SDimitry Andric     th->th.ompt_thread_info.state = ompt_state_work_parallel;
10860b57cec5SDimitry Andric     th->th.ompt_thread_info.wait_id = 0;
10870b57cec5SDimitry Andric 
10880b57cec5SDimitry Andric     /* OMPT event callback */
10890b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquired) {
10900b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
10910b57cec5SDimitry Andric           ompt_mutex_ordered, (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
10920b57cec5SDimitry Andric     }
10930b57cec5SDimitry Andric   }
10940b57cec5SDimitry Andric #endif
10950b57cec5SDimitry Andric 
10960b57cec5SDimitry Andric #if USE_ITT_BUILD
10970b57cec5SDimitry Andric   __kmp_itt_ordered_start(gtid);
10980b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
10990b57cec5SDimitry Andric }
11000b57cec5SDimitry Andric 
11010b57cec5SDimitry Andric /*!
11020b57cec5SDimitry Andric @ingroup WORK_SHARING
11030b57cec5SDimitry Andric @param loc  source location information.
11040b57cec5SDimitry Andric @param gtid  global thread number.
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric End execution of an <tt>ordered</tt> construct.
11070b57cec5SDimitry Andric */
11080b57cec5SDimitry Andric void __kmpc_end_ordered(ident_t *loc, kmp_int32 gtid) {
11090b57cec5SDimitry Andric   int cid = 0;
11100b57cec5SDimitry Andric   kmp_info_t *th;
11110b57cec5SDimitry Andric 
11120b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_end_ordered: called T#%d\n", gtid));
1113e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
11140b57cec5SDimitry Andric 
11150b57cec5SDimitry Andric #if USE_ITT_BUILD
11160b57cec5SDimitry Andric   __kmp_itt_ordered_end(gtid);
11170b57cec5SDimitry Andric // TODO: ordered_wait_id
11180b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric   th = __kmp_threads[gtid];
11210b57cec5SDimitry Andric 
11220b57cec5SDimitry Andric   if (th->th.th_dispatch->th_dxo_fcn != 0)
11230b57cec5SDimitry Andric     (*th->th.th_dispatch->th_dxo_fcn)(&gtid, &cid, loc);
11240b57cec5SDimitry Andric   else
11250b57cec5SDimitry Andric     __kmp_parallel_dxo(&gtid, &cid, loc);
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
11280b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(gtid);
11290b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_released) {
11300b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
11310b57cec5SDimitry Andric         ompt_mutex_ordered,
11320b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)&__kmp_team_from_gtid(gtid)
11330b57cec5SDimitry Andric             ->t.t_ordered.dt.t_value,
11340b57cec5SDimitry Andric         OMPT_LOAD_RETURN_ADDRESS(gtid));
11350b57cec5SDimitry Andric   }
11360b57cec5SDimitry Andric #endif
11370b57cec5SDimitry Andric }
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric static __forceinline void
11420b57cec5SDimitry Andric __kmp_init_indirect_csptr(kmp_critical_name *crit, ident_t const *loc,
11430b57cec5SDimitry Andric                           kmp_int32 gtid, kmp_indirect_locktag_t tag) {
11440b57cec5SDimitry Andric   // Pointer to the allocated indirect lock is written to crit, while indexing
11450b57cec5SDimitry Andric   // is ignored.
11460b57cec5SDimitry Andric   void *idx;
11470b57cec5SDimitry Andric   kmp_indirect_lock_t **lck;
11480b57cec5SDimitry Andric   lck = (kmp_indirect_lock_t **)crit;
11490b57cec5SDimitry Andric   kmp_indirect_lock_t *ilk = __kmp_allocate_indirect_lock(&idx, gtid, tag);
11500b57cec5SDimitry Andric   KMP_I_LOCK_FUNC(ilk, init)(ilk->lock);
11510b57cec5SDimitry Andric   KMP_SET_I_LOCK_LOCATION(ilk, loc);
11520b57cec5SDimitry Andric   KMP_SET_I_LOCK_FLAGS(ilk, kmp_lf_critical_section);
11530b57cec5SDimitry Andric   KA_TRACE(20,
11540b57cec5SDimitry Andric            ("__kmp_init_indirect_csptr: initialized indirect lock #%d\n", tag));
11550b57cec5SDimitry Andric #if USE_ITT_BUILD
11560b57cec5SDimitry Andric   __kmp_itt_critical_creating(ilk->lock, loc);
11570b57cec5SDimitry Andric #endif
11580b57cec5SDimitry Andric   int status = KMP_COMPARE_AND_STORE_PTR(lck, nullptr, ilk);
11590b57cec5SDimitry Andric   if (status == 0) {
11600b57cec5SDimitry Andric #if USE_ITT_BUILD
11610b57cec5SDimitry Andric     __kmp_itt_critical_destroyed(ilk->lock);
11620b57cec5SDimitry Andric #endif
11630b57cec5SDimitry Andric     // We don't really need to destroy the unclaimed lock here since it will be
11640b57cec5SDimitry Andric     // cleaned up at program exit.
11650b57cec5SDimitry Andric     // KMP_D_LOCK_FUNC(&idx, destroy)((kmp_dyna_lock_t *)&idx);
11660b57cec5SDimitry Andric   }
11670b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(*lck != NULL);
11680b57cec5SDimitry Andric }
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric // Fast-path acquire tas lock
11710b57cec5SDimitry Andric #define KMP_ACQUIRE_TAS_LOCK(lock, gtid)                                       \
11720b57cec5SDimitry Andric   {                                                                            \
11730b57cec5SDimitry Andric     kmp_tas_lock_t *l = (kmp_tas_lock_t *)lock;                                \
11740b57cec5SDimitry Andric     kmp_int32 tas_free = KMP_LOCK_FREE(tas);                                   \
11750b57cec5SDimitry Andric     kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas);                         \
11760b57cec5SDimitry Andric     if (KMP_ATOMIC_LD_RLX(&l->lk.poll) != tas_free ||                          \
11770b57cec5SDimitry Andric         !__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy)) {    \
11780b57cec5SDimitry Andric       kmp_uint32 spins;                                                        \
11790b57cec5SDimitry Andric       KMP_FSYNC_PREPARE(l);                                                    \
11800b57cec5SDimitry Andric       KMP_INIT_YIELD(spins);                                                   \
11810b57cec5SDimitry Andric       kmp_backoff_t backoff = __kmp_spin_backoff_params;                       \
11820b57cec5SDimitry Andric       do {                                                                     \
11830b57cec5SDimitry Andric         if (TCR_4(__kmp_nth) >                                                 \
11840b57cec5SDimitry Andric             (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) {             \
11850b57cec5SDimitry Andric           KMP_YIELD(TRUE);                                                     \
11860b57cec5SDimitry Andric         } else {                                                               \
11870b57cec5SDimitry Andric           KMP_YIELD_SPIN(spins);                                               \
11880b57cec5SDimitry Andric         }                                                                      \
11890b57cec5SDimitry Andric         __kmp_spin_backoff(&backoff);                                          \
11900b57cec5SDimitry Andric       } while (                                                                \
11910b57cec5SDimitry Andric           KMP_ATOMIC_LD_RLX(&l->lk.poll) != tas_free ||                        \
11920b57cec5SDimitry Andric           !__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy));   \
11930b57cec5SDimitry Andric     }                                                                          \
11940b57cec5SDimitry Andric     KMP_FSYNC_ACQUIRED(l);                                                     \
11950b57cec5SDimitry Andric   }
11960b57cec5SDimitry Andric 
11970b57cec5SDimitry Andric // Fast-path test tas lock
11980b57cec5SDimitry Andric #define KMP_TEST_TAS_LOCK(lock, gtid, rc)                                      \
11990b57cec5SDimitry Andric   {                                                                            \
12000b57cec5SDimitry Andric     kmp_tas_lock_t *l = (kmp_tas_lock_t *)lock;                                \
12010b57cec5SDimitry Andric     kmp_int32 tas_free = KMP_LOCK_FREE(tas);                                   \
12020b57cec5SDimitry Andric     kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas);                         \
12030b57cec5SDimitry Andric     rc = KMP_ATOMIC_LD_RLX(&l->lk.poll) == tas_free &&                         \
12040b57cec5SDimitry Andric          __kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy);      \
12050b57cec5SDimitry Andric   }
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric // Fast-path release tas lock
12080b57cec5SDimitry Andric #define KMP_RELEASE_TAS_LOCK(lock, gtid)                                       \
12090b57cec5SDimitry Andric   { KMP_ATOMIC_ST_REL(&((kmp_tas_lock_t *)lock)->lk.poll, KMP_LOCK_FREE(tas)); }
12100b57cec5SDimitry Andric 
12110b57cec5SDimitry Andric #if KMP_USE_FUTEX
12120b57cec5SDimitry Andric 
12130b57cec5SDimitry Andric #include <sys/syscall.h>
12140b57cec5SDimitry Andric #include <unistd.h>
12150b57cec5SDimitry Andric #ifndef FUTEX_WAIT
12160b57cec5SDimitry Andric #define FUTEX_WAIT 0
12170b57cec5SDimitry Andric #endif
12180b57cec5SDimitry Andric #ifndef FUTEX_WAKE
12190b57cec5SDimitry Andric #define FUTEX_WAKE 1
12200b57cec5SDimitry Andric #endif
12210b57cec5SDimitry Andric 
12220b57cec5SDimitry Andric // Fast-path acquire futex lock
12230b57cec5SDimitry Andric #define KMP_ACQUIRE_FUTEX_LOCK(lock, gtid)                                     \
12240b57cec5SDimitry Andric   {                                                                            \
12250b57cec5SDimitry Andric     kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock;                          \
12260b57cec5SDimitry Andric     kmp_int32 gtid_code = (gtid + 1) << 1;                                     \
12270b57cec5SDimitry Andric     KMP_MB();                                                                  \
12280b57cec5SDimitry Andric     KMP_FSYNC_PREPARE(ftx);                                                    \
12290b57cec5SDimitry Andric     kmp_int32 poll_val;                                                        \
12300b57cec5SDimitry Andric     while ((poll_val = KMP_COMPARE_AND_STORE_RET32(                            \
12310b57cec5SDimitry Andric                 &(ftx->lk.poll), KMP_LOCK_FREE(futex),                         \
12320b57cec5SDimitry Andric                 KMP_LOCK_BUSY(gtid_code, futex))) != KMP_LOCK_FREE(futex)) {   \
12330b57cec5SDimitry Andric       kmp_int32 cond = KMP_LOCK_STRIP(poll_val) & 1;                           \
12340b57cec5SDimitry Andric       if (!cond) {                                                             \
12350b57cec5SDimitry Andric         if (!KMP_COMPARE_AND_STORE_RET32(&(ftx->lk.poll), poll_val,            \
12360b57cec5SDimitry Andric                                          poll_val |                            \
12370b57cec5SDimitry Andric                                              KMP_LOCK_BUSY(1, futex))) {       \
12380b57cec5SDimitry Andric           continue;                                                            \
12390b57cec5SDimitry Andric         }                                                                      \
12400b57cec5SDimitry Andric         poll_val |= KMP_LOCK_BUSY(1, futex);                                   \
12410b57cec5SDimitry Andric       }                                                                        \
12420b57cec5SDimitry Andric       kmp_int32 rc;                                                            \
12430b57cec5SDimitry Andric       if ((rc = syscall(__NR_futex, &(ftx->lk.poll), FUTEX_WAIT, poll_val,     \
12440b57cec5SDimitry Andric                         NULL, NULL, 0)) != 0) {                                \
12450b57cec5SDimitry Andric         continue;                                                              \
12460b57cec5SDimitry Andric       }                                                                        \
12470b57cec5SDimitry Andric       gtid_code |= 1;                                                          \
12480b57cec5SDimitry Andric     }                                                                          \
12490b57cec5SDimitry Andric     KMP_FSYNC_ACQUIRED(ftx);                                                   \
12500b57cec5SDimitry Andric   }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric // Fast-path test futex lock
12530b57cec5SDimitry Andric #define KMP_TEST_FUTEX_LOCK(lock, gtid, rc)                                    \
12540b57cec5SDimitry Andric   {                                                                            \
12550b57cec5SDimitry Andric     kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock;                          \
12560b57cec5SDimitry Andric     if (KMP_COMPARE_AND_STORE_ACQ32(&(ftx->lk.poll), KMP_LOCK_FREE(futex),     \
12570b57cec5SDimitry Andric                                     KMP_LOCK_BUSY(gtid + 1 << 1, futex))) {    \
12580b57cec5SDimitry Andric       KMP_FSYNC_ACQUIRED(ftx);                                                 \
12590b57cec5SDimitry Andric       rc = TRUE;                                                               \
12600b57cec5SDimitry Andric     } else {                                                                   \
12610b57cec5SDimitry Andric       rc = FALSE;                                                              \
12620b57cec5SDimitry Andric     }                                                                          \
12630b57cec5SDimitry Andric   }
12640b57cec5SDimitry Andric 
12650b57cec5SDimitry Andric // Fast-path release futex lock
12660b57cec5SDimitry Andric #define KMP_RELEASE_FUTEX_LOCK(lock, gtid)                                     \
12670b57cec5SDimitry Andric   {                                                                            \
12680b57cec5SDimitry Andric     kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock;                          \
12690b57cec5SDimitry Andric     KMP_MB();                                                                  \
12700b57cec5SDimitry Andric     KMP_FSYNC_RELEASING(ftx);                                                  \
12710b57cec5SDimitry Andric     kmp_int32 poll_val =                                                       \
12720b57cec5SDimitry Andric         KMP_XCHG_FIXED32(&(ftx->lk.poll), KMP_LOCK_FREE(futex));               \
12730b57cec5SDimitry Andric     if (KMP_LOCK_STRIP(poll_val) & 1) {                                        \
12740b57cec5SDimitry Andric       syscall(__NR_futex, &(ftx->lk.poll), FUTEX_WAKE,                         \
12750b57cec5SDimitry Andric               KMP_LOCK_BUSY(1, futex), NULL, NULL, 0);                         \
12760b57cec5SDimitry Andric     }                                                                          \
12770b57cec5SDimitry Andric     KMP_MB();                                                                  \
12780b57cec5SDimitry Andric     KMP_YIELD_OVERSUB();                                                       \
12790b57cec5SDimitry Andric   }
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric #endif // KMP_USE_FUTEX
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
12840b57cec5SDimitry Andric 
12850b57cec5SDimitry Andric static kmp_user_lock_p __kmp_get_critical_section_ptr(kmp_critical_name *crit,
12860b57cec5SDimitry Andric                                                       ident_t const *loc,
12870b57cec5SDimitry Andric                                                       kmp_int32 gtid) {
12880b57cec5SDimitry Andric   kmp_user_lock_p *lck_pp = (kmp_user_lock_p *)crit;
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric   // Because of the double-check, the following load doesn't need to be volatile
12910b57cec5SDimitry Andric   kmp_user_lock_p lck = (kmp_user_lock_p)TCR_PTR(*lck_pp);
12920b57cec5SDimitry Andric 
12930b57cec5SDimitry Andric   if (lck == NULL) {
12940b57cec5SDimitry Andric     void *idx;
12950b57cec5SDimitry Andric 
12960b57cec5SDimitry Andric     // Allocate & initialize the lock.
12970b57cec5SDimitry Andric     // Remember alloc'ed locks in table in order to free them in __kmp_cleanup()
12980b57cec5SDimitry Andric     lck = __kmp_user_lock_allocate(&idx, gtid, kmp_lf_critical_section);
12990b57cec5SDimitry Andric     __kmp_init_user_lock_with_checks(lck);
13000b57cec5SDimitry Andric     __kmp_set_user_lock_location(lck, loc);
13010b57cec5SDimitry Andric #if USE_ITT_BUILD
13020b57cec5SDimitry Andric     __kmp_itt_critical_creating(lck);
13030b57cec5SDimitry Andric // __kmp_itt_critical_creating() should be called *before* the first usage
13040b57cec5SDimitry Andric // of underlying lock. It is the only place where we can guarantee it. There
13050b57cec5SDimitry Andric // are chances the lock will destroyed with no usage, but it is not a
13060b57cec5SDimitry Andric // problem, because this is not real event seen by user but rather setting
13070b57cec5SDimitry Andric // name for object (lock). See more details in kmp_itt.h.
13080b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
13090b57cec5SDimitry Andric 
13100b57cec5SDimitry Andric     // Use a cmpxchg instruction to slam the start of the critical section with
13110b57cec5SDimitry Andric     // the lock pointer.  If another thread beat us to it, deallocate the lock,
13120b57cec5SDimitry Andric     // and use the lock that the other thread allocated.
13130b57cec5SDimitry Andric     int status = KMP_COMPARE_AND_STORE_PTR(lck_pp, 0, lck);
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric     if (status == 0) {
13160b57cec5SDimitry Andric // Deallocate the lock and reload the value.
13170b57cec5SDimitry Andric #if USE_ITT_BUILD
13180b57cec5SDimitry Andric       __kmp_itt_critical_destroyed(lck);
13190b57cec5SDimitry Andric // Let ITT know the lock is destroyed and the same memory location may be reused
13200b57cec5SDimitry Andric // for another purpose.
13210b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
13220b57cec5SDimitry Andric       __kmp_destroy_user_lock_with_checks(lck);
13230b57cec5SDimitry Andric       __kmp_user_lock_free(&idx, gtid, lck);
13240b57cec5SDimitry Andric       lck = (kmp_user_lock_p)TCR_PTR(*lck_pp);
13250b57cec5SDimitry Andric       KMP_DEBUG_ASSERT(lck != NULL);
13260b57cec5SDimitry Andric     }
13270b57cec5SDimitry Andric   }
13280b57cec5SDimitry Andric   return lck;
13290b57cec5SDimitry Andric }
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
13320b57cec5SDimitry Andric 
13330b57cec5SDimitry Andric /*!
13340b57cec5SDimitry Andric @ingroup WORK_SHARING
13350b57cec5SDimitry Andric @param loc  source location information.
13360b57cec5SDimitry Andric @param global_tid  global thread number.
13370b57cec5SDimitry Andric @param crit identity of the critical section. This could be a pointer to a lock
13380b57cec5SDimitry Andric associated with the critical section, or some other suitably unique value.
13390b57cec5SDimitry Andric 
13400b57cec5SDimitry Andric Enter code protected by a `critical` construct.
13410b57cec5SDimitry Andric This function blocks until the executing thread can enter the critical section.
13420b57cec5SDimitry Andric */
13430b57cec5SDimitry Andric void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
13440b57cec5SDimitry Andric                      kmp_critical_name *crit) {
13450b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
13460b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
13470b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(global_tid);
13480b57cec5SDimitry Andric #endif // OMPT_SUPPORT
13490b57cec5SDimitry Andric   __kmpc_critical_with_hint(loc, global_tid, crit, omp_lock_hint_none);
13500b57cec5SDimitry Andric #else
13510b57cec5SDimitry Andric   KMP_COUNT_BLOCK(OMP_CRITICAL);
13520b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
13530b57cec5SDimitry Andric   ompt_state_t prev_state = ompt_state_undefined;
13540b57cec5SDimitry Andric   ompt_thread_info_t ti;
13550b57cec5SDimitry Andric #endif
13560b57cec5SDimitry Andric   kmp_user_lock_p lck;
13570b57cec5SDimitry Andric 
13580b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_critical: called T#%d\n", global_tid));
1359e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
13600b57cec5SDimitry Andric 
13610b57cec5SDimitry Andric   // TODO: add THR_OVHD_STATE
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric   KMP_PUSH_PARTITIONED_TIMER(OMP_critical_wait);
13640b57cec5SDimitry Andric   KMP_CHECK_USER_LOCK_INIT();
13650b57cec5SDimitry Andric 
13660b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
13670b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_CRITICAL_SIZE)) {
13680b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
13690b57cec5SDimitry Andric   }
13700b57cec5SDimitry Andric #if KMP_USE_FUTEX
13710b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
13720b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_CRITICAL_SIZE)) {
13730b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
13740b57cec5SDimitry Andric   }
13750b57cec5SDimitry Andric #endif
13760b57cec5SDimitry Andric   else { // ticket, queuing or drdpa
13770b57cec5SDimitry Andric     lck = __kmp_get_critical_section_ptr(crit, loc, global_tid);
13780b57cec5SDimitry Andric   }
13790b57cec5SDimitry Andric 
13800b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
13810b57cec5SDimitry Andric     __kmp_push_sync(global_tid, ct_critical, loc, lck);
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric     // since the critical directive binds to all threads, not just the current
13840b57cec5SDimitry Andric     // team we have to check this even if we are in a serialized team.
13850b57cec5SDimitry Andric     // also, even if we are the uber thread, we still have to conduct the lock,
13860b57cec5SDimitry Andric     // as we have to contend with sibling threads.
13870b57cec5SDimitry Andric 
13880b57cec5SDimitry Andric #if USE_ITT_BUILD
13890b57cec5SDimitry Andric   __kmp_itt_critical_acquiring(lck);
13900b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
13910b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
13920b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(gtid);
13930b57cec5SDimitry Andric   void *codeptr_ra = NULL;
13940b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
13950b57cec5SDimitry Andric     ti = __kmp_threads[global_tid]->th.ompt_thread_info;
13960b57cec5SDimitry Andric     /* OMPT state update */
13970b57cec5SDimitry Andric     prev_state = ti.state;
13980b57cec5SDimitry Andric     ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
13990b57cec5SDimitry Andric     ti.state = ompt_state_wait_critical;
14000b57cec5SDimitry Andric 
14010b57cec5SDimitry Andric     /* OMPT event callback */
14020b57cec5SDimitry Andric     codeptr_ra = OMPT_LOAD_RETURN_ADDRESS(gtid);
14030b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquire) {
14040b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
14050b57cec5SDimitry Andric           ompt_mutex_critical, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
14060b57cec5SDimitry Andric           (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
14070b57cec5SDimitry Andric     }
14080b57cec5SDimitry Andric   }
14090b57cec5SDimitry Andric #endif
14100b57cec5SDimitry Andric   // Value of 'crit' should be good for using as a critical_id of the critical
14110b57cec5SDimitry Andric   // section directive.
14120b57cec5SDimitry Andric   __kmp_acquire_user_lock_with_checks(lck, global_tid);
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric #if USE_ITT_BUILD
14150b57cec5SDimitry Andric   __kmp_itt_critical_acquired(lck);
14160b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
14170b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
14180b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
14190b57cec5SDimitry Andric     /* OMPT state update */
14200b57cec5SDimitry Andric     ti.state = prev_state;
14210b57cec5SDimitry Andric     ti.wait_id = 0;
14220b57cec5SDimitry Andric 
14230b57cec5SDimitry Andric     /* OMPT event callback */
14240b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquired) {
14250b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
14260b57cec5SDimitry Andric           ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
14270b57cec5SDimitry Andric     }
14280b57cec5SDimitry Andric   }
14290b57cec5SDimitry Andric #endif
14300b57cec5SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
14310b57cec5SDimitry Andric 
14320b57cec5SDimitry Andric   KMP_PUSH_PARTITIONED_TIMER(OMP_critical);
14330b57cec5SDimitry Andric   KA_TRACE(15, ("__kmpc_critical: done T#%d\n", global_tid));
14340b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
14350b57cec5SDimitry Andric }
14360b57cec5SDimitry Andric 
14370b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric // Converts the given hint to an internal lock implementation
14400b57cec5SDimitry Andric static __forceinline kmp_dyna_lockseq_t __kmp_map_hint_to_lock(uintptr_t hint) {
14410b57cec5SDimitry Andric #if KMP_USE_TSX
14420b57cec5SDimitry Andric #define KMP_TSX_LOCK(seq) lockseq_##seq
14430b57cec5SDimitry Andric #else
14440b57cec5SDimitry Andric #define KMP_TSX_LOCK(seq) __kmp_user_lock_seq
14450b57cec5SDimitry Andric #endif
14460b57cec5SDimitry Andric 
14470b57cec5SDimitry Andric #if KMP_ARCH_X86 || KMP_ARCH_X86_64
1448349cc55cSDimitry Andric #define KMP_CPUINFO_RTM (__kmp_cpuinfo.flags.rtm)
14490b57cec5SDimitry Andric #else
14500b57cec5SDimitry Andric #define KMP_CPUINFO_RTM 0
14510b57cec5SDimitry Andric #endif
14520b57cec5SDimitry Andric 
14530b57cec5SDimitry Andric   // Hints that do not require further logic
14540b57cec5SDimitry Andric   if (hint & kmp_lock_hint_hle)
14550b57cec5SDimitry Andric     return KMP_TSX_LOCK(hle);
14560b57cec5SDimitry Andric   if (hint & kmp_lock_hint_rtm)
1457e8d8bef9SDimitry Andric     return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(rtm_queuing) : __kmp_user_lock_seq;
14580b57cec5SDimitry Andric   if (hint & kmp_lock_hint_adaptive)
14590b57cec5SDimitry Andric     return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(adaptive) : __kmp_user_lock_seq;
14600b57cec5SDimitry Andric 
14610b57cec5SDimitry Andric   // Rule out conflicting hints first by returning the default lock
14620b57cec5SDimitry Andric   if ((hint & omp_lock_hint_contended) && (hint & omp_lock_hint_uncontended))
14630b57cec5SDimitry Andric     return __kmp_user_lock_seq;
14640b57cec5SDimitry Andric   if ((hint & omp_lock_hint_speculative) &&
14650b57cec5SDimitry Andric       (hint & omp_lock_hint_nonspeculative))
14660b57cec5SDimitry Andric     return __kmp_user_lock_seq;
14670b57cec5SDimitry Andric 
14680b57cec5SDimitry Andric   // Do not even consider speculation when it appears to be contended
14690b57cec5SDimitry Andric   if (hint & omp_lock_hint_contended)
14700b57cec5SDimitry Andric     return lockseq_queuing;
14710b57cec5SDimitry Andric 
14720b57cec5SDimitry Andric   // Uncontended lock without speculation
14730b57cec5SDimitry Andric   if ((hint & omp_lock_hint_uncontended) && !(hint & omp_lock_hint_speculative))
14740b57cec5SDimitry Andric     return lockseq_tas;
14750b57cec5SDimitry Andric 
1476e8d8bef9SDimitry Andric   // Use RTM lock for speculation
14770b57cec5SDimitry Andric   if (hint & omp_lock_hint_speculative)
1478e8d8bef9SDimitry Andric     return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(rtm_spin) : __kmp_user_lock_seq;
14790b57cec5SDimitry Andric 
14800b57cec5SDimitry Andric   return __kmp_user_lock_seq;
14810b57cec5SDimitry Andric }
14820b57cec5SDimitry Andric 
14830b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
14840b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
14850b57cec5SDimitry Andric static kmp_mutex_impl_t
14860b57cec5SDimitry Andric __ompt_get_mutex_impl_type(void *user_lock, kmp_indirect_lock_t *ilock = 0) {
14870b57cec5SDimitry Andric   if (user_lock) {
14880b57cec5SDimitry Andric     switch (KMP_EXTRACT_D_TAG(user_lock)) {
14890b57cec5SDimitry Andric     case 0:
14900b57cec5SDimitry Andric       break;
14910b57cec5SDimitry Andric #if KMP_USE_FUTEX
14920b57cec5SDimitry Andric     case locktag_futex:
14930b57cec5SDimitry Andric       return kmp_mutex_impl_queuing;
14940b57cec5SDimitry Andric #endif
14950b57cec5SDimitry Andric     case locktag_tas:
14960b57cec5SDimitry Andric       return kmp_mutex_impl_spin;
14970b57cec5SDimitry Andric #if KMP_USE_TSX
14980b57cec5SDimitry Andric     case locktag_hle:
1499e8d8bef9SDimitry Andric     case locktag_rtm_spin:
15000b57cec5SDimitry Andric       return kmp_mutex_impl_speculative;
15010b57cec5SDimitry Andric #endif
15020b57cec5SDimitry Andric     default:
15030b57cec5SDimitry Andric       return kmp_mutex_impl_none;
15040b57cec5SDimitry Andric     }
15050b57cec5SDimitry Andric     ilock = KMP_LOOKUP_I_LOCK(user_lock);
15060b57cec5SDimitry Andric   }
15070b57cec5SDimitry Andric   KMP_ASSERT(ilock);
15080b57cec5SDimitry Andric   switch (ilock->type) {
15090b57cec5SDimitry Andric #if KMP_USE_TSX
15100b57cec5SDimitry Andric   case locktag_adaptive:
1511e8d8bef9SDimitry Andric   case locktag_rtm_queuing:
15120b57cec5SDimitry Andric     return kmp_mutex_impl_speculative;
15130b57cec5SDimitry Andric #endif
15140b57cec5SDimitry Andric   case locktag_nested_tas:
15150b57cec5SDimitry Andric     return kmp_mutex_impl_spin;
15160b57cec5SDimitry Andric #if KMP_USE_FUTEX
15170b57cec5SDimitry Andric   case locktag_nested_futex:
15180b57cec5SDimitry Andric #endif
15190b57cec5SDimitry Andric   case locktag_ticket:
15200b57cec5SDimitry Andric   case locktag_queuing:
15210b57cec5SDimitry Andric   case locktag_drdpa:
15220b57cec5SDimitry Andric   case locktag_nested_ticket:
15230b57cec5SDimitry Andric   case locktag_nested_queuing:
15240b57cec5SDimitry Andric   case locktag_nested_drdpa:
15250b57cec5SDimitry Andric     return kmp_mutex_impl_queuing;
15260b57cec5SDimitry Andric   default:
15270b57cec5SDimitry Andric     return kmp_mutex_impl_none;
15280b57cec5SDimitry Andric   }
15290b57cec5SDimitry Andric }
15300b57cec5SDimitry Andric #else
15310b57cec5SDimitry Andric // For locks without dynamic binding
15320b57cec5SDimitry Andric static kmp_mutex_impl_t __ompt_get_mutex_impl_type() {
15330b57cec5SDimitry Andric   switch (__kmp_user_lock_kind) {
15340b57cec5SDimitry Andric   case lk_tas:
15350b57cec5SDimitry Andric     return kmp_mutex_impl_spin;
15360b57cec5SDimitry Andric #if KMP_USE_FUTEX
15370b57cec5SDimitry Andric   case lk_futex:
15380b57cec5SDimitry Andric #endif
15390b57cec5SDimitry Andric   case lk_ticket:
15400b57cec5SDimitry Andric   case lk_queuing:
15410b57cec5SDimitry Andric   case lk_drdpa:
15420b57cec5SDimitry Andric     return kmp_mutex_impl_queuing;
15430b57cec5SDimitry Andric #if KMP_USE_TSX
15440b57cec5SDimitry Andric   case lk_hle:
1545e8d8bef9SDimitry Andric   case lk_rtm_queuing:
1546e8d8bef9SDimitry Andric   case lk_rtm_spin:
15470b57cec5SDimitry Andric   case lk_adaptive:
15480b57cec5SDimitry Andric     return kmp_mutex_impl_speculative;
15490b57cec5SDimitry Andric #endif
15500b57cec5SDimitry Andric   default:
15510b57cec5SDimitry Andric     return kmp_mutex_impl_none;
15520b57cec5SDimitry Andric   }
15530b57cec5SDimitry Andric }
15540b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
15550b57cec5SDimitry Andric #endif // OMPT_SUPPORT && OMPT_OPTIONAL
15560b57cec5SDimitry Andric 
15570b57cec5SDimitry Andric /*!
15580b57cec5SDimitry Andric @ingroup WORK_SHARING
15590b57cec5SDimitry Andric @param loc  source location information.
15600b57cec5SDimitry Andric @param global_tid  global thread number.
15610b57cec5SDimitry Andric @param crit identity of the critical section. This could be a pointer to a lock
15620b57cec5SDimitry Andric associated with the critical section, or some other suitably unique value.
15630b57cec5SDimitry Andric @param hint the lock hint.
15640b57cec5SDimitry Andric 
15650b57cec5SDimitry Andric Enter code protected by a `critical` construct with a hint. The hint value is
15660b57cec5SDimitry Andric used to suggest a lock implementation. This function blocks until the executing
15670b57cec5SDimitry Andric thread can enter the critical section unless the hint suggests use of
15680b57cec5SDimitry Andric speculative execution and the hardware supports it.
15690b57cec5SDimitry Andric */
15700b57cec5SDimitry Andric void __kmpc_critical_with_hint(ident_t *loc, kmp_int32 global_tid,
15710b57cec5SDimitry Andric                                kmp_critical_name *crit, uint32_t hint) {
15720b57cec5SDimitry Andric   KMP_COUNT_BLOCK(OMP_CRITICAL);
15730b57cec5SDimitry Andric   kmp_user_lock_p lck;
15740b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
15750b57cec5SDimitry Andric   ompt_state_t prev_state = ompt_state_undefined;
15760b57cec5SDimitry Andric   ompt_thread_info_t ti;
15770b57cec5SDimitry Andric   // This is the case, if called from __kmpc_critical:
15780b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(global_tid);
15790b57cec5SDimitry Andric   if (!codeptr)
15800b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
15810b57cec5SDimitry Andric #endif
15820b57cec5SDimitry Andric 
15830b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_critical: called T#%d\n", global_tid));
1584e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
15850b57cec5SDimitry Andric 
15860b57cec5SDimitry Andric   kmp_dyna_lock_t *lk = (kmp_dyna_lock_t *)crit;
15870b57cec5SDimitry Andric   // Check if it is initialized.
15880b57cec5SDimitry Andric   KMP_PUSH_PARTITIONED_TIMER(OMP_critical_wait);
1589fe6060f1SDimitry Andric   kmp_dyna_lockseq_t lockseq = __kmp_map_hint_to_lock(hint);
15900b57cec5SDimitry Andric   if (*lk == 0) {
1591fe6060f1SDimitry Andric     if (KMP_IS_D_LOCK(lockseq)) {
159274626c16SDimitry Andric       KMP_COMPARE_AND_STORE_ACQ32(
159374626c16SDimitry Andric           (volatile kmp_int32 *)&((kmp_base_tas_lock_t *)crit)->poll, 0,
1594fe6060f1SDimitry Andric           KMP_GET_D_TAG(lockseq));
15950b57cec5SDimitry Andric     } else {
1596fe6060f1SDimitry Andric       __kmp_init_indirect_csptr(crit, loc, global_tid, KMP_GET_I_TAG(lockseq));
15970b57cec5SDimitry Andric     }
15980b57cec5SDimitry Andric   }
15990b57cec5SDimitry Andric   // Branch for accessing the actual lock object and set operation. This
16000b57cec5SDimitry Andric   // branching is inevitable since this lock initialization does not follow the
16010b57cec5SDimitry Andric   // normal dispatch path (lock table is not used).
16020b57cec5SDimitry Andric   if (KMP_EXTRACT_D_TAG(lk) != 0) {
16030b57cec5SDimitry Andric     lck = (kmp_user_lock_p)lk;
16040b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
16050b57cec5SDimitry Andric       __kmp_push_sync(global_tid, ct_critical, loc, lck,
16060b57cec5SDimitry Andric                       __kmp_map_hint_to_lock(hint));
16070b57cec5SDimitry Andric     }
16080b57cec5SDimitry Andric #if USE_ITT_BUILD
16090b57cec5SDimitry Andric     __kmp_itt_critical_acquiring(lck);
16100b57cec5SDimitry Andric #endif
16110b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
16120b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
16130b57cec5SDimitry Andric       ti = __kmp_threads[global_tid]->th.ompt_thread_info;
16140b57cec5SDimitry Andric       /* OMPT state update */
16150b57cec5SDimitry Andric       prev_state = ti.state;
16160b57cec5SDimitry Andric       ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
16170b57cec5SDimitry Andric       ti.state = ompt_state_wait_critical;
16180b57cec5SDimitry Andric 
16190b57cec5SDimitry Andric       /* OMPT event callback */
16200b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_acquire) {
16210b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
16220b57cec5SDimitry Andric             ompt_mutex_critical, (unsigned int)hint,
16230b57cec5SDimitry Andric             __ompt_get_mutex_impl_type(crit), (ompt_wait_id_t)(uintptr_t)lck,
16240b57cec5SDimitry Andric             codeptr);
16250b57cec5SDimitry Andric       }
16260b57cec5SDimitry Andric     }
16270b57cec5SDimitry Andric #endif
16280b57cec5SDimitry Andric #if KMP_USE_INLINED_TAS
1629fe6060f1SDimitry Andric     if (lockseq == lockseq_tas && !__kmp_env_consistency_check) {
16300b57cec5SDimitry Andric       KMP_ACQUIRE_TAS_LOCK(lck, global_tid);
16310b57cec5SDimitry Andric     } else
16320b57cec5SDimitry Andric #elif KMP_USE_INLINED_FUTEX
1633fe6060f1SDimitry Andric     if (lockseq == lockseq_futex && !__kmp_env_consistency_check) {
16340b57cec5SDimitry Andric       KMP_ACQUIRE_FUTEX_LOCK(lck, global_tid);
16350b57cec5SDimitry Andric     } else
16360b57cec5SDimitry Andric #endif
16370b57cec5SDimitry Andric     {
16380b57cec5SDimitry Andric       KMP_D_LOCK_FUNC(lk, set)(lk, global_tid);
16390b57cec5SDimitry Andric     }
16400b57cec5SDimitry Andric   } else {
16410b57cec5SDimitry Andric     kmp_indirect_lock_t *ilk = *((kmp_indirect_lock_t **)lk);
16420b57cec5SDimitry Andric     lck = ilk->lock;
16430b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
16440b57cec5SDimitry Andric       __kmp_push_sync(global_tid, ct_critical, loc, lck,
16450b57cec5SDimitry Andric                       __kmp_map_hint_to_lock(hint));
16460b57cec5SDimitry Andric     }
16470b57cec5SDimitry Andric #if USE_ITT_BUILD
16480b57cec5SDimitry Andric     __kmp_itt_critical_acquiring(lck);
16490b57cec5SDimitry Andric #endif
16500b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
16510b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
16520b57cec5SDimitry Andric       ti = __kmp_threads[global_tid]->th.ompt_thread_info;
16530b57cec5SDimitry Andric       /* OMPT state update */
16540b57cec5SDimitry Andric       prev_state = ti.state;
16550b57cec5SDimitry Andric       ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
16560b57cec5SDimitry Andric       ti.state = ompt_state_wait_critical;
16570b57cec5SDimitry Andric 
16580b57cec5SDimitry Andric       /* OMPT event callback */
16590b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_acquire) {
16600b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
16610b57cec5SDimitry Andric             ompt_mutex_critical, (unsigned int)hint,
16620b57cec5SDimitry Andric             __ompt_get_mutex_impl_type(0, ilk), (ompt_wait_id_t)(uintptr_t)lck,
16630b57cec5SDimitry Andric             codeptr);
16640b57cec5SDimitry Andric       }
16650b57cec5SDimitry Andric     }
16660b57cec5SDimitry Andric #endif
16670b57cec5SDimitry Andric     KMP_I_LOCK_FUNC(ilk, set)(lck, global_tid);
16680b57cec5SDimitry Andric   }
16690b57cec5SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
16700b57cec5SDimitry Andric 
16710b57cec5SDimitry Andric #if USE_ITT_BUILD
16720b57cec5SDimitry Andric   __kmp_itt_critical_acquired(lck);
16730b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
16740b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
16750b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
16760b57cec5SDimitry Andric     /* OMPT state update */
16770b57cec5SDimitry Andric     ti.state = prev_state;
16780b57cec5SDimitry Andric     ti.wait_id = 0;
16790b57cec5SDimitry Andric 
16800b57cec5SDimitry Andric     /* OMPT event callback */
16810b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquired) {
16820b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
16830b57cec5SDimitry Andric           ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
16840b57cec5SDimitry Andric     }
16850b57cec5SDimitry Andric   }
16860b57cec5SDimitry Andric #endif
16870b57cec5SDimitry Andric 
16880b57cec5SDimitry Andric   KMP_PUSH_PARTITIONED_TIMER(OMP_critical);
16890b57cec5SDimitry Andric   KA_TRACE(15, ("__kmpc_critical: done T#%d\n", global_tid));
16900b57cec5SDimitry Andric } // __kmpc_critical_with_hint
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
16930b57cec5SDimitry Andric 
16940b57cec5SDimitry Andric /*!
16950b57cec5SDimitry Andric @ingroup WORK_SHARING
16960b57cec5SDimitry Andric @param loc  source location information.
16970b57cec5SDimitry Andric @param global_tid  global thread number .
16980b57cec5SDimitry Andric @param crit identity of the critical section. This could be a pointer to a lock
16990b57cec5SDimitry Andric associated with the critical section, or some other suitably unique value.
17000b57cec5SDimitry Andric 
17010b57cec5SDimitry Andric Leave a critical section, releasing any lock that was held during its execution.
17020b57cec5SDimitry Andric */
17030b57cec5SDimitry Andric void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
17040b57cec5SDimitry Andric                          kmp_critical_name *crit) {
17050b57cec5SDimitry Andric   kmp_user_lock_p lck;
17060b57cec5SDimitry Andric 
17070b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_end_critical: called T#%d\n", global_tid));
17080b57cec5SDimitry Andric 
17090b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
1710fe6060f1SDimitry Andric   int locktag = KMP_EXTRACT_D_TAG(crit);
1711fe6060f1SDimitry Andric   if (locktag) {
17120b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
17130b57cec5SDimitry Andric     KMP_ASSERT(lck != NULL);
17140b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
17150b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_critical, loc);
17160b57cec5SDimitry Andric     }
17170b57cec5SDimitry Andric #if USE_ITT_BUILD
17180b57cec5SDimitry Andric     __kmp_itt_critical_releasing(lck);
17190b57cec5SDimitry Andric #endif
17200b57cec5SDimitry Andric #if KMP_USE_INLINED_TAS
1721fe6060f1SDimitry Andric     if (locktag == locktag_tas && !__kmp_env_consistency_check) {
17220b57cec5SDimitry Andric       KMP_RELEASE_TAS_LOCK(lck, global_tid);
17230b57cec5SDimitry Andric     } else
17240b57cec5SDimitry Andric #elif KMP_USE_INLINED_FUTEX
1725fe6060f1SDimitry Andric     if (locktag == locktag_futex && !__kmp_env_consistency_check) {
17260b57cec5SDimitry Andric       KMP_RELEASE_FUTEX_LOCK(lck, global_tid);
17270b57cec5SDimitry Andric     } else
17280b57cec5SDimitry Andric #endif
17290b57cec5SDimitry Andric     {
17300b57cec5SDimitry Andric       KMP_D_LOCK_FUNC(lck, unset)((kmp_dyna_lock_t *)lck, global_tid);
17310b57cec5SDimitry Andric     }
17320b57cec5SDimitry Andric   } else {
17330b57cec5SDimitry Andric     kmp_indirect_lock_t *ilk =
17340b57cec5SDimitry Andric         (kmp_indirect_lock_t *)TCR_PTR(*((kmp_indirect_lock_t **)crit));
17350b57cec5SDimitry Andric     KMP_ASSERT(ilk != NULL);
17360b57cec5SDimitry Andric     lck = ilk->lock;
17370b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
17380b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_critical, loc);
17390b57cec5SDimitry Andric     }
17400b57cec5SDimitry Andric #if USE_ITT_BUILD
17410b57cec5SDimitry Andric     __kmp_itt_critical_releasing(lck);
17420b57cec5SDimitry Andric #endif
17430b57cec5SDimitry Andric     KMP_I_LOCK_FUNC(ilk, unset)(lck, global_tid);
17440b57cec5SDimitry Andric   }
17450b57cec5SDimitry Andric 
17460b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
17470b57cec5SDimitry Andric 
17480b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
17490b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_CRITICAL_SIZE)) {
17500b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
17510b57cec5SDimitry Andric   }
17520b57cec5SDimitry Andric #if KMP_USE_FUTEX
17530b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
17540b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_CRITICAL_SIZE)) {
17550b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
17560b57cec5SDimitry Andric   }
17570b57cec5SDimitry Andric #endif
17580b57cec5SDimitry Andric   else { // ticket, queuing or drdpa
17590b57cec5SDimitry Andric     lck = (kmp_user_lock_p)TCR_PTR(*((kmp_user_lock_p *)crit));
17600b57cec5SDimitry Andric   }
17610b57cec5SDimitry Andric 
17620b57cec5SDimitry Andric   KMP_ASSERT(lck != NULL);
17630b57cec5SDimitry Andric 
17640b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
17650b57cec5SDimitry Andric     __kmp_pop_sync(global_tid, ct_critical, loc);
17660b57cec5SDimitry Andric 
17670b57cec5SDimitry Andric #if USE_ITT_BUILD
17680b57cec5SDimitry Andric   __kmp_itt_critical_releasing(lck);
17690b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
17700b57cec5SDimitry Andric   // Value of 'crit' should be good for using as a critical_id of the critical
17710b57cec5SDimitry Andric   // section directive.
17720b57cec5SDimitry Andric   __kmp_release_user_lock_with_checks(lck, global_tid);
17730b57cec5SDimitry Andric 
17740b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
17750b57cec5SDimitry Andric 
17760b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
17770b57cec5SDimitry Andric   /* OMPT release event triggers after lock is released; place here to trigger
17780b57cec5SDimitry Andric    * for all #if branches */
17790b57cec5SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(global_tid);
17800b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_released) {
17810b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
17820b57cec5SDimitry Andric         ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck,
17830b57cec5SDimitry Andric         OMPT_LOAD_RETURN_ADDRESS(0));
17840b57cec5SDimitry Andric   }
17850b57cec5SDimitry Andric #endif
17860b57cec5SDimitry Andric 
17870b57cec5SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
17880b57cec5SDimitry Andric   KA_TRACE(15, ("__kmpc_end_critical: done T#%d\n", global_tid));
17890b57cec5SDimitry Andric }
17900b57cec5SDimitry Andric 
17910b57cec5SDimitry Andric /*!
17920b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
17930b57cec5SDimitry Andric @param loc source location information
17940b57cec5SDimitry Andric @param global_tid thread id.
17950b57cec5SDimitry Andric @return one if the thread should execute the master block, zero otherwise
17960b57cec5SDimitry Andric 
17970b57cec5SDimitry Andric Start execution of a combined barrier and master. The barrier is executed inside
17980b57cec5SDimitry Andric this function.
17990b57cec5SDimitry Andric */
18000b57cec5SDimitry Andric kmp_int32 __kmpc_barrier_master(ident_t *loc, kmp_int32 global_tid) {
18010b57cec5SDimitry Andric   int status;
18020b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_barrier_master: called T#%d\n", global_tid));
1803e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
18040b57cec5SDimitry Andric 
18050b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
18060b57cec5SDimitry Andric     __kmp_parallel_initialize();
18070b57cec5SDimitry Andric 
18080b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
18090b57cec5SDimitry Andric 
18100b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
18110b57cec5SDimitry Andric     __kmp_check_barrier(global_tid, ct_barrier, loc);
18120b57cec5SDimitry Andric 
18130b57cec5SDimitry Andric #if OMPT_SUPPORT
18140b57cec5SDimitry Andric   ompt_frame_t *ompt_frame;
18150b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
18160b57cec5SDimitry Andric     __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
18170b57cec5SDimitry Andric     if (ompt_frame->enter_frame.ptr == NULL)
18180b57cec5SDimitry Andric       ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
18190b57cec5SDimitry Andric   }
1820e8d8bef9SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(global_tid);
18210b57cec5SDimitry Andric #endif
18220b57cec5SDimitry Andric #if USE_ITT_NOTIFY
18230b57cec5SDimitry Andric   __kmp_threads[global_tid]->th.th_ident = loc;
18240b57cec5SDimitry Andric #endif
18250b57cec5SDimitry Andric   status = __kmp_barrier(bs_plain_barrier, global_tid, TRUE, 0, NULL, NULL);
18260b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
18270b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
18280b57cec5SDimitry Andric     ompt_frame->enter_frame = ompt_data_none;
18290b57cec5SDimitry Andric   }
18300b57cec5SDimitry Andric #endif
18310b57cec5SDimitry Andric 
18320b57cec5SDimitry Andric   return (status != 0) ? 0 : 1;
18330b57cec5SDimitry Andric }
18340b57cec5SDimitry Andric 
18350b57cec5SDimitry Andric /*!
18360b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
18370b57cec5SDimitry Andric @param loc source location information
18380b57cec5SDimitry Andric @param global_tid thread id.
18390b57cec5SDimitry Andric 
18400b57cec5SDimitry Andric Complete the execution of a combined barrier and master. This function should
18410b57cec5SDimitry Andric only be called at the completion of the <tt>master</tt> code. Other threads will
18420b57cec5SDimitry Andric still be waiting at the barrier and this call releases them.
18430b57cec5SDimitry Andric */
18440b57cec5SDimitry Andric void __kmpc_end_barrier_master(ident_t *loc, kmp_int32 global_tid) {
18450b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_end_barrier_master: called T#%d\n", global_tid));
1846e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
18470b57cec5SDimitry Andric   __kmp_end_split_barrier(bs_plain_barrier, global_tid);
18480b57cec5SDimitry Andric }
18490b57cec5SDimitry Andric 
18500b57cec5SDimitry Andric /*!
18510b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
18520b57cec5SDimitry Andric @param loc source location information
18530b57cec5SDimitry Andric @param global_tid thread id.
18540b57cec5SDimitry Andric @return one if the thread should execute the master block, zero otherwise
18550b57cec5SDimitry Andric 
18560b57cec5SDimitry Andric Start execution of a combined barrier and master(nowait) construct.
18570b57cec5SDimitry Andric The barrier is executed inside this function.
18580b57cec5SDimitry Andric There is no equivalent "end" function, since the
18590b57cec5SDimitry Andric */
18600b57cec5SDimitry Andric kmp_int32 __kmpc_barrier_master_nowait(ident_t *loc, kmp_int32 global_tid) {
18610b57cec5SDimitry Andric   kmp_int32 ret;
18620b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_barrier_master_nowait: called T#%d\n", global_tid));
1863e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
18640b57cec5SDimitry Andric 
18650b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
18660b57cec5SDimitry Andric     __kmp_parallel_initialize();
18670b57cec5SDimitry Andric 
18680b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
18690b57cec5SDimitry Andric 
18700b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
18710b57cec5SDimitry Andric     if (loc == 0) {
18720b57cec5SDimitry Andric       KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
18730b57cec5SDimitry Andric     }
18740b57cec5SDimitry Andric     __kmp_check_barrier(global_tid, ct_barrier, loc);
18750b57cec5SDimitry Andric   }
18760b57cec5SDimitry Andric 
18770b57cec5SDimitry Andric #if OMPT_SUPPORT
18780b57cec5SDimitry Andric   ompt_frame_t *ompt_frame;
18790b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
18800b57cec5SDimitry Andric     __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
18810b57cec5SDimitry Andric     if (ompt_frame->enter_frame.ptr == NULL)
18820b57cec5SDimitry Andric       ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
18830b57cec5SDimitry Andric   }
1884e8d8bef9SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(global_tid);
18850b57cec5SDimitry Andric #endif
18860b57cec5SDimitry Andric #if USE_ITT_NOTIFY
18870b57cec5SDimitry Andric   __kmp_threads[global_tid]->th.th_ident = loc;
18880b57cec5SDimitry Andric #endif
18890b57cec5SDimitry Andric   __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
18900b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
18910b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
18920b57cec5SDimitry Andric     ompt_frame->enter_frame = ompt_data_none;
18930b57cec5SDimitry Andric   }
18940b57cec5SDimitry Andric #endif
18950b57cec5SDimitry Andric 
18960b57cec5SDimitry Andric   ret = __kmpc_master(loc, global_tid);
18970b57cec5SDimitry Andric 
18980b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
18990b57cec5SDimitry Andric     /*  there's no __kmpc_end_master called; so the (stats) */
19000b57cec5SDimitry Andric     /*  actions of __kmpc_end_master are done here          */
19010b57cec5SDimitry Andric     if (ret) {
19020b57cec5SDimitry Andric       /* only one thread should do the pop since only */
19030b57cec5SDimitry Andric       /* one did the push (see __kmpc_master())       */
19040b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_master, loc);
19050b57cec5SDimitry Andric     }
19060b57cec5SDimitry Andric   }
19070b57cec5SDimitry Andric 
19080b57cec5SDimitry Andric   return (ret);
19090b57cec5SDimitry Andric }
19100b57cec5SDimitry Andric 
19110b57cec5SDimitry Andric /* The BARRIER for a SINGLE process section is always explicit   */
19120b57cec5SDimitry Andric /*!
19130b57cec5SDimitry Andric @ingroup WORK_SHARING
19140b57cec5SDimitry Andric @param loc  source location information
19150b57cec5SDimitry Andric @param global_tid  global thread number
19160b57cec5SDimitry Andric @return One if this thread should execute the single construct, zero otherwise.
19170b57cec5SDimitry Andric 
19180b57cec5SDimitry Andric Test whether to execute a <tt>single</tt> construct.
19190b57cec5SDimitry Andric There are no implicit barriers in the two "single" calls, rather the compiler
19200b57cec5SDimitry Andric should introduce an explicit barrier if it is required.
19210b57cec5SDimitry Andric */
19220b57cec5SDimitry Andric 
19230b57cec5SDimitry Andric kmp_int32 __kmpc_single(ident_t *loc, kmp_int32 global_tid) {
1924e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
19250b57cec5SDimitry Andric   kmp_int32 rc = __kmp_enter_single(global_tid, loc, TRUE);
19260b57cec5SDimitry Andric 
19270b57cec5SDimitry Andric   if (rc) {
19280b57cec5SDimitry Andric     // We are going to execute the single statement, so we should count it.
19290b57cec5SDimitry Andric     KMP_COUNT_BLOCK(OMP_SINGLE);
19300b57cec5SDimitry Andric     KMP_PUSH_PARTITIONED_TIMER(OMP_single);
19310b57cec5SDimitry Andric   }
19320b57cec5SDimitry Andric 
19330b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
19340b57cec5SDimitry Andric   kmp_info_t *this_thr = __kmp_threads[global_tid];
19350b57cec5SDimitry Andric   kmp_team_t *team = this_thr->th.th_team;
19360b57cec5SDimitry Andric   int tid = __kmp_tid_from_gtid(global_tid);
19370b57cec5SDimitry Andric 
19380b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
19390b57cec5SDimitry Andric     if (rc) {
19400b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_work) {
19410b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_work)(
19420b57cec5SDimitry Andric             ompt_work_single_executor, ompt_scope_begin,
19430b57cec5SDimitry Andric             &(team->t.ompt_team_info.parallel_data),
19440b57cec5SDimitry Andric             &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
19450b57cec5SDimitry Andric             1, OMPT_GET_RETURN_ADDRESS(0));
19460b57cec5SDimitry Andric       }
19470b57cec5SDimitry Andric     } else {
19480b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_work) {
19490b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_work)(
19500b57cec5SDimitry Andric             ompt_work_single_other, ompt_scope_begin,
19510b57cec5SDimitry Andric             &(team->t.ompt_team_info.parallel_data),
19520b57cec5SDimitry Andric             &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
19530b57cec5SDimitry Andric             1, OMPT_GET_RETURN_ADDRESS(0));
19540b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_work)(
19550b57cec5SDimitry Andric             ompt_work_single_other, ompt_scope_end,
19560b57cec5SDimitry Andric             &(team->t.ompt_team_info.parallel_data),
19570b57cec5SDimitry Andric             &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
19580b57cec5SDimitry Andric             1, OMPT_GET_RETURN_ADDRESS(0));
19590b57cec5SDimitry Andric       }
19600b57cec5SDimitry Andric     }
19610b57cec5SDimitry Andric   }
19620b57cec5SDimitry Andric #endif
19630b57cec5SDimitry Andric 
19640b57cec5SDimitry Andric   return rc;
19650b57cec5SDimitry Andric }
19660b57cec5SDimitry Andric 
19670b57cec5SDimitry Andric /*!
19680b57cec5SDimitry Andric @ingroup WORK_SHARING
19690b57cec5SDimitry Andric @param loc  source location information
19700b57cec5SDimitry Andric @param global_tid  global thread number
19710b57cec5SDimitry Andric 
19720b57cec5SDimitry Andric Mark the end of a <tt>single</tt> construct.  This function should
19730b57cec5SDimitry Andric only be called by the thread that executed the block of code protected
19740b57cec5SDimitry Andric by the `single` construct.
19750b57cec5SDimitry Andric */
19760b57cec5SDimitry Andric void __kmpc_end_single(ident_t *loc, kmp_int32 global_tid) {
1977e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
19780b57cec5SDimitry Andric   __kmp_exit_single(global_tid);
19790b57cec5SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
19800b57cec5SDimitry Andric 
19810b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
19820b57cec5SDimitry Andric   kmp_info_t *this_thr = __kmp_threads[global_tid];
19830b57cec5SDimitry Andric   kmp_team_t *team = this_thr->th.th_team;
19840b57cec5SDimitry Andric   int tid = __kmp_tid_from_gtid(global_tid);
19850b57cec5SDimitry Andric 
19860b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_work) {
19870b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_work)(
19880b57cec5SDimitry Andric         ompt_work_single_executor, ompt_scope_end,
19890b57cec5SDimitry Andric         &(team->t.ompt_team_info.parallel_data),
19900b57cec5SDimitry Andric         &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
19910b57cec5SDimitry Andric         OMPT_GET_RETURN_ADDRESS(0));
19920b57cec5SDimitry Andric   }
19930b57cec5SDimitry Andric #endif
19940b57cec5SDimitry Andric }
19950b57cec5SDimitry Andric 
19960b57cec5SDimitry Andric /*!
19970b57cec5SDimitry Andric @ingroup WORK_SHARING
19980b57cec5SDimitry Andric @param loc Source location
19990b57cec5SDimitry Andric @param global_tid Global thread id
20000b57cec5SDimitry Andric 
20010b57cec5SDimitry Andric Mark the end of a statically scheduled loop.
20020b57cec5SDimitry Andric */
20030b57cec5SDimitry Andric void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid) {
20040b57cec5SDimitry Andric   KMP_POP_PARTITIONED_TIMER();
20050b57cec5SDimitry Andric   KE_TRACE(10, ("__kmpc_for_static_fini called T#%d\n", global_tid));
20060b57cec5SDimitry Andric 
20070b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
20080b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_work) {
2009*0fca6ea1SDimitry Andric     ompt_work_t ompt_work_type = ompt_work_loop_static;
20100b57cec5SDimitry Andric     ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
20110b57cec5SDimitry Andric     ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
20120b57cec5SDimitry Andric     // Determine workshare type
20130b57cec5SDimitry Andric     if (loc != NULL) {
20140b57cec5SDimitry Andric       if ((loc->flags & KMP_IDENT_WORK_LOOP) != 0) {
2015*0fca6ea1SDimitry Andric         ompt_work_type = ompt_work_loop_static;
20160b57cec5SDimitry Andric       } else if ((loc->flags & KMP_IDENT_WORK_SECTIONS) != 0) {
20170b57cec5SDimitry Andric         ompt_work_type = ompt_work_sections;
20180b57cec5SDimitry Andric       } else if ((loc->flags & KMP_IDENT_WORK_DISTRIBUTE) != 0) {
20190b57cec5SDimitry Andric         ompt_work_type = ompt_work_distribute;
20200b57cec5SDimitry Andric       } else {
20210b57cec5SDimitry Andric         // use default set above.
20220b57cec5SDimitry Andric         // a warning about this case is provided in __kmpc_for_static_init
20230b57cec5SDimitry Andric       }
20240b57cec5SDimitry Andric       KMP_DEBUG_ASSERT(ompt_work_type);
20250b57cec5SDimitry Andric     }
20260b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_work)(
20270b57cec5SDimitry Andric         ompt_work_type, ompt_scope_end, &(team_info->parallel_data),
20280b57cec5SDimitry Andric         &(task_info->task_data), 0, OMPT_GET_RETURN_ADDRESS(0));
20290b57cec5SDimitry Andric   }
20300b57cec5SDimitry Andric #endif
20310b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
20320b57cec5SDimitry Andric     __kmp_pop_workshare(global_tid, ct_pdo, loc);
20330b57cec5SDimitry Andric }
20340b57cec5SDimitry Andric 
20350b57cec5SDimitry Andric // User routines which take C-style arguments (call by value)
20360b57cec5SDimitry Andric // different from the Fortran equivalent routines
20370b57cec5SDimitry Andric 
20380b57cec5SDimitry Andric void ompc_set_num_threads(int arg) {
20390b57cec5SDimitry Andric   // !!!!! TODO: check the per-task binding
20400b57cec5SDimitry Andric   __kmp_set_num_threads(arg, __kmp_entry_gtid());
20410b57cec5SDimitry Andric }
20420b57cec5SDimitry Andric 
20430b57cec5SDimitry Andric void ompc_set_dynamic(int flag) {
20440b57cec5SDimitry Andric   kmp_info_t *thread;
20450b57cec5SDimitry Andric 
20460b57cec5SDimitry Andric   /* For the thread-private implementation of the internal controls */
20470b57cec5SDimitry Andric   thread = __kmp_entry_thread();
20480b57cec5SDimitry Andric 
20490b57cec5SDimitry Andric   __kmp_save_internal_controls(thread);
20500b57cec5SDimitry Andric 
2051e8d8bef9SDimitry Andric   set__dynamic(thread, flag ? true : false);
20520b57cec5SDimitry Andric }
20530b57cec5SDimitry Andric 
20540b57cec5SDimitry Andric void ompc_set_nested(int flag) {
20550b57cec5SDimitry Andric   kmp_info_t *thread;
20560b57cec5SDimitry Andric 
20570b57cec5SDimitry Andric   /* For the thread-private internal controls implementation */
20580b57cec5SDimitry Andric   thread = __kmp_entry_thread();
20590b57cec5SDimitry Andric 
20600b57cec5SDimitry Andric   __kmp_save_internal_controls(thread);
20610b57cec5SDimitry Andric 
20620b57cec5SDimitry Andric   set__max_active_levels(thread, flag ? __kmp_dflt_max_active_levels : 1);
20630b57cec5SDimitry Andric }
20640b57cec5SDimitry Andric 
20650b57cec5SDimitry Andric void ompc_set_max_active_levels(int max_active_levels) {
20660b57cec5SDimitry Andric   /* TO DO */
20670b57cec5SDimitry Andric   /* we want per-task implementation of this internal control */
20680b57cec5SDimitry Andric 
20690b57cec5SDimitry Andric   /* For the per-thread internal controls implementation */
20700b57cec5SDimitry Andric   __kmp_set_max_active_levels(__kmp_entry_gtid(), max_active_levels);
20710b57cec5SDimitry Andric }
20720b57cec5SDimitry Andric 
20730b57cec5SDimitry Andric void ompc_set_schedule(omp_sched_t kind, int modifier) {
20740b57cec5SDimitry Andric   // !!!!! TODO: check the per-task binding
20750b57cec5SDimitry Andric   __kmp_set_schedule(__kmp_entry_gtid(), (kmp_sched_t)kind, modifier);
20760b57cec5SDimitry Andric }
20770b57cec5SDimitry Andric 
20780b57cec5SDimitry Andric int ompc_get_ancestor_thread_num(int level) {
20790b57cec5SDimitry Andric   return __kmp_get_ancestor_thread_num(__kmp_entry_gtid(), level);
20800b57cec5SDimitry Andric }
20810b57cec5SDimitry Andric 
20820b57cec5SDimitry Andric int ompc_get_team_size(int level) {
20830b57cec5SDimitry Andric   return __kmp_get_team_size(__kmp_entry_gtid(), level);
20840b57cec5SDimitry Andric }
20850b57cec5SDimitry Andric 
20860b57cec5SDimitry Andric /* OpenMP 5.0 Affinity Format API */
2087fe6060f1SDimitry Andric void KMP_EXPAND_NAME(ompc_set_affinity_format)(char const *format) {
20880b57cec5SDimitry Andric   if (!__kmp_init_serial) {
20890b57cec5SDimitry Andric     __kmp_serial_initialize();
20900b57cec5SDimitry Andric   }
20910b57cec5SDimitry Andric   __kmp_strncpy_truncate(__kmp_affinity_format, KMP_AFFINITY_FORMAT_SIZE,
20920b57cec5SDimitry Andric                          format, KMP_STRLEN(format) + 1);
20930b57cec5SDimitry Andric }
20940b57cec5SDimitry Andric 
2095fe6060f1SDimitry Andric size_t KMP_EXPAND_NAME(ompc_get_affinity_format)(char *buffer, size_t size) {
20960b57cec5SDimitry Andric   size_t format_size;
20970b57cec5SDimitry Andric   if (!__kmp_init_serial) {
20980b57cec5SDimitry Andric     __kmp_serial_initialize();
20990b57cec5SDimitry Andric   }
21000b57cec5SDimitry Andric   format_size = KMP_STRLEN(__kmp_affinity_format);
21010b57cec5SDimitry Andric   if (buffer && size) {
21020b57cec5SDimitry Andric     __kmp_strncpy_truncate(buffer, size, __kmp_affinity_format,
21030b57cec5SDimitry Andric                            format_size + 1);
21040b57cec5SDimitry Andric   }
21050b57cec5SDimitry Andric   return format_size;
21060b57cec5SDimitry Andric }
21070b57cec5SDimitry Andric 
2108fe6060f1SDimitry Andric void KMP_EXPAND_NAME(ompc_display_affinity)(char const *format) {
21090b57cec5SDimitry Andric   int gtid;
21100b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_middle)) {
21110b57cec5SDimitry Andric     __kmp_middle_initialize();
21120b57cec5SDimitry Andric   }
2113fe6060f1SDimitry Andric   __kmp_assign_root_init_mask();
21140b57cec5SDimitry Andric   gtid = __kmp_get_gtid();
2115fcaf7f86SDimitry Andric #if KMP_AFFINITY_SUPPORTED
2116bdd1243dSDimitry Andric   if (__kmp_threads[gtid]->th.th_team->t.t_level == 0 &&
2117bdd1243dSDimitry Andric       __kmp_affinity.flags.reset) {
2118fcaf7f86SDimitry Andric     __kmp_reset_root_init_mask(gtid);
2119fcaf7f86SDimitry Andric   }
2120fcaf7f86SDimitry Andric #endif
21210b57cec5SDimitry Andric   __kmp_aux_display_affinity(gtid, format);
21220b57cec5SDimitry Andric }
21230b57cec5SDimitry Andric 
2124fe6060f1SDimitry Andric size_t KMP_EXPAND_NAME(ompc_capture_affinity)(char *buffer, size_t buf_size,
21250b57cec5SDimitry Andric                                               char const *format) {
21260b57cec5SDimitry Andric   int gtid;
21270b57cec5SDimitry Andric   size_t num_required;
21280b57cec5SDimitry Andric   kmp_str_buf_t capture_buf;
21290b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_middle)) {
21300b57cec5SDimitry Andric     __kmp_middle_initialize();
21310b57cec5SDimitry Andric   }
2132fe6060f1SDimitry Andric   __kmp_assign_root_init_mask();
21330b57cec5SDimitry Andric   gtid = __kmp_get_gtid();
2134fcaf7f86SDimitry Andric #if KMP_AFFINITY_SUPPORTED
2135bdd1243dSDimitry Andric   if (__kmp_threads[gtid]->th.th_team->t.t_level == 0 &&
2136bdd1243dSDimitry Andric       __kmp_affinity.flags.reset) {
2137fcaf7f86SDimitry Andric     __kmp_reset_root_init_mask(gtid);
2138fcaf7f86SDimitry Andric   }
2139fcaf7f86SDimitry Andric #endif
21400b57cec5SDimitry Andric   __kmp_str_buf_init(&capture_buf);
21410b57cec5SDimitry Andric   num_required = __kmp_aux_capture_affinity(gtid, format, &capture_buf);
21420b57cec5SDimitry Andric   if (buffer && buf_size) {
21430b57cec5SDimitry Andric     __kmp_strncpy_truncate(buffer, buf_size, capture_buf.str,
21440b57cec5SDimitry Andric                            capture_buf.used + 1);
21450b57cec5SDimitry Andric   }
21460b57cec5SDimitry Andric   __kmp_str_buf_free(&capture_buf);
21470b57cec5SDimitry Andric   return num_required;
21480b57cec5SDimitry Andric }
21490b57cec5SDimitry Andric 
21500b57cec5SDimitry Andric void kmpc_set_stacksize(int arg) {
21510b57cec5SDimitry Andric   // __kmp_aux_set_stacksize initializes the library if needed
21520b57cec5SDimitry Andric   __kmp_aux_set_stacksize(arg);
21530b57cec5SDimitry Andric }
21540b57cec5SDimitry Andric 
21550b57cec5SDimitry Andric void kmpc_set_stacksize_s(size_t arg) {
21560b57cec5SDimitry Andric   // __kmp_aux_set_stacksize initializes the library if needed
21570b57cec5SDimitry Andric   __kmp_aux_set_stacksize(arg);
21580b57cec5SDimitry Andric }
21590b57cec5SDimitry Andric 
21600b57cec5SDimitry Andric void kmpc_set_blocktime(int arg) {
21615f757f3fSDimitry Andric   int gtid, tid, bt = arg;
21620b57cec5SDimitry Andric   kmp_info_t *thread;
21630b57cec5SDimitry Andric 
21640b57cec5SDimitry Andric   gtid = __kmp_entry_gtid();
21650b57cec5SDimitry Andric   tid = __kmp_tid_from_gtid(gtid);
21660b57cec5SDimitry Andric   thread = __kmp_thread_from_gtid(gtid);
21670b57cec5SDimitry Andric 
21685f757f3fSDimitry Andric   __kmp_aux_convert_blocktime(&bt);
21695f757f3fSDimitry Andric   __kmp_aux_set_blocktime(bt, thread, tid);
21700b57cec5SDimitry Andric }
21710b57cec5SDimitry Andric 
21720b57cec5SDimitry Andric void kmpc_set_library(int arg) {
21730b57cec5SDimitry Andric   // __kmp_user_set_library initializes the library if needed
21740b57cec5SDimitry Andric   __kmp_user_set_library((enum library_type)arg);
21750b57cec5SDimitry Andric }
21760b57cec5SDimitry Andric 
21770b57cec5SDimitry Andric void kmpc_set_defaults(char const *str) {
21780b57cec5SDimitry Andric   // __kmp_aux_set_defaults initializes the library if needed
21790b57cec5SDimitry Andric   __kmp_aux_set_defaults(str, KMP_STRLEN(str));
21800b57cec5SDimitry Andric }
21810b57cec5SDimitry Andric 
21820b57cec5SDimitry Andric void kmpc_set_disp_num_buffers(int arg) {
21830b57cec5SDimitry Andric   // ignore after initialization because some teams have already
21840b57cec5SDimitry Andric   // allocated dispatch buffers
2185fe6060f1SDimitry Andric   if (__kmp_init_serial == FALSE && arg >= KMP_MIN_DISP_NUM_BUFF &&
2186fe6060f1SDimitry Andric       arg <= KMP_MAX_DISP_NUM_BUFF) {
21870b57cec5SDimitry Andric     __kmp_dispatch_num_buffers = arg;
21880b57cec5SDimitry Andric   }
2189fe6060f1SDimitry Andric }
21900b57cec5SDimitry Andric 
21910b57cec5SDimitry Andric int kmpc_set_affinity_mask_proc(int proc, void **mask) {
21920b57cec5SDimitry Andric #if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
21930b57cec5SDimitry Andric   return -1;
21940b57cec5SDimitry Andric #else
21950b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_middle)) {
21960b57cec5SDimitry Andric     __kmp_middle_initialize();
21970b57cec5SDimitry Andric   }
2198fe6060f1SDimitry Andric   __kmp_assign_root_init_mask();
21990b57cec5SDimitry Andric   return __kmp_aux_set_affinity_mask_proc(proc, mask);
22000b57cec5SDimitry Andric #endif
22010b57cec5SDimitry Andric }
22020b57cec5SDimitry Andric 
22030b57cec5SDimitry Andric int kmpc_unset_affinity_mask_proc(int proc, void **mask) {
22040b57cec5SDimitry Andric #if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
22050b57cec5SDimitry Andric   return -1;
22060b57cec5SDimitry Andric #else
22070b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_middle)) {
22080b57cec5SDimitry Andric     __kmp_middle_initialize();
22090b57cec5SDimitry Andric   }
2210fe6060f1SDimitry Andric   __kmp_assign_root_init_mask();
22110b57cec5SDimitry Andric   return __kmp_aux_unset_affinity_mask_proc(proc, mask);
22120b57cec5SDimitry Andric #endif
22130b57cec5SDimitry Andric }
22140b57cec5SDimitry Andric 
22150b57cec5SDimitry Andric int kmpc_get_affinity_mask_proc(int proc, void **mask) {
22160b57cec5SDimitry Andric #if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
22170b57cec5SDimitry Andric   return -1;
22180b57cec5SDimitry Andric #else
22190b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_middle)) {
22200b57cec5SDimitry Andric     __kmp_middle_initialize();
22210b57cec5SDimitry Andric   }
2222fe6060f1SDimitry Andric   __kmp_assign_root_init_mask();
22230b57cec5SDimitry Andric   return __kmp_aux_get_affinity_mask_proc(proc, mask);
22240b57cec5SDimitry Andric #endif
22250b57cec5SDimitry Andric }
22260b57cec5SDimitry Andric 
22270b57cec5SDimitry Andric /* -------------------------------------------------------------------------- */
22280b57cec5SDimitry Andric /*!
22290b57cec5SDimitry Andric @ingroup THREADPRIVATE
22300b57cec5SDimitry Andric @param loc       source location information
22310b57cec5SDimitry Andric @param gtid      global thread number
22320b57cec5SDimitry Andric @param cpy_size  size of the cpy_data buffer
22330b57cec5SDimitry Andric @param cpy_data  pointer to data to be copied
22340b57cec5SDimitry Andric @param cpy_func  helper function to call for copying data
22350b57cec5SDimitry Andric @param didit     flag variable: 1=single thread; 0=not single thread
22360b57cec5SDimitry Andric 
22370b57cec5SDimitry Andric __kmpc_copyprivate implements the interface for the private data broadcast
22380b57cec5SDimitry Andric needed for the copyprivate clause associated with a single region in an
22390b57cec5SDimitry Andric OpenMP<sup>*</sup> program (both C and Fortran).
22400b57cec5SDimitry Andric All threads participating in the parallel region call this routine.
22410b57cec5SDimitry Andric One of the threads (called the single thread) should have the <tt>didit</tt>
22420b57cec5SDimitry Andric variable set to 1 and all other threads should have that variable set to 0.
22430b57cec5SDimitry Andric All threads pass a pointer to a data buffer (cpy_data) that they have built.
22440b57cec5SDimitry Andric 
22450b57cec5SDimitry Andric The OpenMP specification forbids the use of nowait on the single region when a
22460b57cec5SDimitry Andric copyprivate clause is present. However, @ref __kmpc_copyprivate implements a
22470b57cec5SDimitry Andric barrier internally to avoid race conditions, so the code generation for the
22480b57cec5SDimitry Andric single region should avoid generating a barrier after the call to @ref
22490b57cec5SDimitry Andric __kmpc_copyprivate.
22500b57cec5SDimitry Andric 
22510b57cec5SDimitry Andric The <tt>gtid</tt> parameter is the global thread id for the current thread.
22520b57cec5SDimitry Andric The <tt>loc</tt> parameter is a pointer to source location information.
22530b57cec5SDimitry Andric 
22540b57cec5SDimitry Andric Internal implementation: The single thread will first copy its descriptor
22550b57cec5SDimitry Andric address (cpy_data) to a team-private location, then the other threads will each
22560b57cec5SDimitry Andric call the function pointed to by the parameter cpy_func, which carries out the
22570b57cec5SDimitry Andric copy by copying the data using the cpy_data buffer.
22580b57cec5SDimitry Andric 
22590b57cec5SDimitry Andric The cpy_func routine used for the copy and the contents of the data area defined
22600b57cec5SDimitry Andric by cpy_data and cpy_size may be built in any fashion that will allow the copy
22610b57cec5SDimitry Andric to be done. For instance, the cpy_data buffer can hold the actual data to be
22620b57cec5SDimitry Andric copied or it may hold a list of pointers to the data. The cpy_func routine must
22630b57cec5SDimitry Andric interpret the cpy_data buffer appropriately.
22640b57cec5SDimitry Andric 
22650b57cec5SDimitry Andric The interface to cpy_func is as follows:
22660b57cec5SDimitry Andric @code
22670b57cec5SDimitry Andric void cpy_func( void *destination, void *source )
22680b57cec5SDimitry Andric @endcode
22690b57cec5SDimitry Andric where void *destination is the cpy_data pointer for the thread being copied to
22700b57cec5SDimitry Andric and void *source is the cpy_data pointer for the thread being copied from.
22710b57cec5SDimitry Andric */
22720b57cec5SDimitry Andric void __kmpc_copyprivate(ident_t *loc, kmp_int32 gtid, size_t cpy_size,
22730b57cec5SDimitry Andric                         void *cpy_data, void (*cpy_func)(void *, void *),
22740b57cec5SDimitry Andric                         kmp_int32 didit) {
22750b57cec5SDimitry Andric   void **data_ptr;
22760b57cec5SDimitry Andric   KC_TRACE(10, ("__kmpc_copyprivate: called T#%d\n", gtid));
2277e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
22780b57cec5SDimitry Andric 
22790b57cec5SDimitry Andric   KMP_MB();
22800b57cec5SDimitry Andric 
22810b57cec5SDimitry Andric   data_ptr = &__kmp_team_from_gtid(gtid)->t.t_copypriv_data;
22820b57cec5SDimitry Andric 
22830b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
22840b57cec5SDimitry Andric     if (loc == 0) {
22850b57cec5SDimitry Andric       KMP_WARNING(ConstructIdentInvalid);
22860b57cec5SDimitry Andric     }
22870b57cec5SDimitry Andric   }
22880b57cec5SDimitry Andric 
22890b57cec5SDimitry Andric   // ToDo: Optimize the following two barriers into some kind of split barrier
22900b57cec5SDimitry Andric 
22910b57cec5SDimitry Andric   if (didit)
22920b57cec5SDimitry Andric     *data_ptr = cpy_data;
22930b57cec5SDimitry Andric 
22940b57cec5SDimitry Andric #if OMPT_SUPPORT
22950b57cec5SDimitry Andric   ompt_frame_t *ompt_frame;
22960b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
22970b57cec5SDimitry Andric     __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
22980b57cec5SDimitry Andric     if (ompt_frame->enter_frame.ptr == NULL)
22990b57cec5SDimitry Andric       ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
23000b57cec5SDimitry Andric   }
2301e8d8bef9SDimitry Andric   OMPT_STORE_RETURN_ADDRESS(gtid);
23020b57cec5SDimitry Andric #endif
23030b57cec5SDimitry Andric /* This barrier is not a barrier region boundary */
23040b57cec5SDimitry Andric #if USE_ITT_NOTIFY
23050b57cec5SDimitry Andric   __kmp_threads[gtid]->th.th_ident = loc;
23060b57cec5SDimitry Andric #endif
23070b57cec5SDimitry Andric   __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
23080b57cec5SDimitry Andric 
23090b57cec5SDimitry Andric   if (!didit)
23100b57cec5SDimitry Andric     (*cpy_func)(cpy_data, *data_ptr);
23110b57cec5SDimitry Andric 
23120b57cec5SDimitry Andric   // Consider next barrier a user-visible barrier for barrier region boundaries
23130b57cec5SDimitry Andric   // Nesting checks are already handled by the single construct checks
2314e8d8bef9SDimitry Andric   {
23150b57cec5SDimitry Andric #if OMPT_SUPPORT
23160b57cec5SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(gtid);
23170b57cec5SDimitry Andric #endif
23180b57cec5SDimitry Andric #if USE_ITT_NOTIFY
23190b57cec5SDimitry Andric     __kmp_threads[gtid]->th.th_ident = loc; // TODO: check if it is needed (e.g.
23200b57cec5SDimitry Andric // tasks can overwrite the location)
23210b57cec5SDimitry Andric #endif
23220b57cec5SDimitry Andric     __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
23230b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
23240b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
23250b57cec5SDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
23260b57cec5SDimitry Andric     }
23270b57cec5SDimitry Andric #endif
23280b57cec5SDimitry Andric   }
2329e8d8bef9SDimitry Andric }
23300b57cec5SDimitry Andric 
23310b57cec5SDimitry Andric /* --------------------------------------------------------------------------*/
2332753f127fSDimitry Andric /*!
2333753f127fSDimitry Andric @ingroup THREADPRIVATE
2334753f127fSDimitry Andric @param loc       source location information
2335753f127fSDimitry Andric @param gtid      global thread number
2336753f127fSDimitry Andric @param cpy_data  pointer to the data to be saved/copied or 0
2337753f127fSDimitry Andric @return          the saved pointer to the data
2338753f127fSDimitry Andric 
2339753f127fSDimitry Andric __kmpc_copyprivate_light is a lighter version of __kmpc_copyprivate:
2340753f127fSDimitry Andric __kmpc_copyprivate_light only saves the pointer it's given (if it's not 0, so
2341753f127fSDimitry Andric coming from single), and returns that pointer in all calls (for single thread
2342753f127fSDimitry Andric it's not needed). This version doesn't do any actual data copying. Data copying
2343753f127fSDimitry Andric has to be done somewhere else, e.g. inline in the generated code. Due to this,
2344753f127fSDimitry Andric this function doesn't have any barrier at the end of the function, like
2345753f127fSDimitry Andric __kmpc_copyprivate does, so generated code needs barrier after copying of all
2346753f127fSDimitry Andric data was done.
2347753f127fSDimitry Andric */
2348753f127fSDimitry Andric void *__kmpc_copyprivate_light(ident_t *loc, kmp_int32 gtid, void *cpy_data) {
2349753f127fSDimitry Andric   void **data_ptr;
2350753f127fSDimitry Andric 
2351753f127fSDimitry Andric   KC_TRACE(10, ("__kmpc_copyprivate_light: called T#%d\n", gtid));
2352753f127fSDimitry Andric 
2353753f127fSDimitry Andric   KMP_MB();
2354753f127fSDimitry Andric 
2355753f127fSDimitry Andric   data_ptr = &__kmp_team_from_gtid(gtid)->t.t_copypriv_data;
2356753f127fSDimitry Andric 
2357753f127fSDimitry Andric   if (__kmp_env_consistency_check) {
2358753f127fSDimitry Andric     if (loc == 0) {
2359753f127fSDimitry Andric       KMP_WARNING(ConstructIdentInvalid);
2360753f127fSDimitry Andric     }
2361753f127fSDimitry Andric   }
2362753f127fSDimitry Andric 
2363753f127fSDimitry Andric   // ToDo: Optimize the following barrier
2364753f127fSDimitry Andric 
2365753f127fSDimitry Andric   if (cpy_data)
2366753f127fSDimitry Andric     *data_ptr = cpy_data;
2367753f127fSDimitry Andric 
2368753f127fSDimitry Andric #if OMPT_SUPPORT
2369753f127fSDimitry Andric   ompt_frame_t *ompt_frame;
2370753f127fSDimitry Andric   if (ompt_enabled.enabled) {
2371753f127fSDimitry Andric     __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
2372753f127fSDimitry Andric     if (ompt_frame->enter_frame.ptr == NULL)
2373753f127fSDimitry Andric       ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
2374753f127fSDimitry Andric     OMPT_STORE_RETURN_ADDRESS(gtid);
2375753f127fSDimitry Andric   }
2376753f127fSDimitry Andric #endif
2377753f127fSDimitry Andric /* This barrier is not a barrier region boundary */
2378753f127fSDimitry Andric #if USE_ITT_NOTIFY
2379753f127fSDimitry Andric   __kmp_threads[gtid]->th.th_ident = loc;
2380753f127fSDimitry Andric #endif
2381753f127fSDimitry Andric   __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2382753f127fSDimitry Andric 
2383753f127fSDimitry Andric   return *data_ptr;
2384753f127fSDimitry Andric }
2385753f127fSDimitry Andric 
2386753f127fSDimitry Andric /* -------------------------------------------------------------------------- */
23870b57cec5SDimitry Andric 
23880b57cec5SDimitry Andric #define INIT_LOCK __kmp_init_user_lock_with_checks
23890b57cec5SDimitry Andric #define INIT_NESTED_LOCK __kmp_init_nested_user_lock_with_checks
23900b57cec5SDimitry Andric #define ACQUIRE_LOCK __kmp_acquire_user_lock_with_checks
23910b57cec5SDimitry Andric #define ACQUIRE_LOCK_TIMED __kmp_acquire_user_lock_with_checks_timed
23920b57cec5SDimitry Andric #define ACQUIRE_NESTED_LOCK __kmp_acquire_nested_user_lock_with_checks
23930b57cec5SDimitry Andric #define ACQUIRE_NESTED_LOCK_TIMED                                              \
23940b57cec5SDimitry Andric   __kmp_acquire_nested_user_lock_with_checks_timed
23950b57cec5SDimitry Andric #define RELEASE_LOCK __kmp_release_user_lock_with_checks
23960b57cec5SDimitry Andric #define RELEASE_NESTED_LOCK __kmp_release_nested_user_lock_with_checks
23970b57cec5SDimitry Andric #define TEST_LOCK __kmp_test_user_lock_with_checks
23980b57cec5SDimitry Andric #define TEST_NESTED_LOCK __kmp_test_nested_user_lock_with_checks
23990b57cec5SDimitry Andric #define DESTROY_LOCK __kmp_destroy_user_lock_with_checks
24000b57cec5SDimitry Andric #define DESTROY_NESTED_LOCK __kmp_destroy_nested_user_lock_with_checks
24010b57cec5SDimitry Andric 
24020b57cec5SDimitry Andric // TODO: Make check abort messages use location info & pass it into
24030b57cec5SDimitry Andric // with_checks routines
24040b57cec5SDimitry Andric 
24050b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
24060b57cec5SDimitry Andric 
24070b57cec5SDimitry Andric // internal lock initializer
24080b57cec5SDimitry Andric static __forceinline void __kmp_init_lock_with_hint(ident_t *loc, void **lock,
24090b57cec5SDimitry Andric                                                     kmp_dyna_lockseq_t seq) {
24100b57cec5SDimitry Andric   if (KMP_IS_D_LOCK(seq)) {
24110b57cec5SDimitry Andric     KMP_INIT_D_LOCK(lock, seq);
24120b57cec5SDimitry Andric #if USE_ITT_BUILD
24130b57cec5SDimitry Andric     __kmp_itt_lock_creating((kmp_user_lock_p)lock, NULL);
24140b57cec5SDimitry Andric #endif
24150b57cec5SDimitry Andric   } else {
24160b57cec5SDimitry Andric     KMP_INIT_I_LOCK(lock, seq);
24170b57cec5SDimitry Andric #if USE_ITT_BUILD
24180b57cec5SDimitry Andric     kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(lock);
24190b57cec5SDimitry Andric     __kmp_itt_lock_creating(ilk->lock, loc);
24200b57cec5SDimitry Andric #endif
24210b57cec5SDimitry Andric   }
24220b57cec5SDimitry Andric }
24230b57cec5SDimitry Andric 
24240b57cec5SDimitry Andric // internal nest lock initializer
24250b57cec5SDimitry Andric static __forceinline void
24260b57cec5SDimitry Andric __kmp_init_nest_lock_with_hint(ident_t *loc, void **lock,
24270b57cec5SDimitry Andric                                kmp_dyna_lockseq_t seq) {
24280b57cec5SDimitry Andric #if KMP_USE_TSX
24290b57cec5SDimitry Andric   // Don't have nested lock implementation for speculative locks
2430e8d8bef9SDimitry Andric   if (seq == lockseq_hle || seq == lockseq_rtm_queuing ||
2431e8d8bef9SDimitry Andric       seq == lockseq_rtm_spin || seq == lockseq_adaptive)
24320b57cec5SDimitry Andric     seq = __kmp_user_lock_seq;
24330b57cec5SDimitry Andric #endif
24340b57cec5SDimitry Andric   switch (seq) {
24350b57cec5SDimitry Andric   case lockseq_tas:
24360b57cec5SDimitry Andric     seq = lockseq_nested_tas;
24370b57cec5SDimitry Andric     break;
24380b57cec5SDimitry Andric #if KMP_USE_FUTEX
24390b57cec5SDimitry Andric   case lockseq_futex:
24400b57cec5SDimitry Andric     seq = lockseq_nested_futex;
24410b57cec5SDimitry Andric     break;
24420b57cec5SDimitry Andric #endif
24430b57cec5SDimitry Andric   case lockseq_ticket:
24440b57cec5SDimitry Andric     seq = lockseq_nested_ticket;
24450b57cec5SDimitry Andric     break;
24460b57cec5SDimitry Andric   case lockseq_queuing:
24470b57cec5SDimitry Andric     seq = lockseq_nested_queuing;
24480b57cec5SDimitry Andric     break;
24490b57cec5SDimitry Andric   case lockseq_drdpa:
24500b57cec5SDimitry Andric     seq = lockseq_nested_drdpa;
24510b57cec5SDimitry Andric     break;
24520b57cec5SDimitry Andric   default:
24530b57cec5SDimitry Andric     seq = lockseq_nested_queuing;
24540b57cec5SDimitry Andric   }
24550b57cec5SDimitry Andric   KMP_INIT_I_LOCK(lock, seq);
24560b57cec5SDimitry Andric #if USE_ITT_BUILD
24570b57cec5SDimitry Andric   kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(lock);
24580b57cec5SDimitry Andric   __kmp_itt_lock_creating(ilk->lock, loc);
24590b57cec5SDimitry Andric #endif
24600b57cec5SDimitry Andric }
24610b57cec5SDimitry Andric 
24620b57cec5SDimitry Andric /* initialize the lock with a hint */
24630b57cec5SDimitry Andric void __kmpc_init_lock_with_hint(ident_t *loc, kmp_int32 gtid, void **user_lock,
24640b57cec5SDimitry Andric                                 uintptr_t hint) {
24650b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
24660b57cec5SDimitry Andric   if (__kmp_env_consistency_check && user_lock == NULL) {
24670b57cec5SDimitry Andric     KMP_FATAL(LockIsUninitialized, "omp_init_lock_with_hint");
24680b57cec5SDimitry Andric   }
24690b57cec5SDimitry Andric 
24700b57cec5SDimitry Andric   __kmp_init_lock_with_hint(loc, user_lock, __kmp_map_hint_to_lock(hint));
24710b57cec5SDimitry Andric 
24720b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
24730b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
24740b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
24750b57cec5SDimitry Andric   if (!codeptr)
24760b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
24770b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_init) {
24780b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
24790b57cec5SDimitry Andric         ompt_mutex_lock, (omp_lock_hint_t)hint,
24800b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
24810b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
24820b57cec5SDimitry Andric   }
24830b57cec5SDimitry Andric #endif
24840b57cec5SDimitry Andric }
24850b57cec5SDimitry Andric 
24860b57cec5SDimitry Andric /* initialize the lock with a hint */
24870b57cec5SDimitry Andric void __kmpc_init_nest_lock_with_hint(ident_t *loc, kmp_int32 gtid,
24880b57cec5SDimitry Andric                                      void **user_lock, uintptr_t hint) {
24890b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
24900b57cec5SDimitry Andric   if (__kmp_env_consistency_check && user_lock == NULL) {
24910b57cec5SDimitry Andric     KMP_FATAL(LockIsUninitialized, "omp_init_nest_lock_with_hint");
24920b57cec5SDimitry Andric   }
24930b57cec5SDimitry Andric 
24940b57cec5SDimitry Andric   __kmp_init_nest_lock_with_hint(loc, user_lock, __kmp_map_hint_to_lock(hint));
24950b57cec5SDimitry Andric 
24960b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
24970b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
24980b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
24990b57cec5SDimitry Andric   if (!codeptr)
25000b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
25010b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_init) {
25020b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
25030b57cec5SDimitry Andric         ompt_mutex_nest_lock, (omp_lock_hint_t)hint,
25040b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
25050b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
25060b57cec5SDimitry Andric   }
25070b57cec5SDimitry Andric #endif
25080b57cec5SDimitry Andric }
25090b57cec5SDimitry Andric 
25100b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
25110b57cec5SDimitry Andric 
25120b57cec5SDimitry Andric /* initialize the lock */
25130b57cec5SDimitry Andric void __kmpc_init_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
25140b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
25150b57cec5SDimitry Andric 
25160b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
25170b57cec5SDimitry Andric   if (__kmp_env_consistency_check && user_lock == NULL) {
25180b57cec5SDimitry Andric     KMP_FATAL(LockIsUninitialized, "omp_init_lock");
25190b57cec5SDimitry Andric   }
25200b57cec5SDimitry Andric   __kmp_init_lock_with_hint(loc, user_lock, __kmp_user_lock_seq);
25210b57cec5SDimitry Andric 
25220b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
25230b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
25240b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
25250b57cec5SDimitry Andric   if (!codeptr)
25260b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
25270b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_init) {
25280b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
25290b57cec5SDimitry Andric         ompt_mutex_lock, omp_lock_hint_none,
25300b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
25310b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
25320b57cec5SDimitry Andric   }
25330b57cec5SDimitry Andric #endif
25340b57cec5SDimitry Andric 
25350b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
25360b57cec5SDimitry Andric 
25370b57cec5SDimitry Andric   static char const *const func = "omp_init_lock";
25380b57cec5SDimitry Andric   kmp_user_lock_p lck;
25390b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
25400b57cec5SDimitry Andric 
25410b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
25420b57cec5SDimitry Andric     if (user_lock == NULL) {
25430b57cec5SDimitry Andric       KMP_FATAL(LockIsUninitialized, func);
25440b57cec5SDimitry Andric     }
25450b57cec5SDimitry Andric   }
25460b57cec5SDimitry Andric 
25470b57cec5SDimitry Andric   KMP_CHECK_USER_LOCK_INIT();
25480b57cec5SDimitry Andric 
25490b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
25500b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
25510b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
25520b57cec5SDimitry Andric   }
25530b57cec5SDimitry Andric #if KMP_USE_FUTEX
25540b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
25550b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
25560b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
25570b57cec5SDimitry Andric   }
25580b57cec5SDimitry Andric #endif
25590b57cec5SDimitry Andric   else {
25600b57cec5SDimitry Andric     lck = __kmp_user_lock_allocate(user_lock, gtid, 0);
25610b57cec5SDimitry Andric   }
25620b57cec5SDimitry Andric   INIT_LOCK(lck);
25630b57cec5SDimitry Andric   __kmp_set_user_lock_location(lck, loc);
25640b57cec5SDimitry Andric 
25650b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
25660b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
25670b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
25680b57cec5SDimitry Andric   if (!codeptr)
25690b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
25700b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_init) {
25710b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
25720b57cec5SDimitry Andric         ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
25730b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
25740b57cec5SDimitry Andric   }
25750b57cec5SDimitry Andric #endif
25760b57cec5SDimitry Andric 
25770b57cec5SDimitry Andric #if USE_ITT_BUILD
25780b57cec5SDimitry Andric   __kmp_itt_lock_creating(lck);
25790b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
25800b57cec5SDimitry Andric 
25810b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
25820b57cec5SDimitry Andric } // __kmpc_init_lock
25830b57cec5SDimitry Andric 
25840b57cec5SDimitry Andric /* initialize the lock */
25850b57cec5SDimitry Andric void __kmpc_init_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
25860b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
25870b57cec5SDimitry Andric 
25880b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
25890b57cec5SDimitry Andric   if (__kmp_env_consistency_check && user_lock == NULL) {
25900b57cec5SDimitry Andric     KMP_FATAL(LockIsUninitialized, "omp_init_nest_lock");
25910b57cec5SDimitry Andric   }
25920b57cec5SDimitry Andric   __kmp_init_nest_lock_with_hint(loc, user_lock, __kmp_user_lock_seq);
25930b57cec5SDimitry Andric 
25940b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
25950b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
25960b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
25970b57cec5SDimitry Andric   if (!codeptr)
25980b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
25990b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_init) {
26000b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
26010b57cec5SDimitry Andric         ompt_mutex_nest_lock, omp_lock_hint_none,
26020b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
26030b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
26040b57cec5SDimitry Andric   }
26050b57cec5SDimitry Andric #endif
26060b57cec5SDimitry Andric 
26070b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
26080b57cec5SDimitry Andric 
26090b57cec5SDimitry Andric   static char const *const func = "omp_init_nest_lock";
26100b57cec5SDimitry Andric   kmp_user_lock_p lck;
26110b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(__kmp_init_serial);
26120b57cec5SDimitry Andric 
26130b57cec5SDimitry Andric   if (__kmp_env_consistency_check) {
26140b57cec5SDimitry Andric     if (user_lock == NULL) {
26150b57cec5SDimitry Andric       KMP_FATAL(LockIsUninitialized, func);
26160b57cec5SDimitry Andric     }
26170b57cec5SDimitry Andric   }
26180b57cec5SDimitry Andric 
26190b57cec5SDimitry Andric   KMP_CHECK_USER_LOCK_INIT();
26200b57cec5SDimitry Andric 
26210b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
26220b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
26230b57cec5SDimitry Andric        OMP_NEST_LOCK_T_SIZE)) {
26240b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
26250b57cec5SDimitry Andric   }
26260b57cec5SDimitry Andric #if KMP_USE_FUTEX
26270b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
26280b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
26290b57cec5SDimitry Andric             OMP_NEST_LOCK_T_SIZE)) {
26300b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
26310b57cec5SDimitry Andric   }
26320b57cec5SDimitry Andric #endif
26330b57cec5SDimitry Andric   else {
26340b57cec5SDimitry Andric     lck = __kmp_user_lock_allocate(user_lock, gtid, 0);
26350b57cec5SDimitry Andric   }
26360b57cec5SDimitry Andric 
26370b57cec5SDimitry Andric   INIT_NESTED_LOCK(lck);
26380b57cec5SDimitry Andric   __kmp_set_user_lock_location(lck, loc);
26390b57cec5SDimitry Andric 
26400b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
26410b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
26420b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
26430b57cec5SDimitry Andric   if (!codeptr)
26440b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
26450b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_init) {
26460b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
26470b57cec5SDimitry Andric         ompt_mutex_nest_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
26480b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
26490b57cec5SDimitry Andric   }
26500b57cec5SDimitry Andric #endif
26510b57cec5SDimitry Andric 
26520b57cec5SDimitry Andric #if USE_ITT_BUILD
26530b57cec5SDimitry Andric   __kmp_itt_lock_creating(lck);
26540b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
26550b57cec5SDimitry Andric 
26560b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
26570b57cec5SDimitry Andric } // __kmpc_init_nest_lock
26580b57cec5SDimitry Andric 
26590b57cec5SDimitry Andric void __kmpc_destroy_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
26600b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
26610b57cec5SDimitry Andric 
26620b57cec5SDimitry Andric #if USE_ITT_BUILD
26630b57cec5SDimitry Andric   kmp_user_lock_p lck;
26640b57cec5SDimitry Andric   if (KMP_EXTRACT_D_TAG(user_lock) == 0) {
26650b57cec5SDimitry Andric     lck = ((kmp_indirect_lock_t *)KMP_LOOKUP_I_LOCK(user_lock))->lock;
26660b57cec5SDimitry Andric   } else {
26670b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
26680b57cec5SDimitry Andric   }
26690b57cec5SDimitry Andric   __kmp_itt_lock_destroyed(lck);
26700b57cec5SDimitry Andric #endif
26710b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
26720b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
26730b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
26740b57cec5SDimitry Andric   if (!codeptr)
26750b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
26760b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_destroy) {
26770b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
26780b57cec5SDimitry Andric         ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
26790b57cec5SDimitry Andric   }
26800b57cec5SDimitry Andric #endif
26810b57cec5SDimitry Andric   KMP_D_LOCK_FUNC(user_lock, destroy)((kmp_dyna_lock_t *)user_lock);
26820b57cec5SDimitry Andric #else
26830b57cec5SDimitry Andric   kmp_user_lock_p lck;
26840b57cec5SDimitry Andric 
26850b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
26860b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
26870b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
26880b57cec5SDimitry Andric   }
26890b57cec5SDimitry Andric #if KMP_USE_FUTEX
26900b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
26910b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
26920b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
26930b57cec5SDimitry Andric   }
26940b57cec5SDimitry Andric #endif
26950b57cec5SDimitry Andric   else {
26960b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_destroy_lock");
26970b57cec5SDimitry Andric   }
26980b57cec5SDimitry Andric 
26990b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
27000b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
27010b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
27020b57cec5SDimitry Andric   if (!codeptr)
27030b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
27040b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_destroy) {
27050b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
27060b57cec5SDimitry Andric         ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
27070b57cec5SDimitry Andric   }
27080b57cec5SDimitry Andric #endif
27090b57cec5SDimitry Andric 
27100b57cec5SDimitry Andric #if USE_ITT_BUILD
27110b57cec5SDimitry Andric   __kmp_itt_lock_destroyed(lck);
27120b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
27130b57cec5SDimitry Andric   DESTROY_LOCK(lck);
27140b57cec5SDimitry Andric 
27150b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
27160b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
27170b57cec5SDimitry Andric     ;
27180b57cec5SDimitry Andric   }
27190b57cec5SDimitry Andric #if KMP_USE_FUTEX
27200b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
27210b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
27220b57cec5SDimitry Andric     ;
27230b57cec5SDimitry Andric   }
27240b57cec5SDimitry Andric #endif
27250b57cec5SDimitry Andric   else {
27260b57cec5SDimitry Andric     __kmp_user_lock_free(user_lock, gtid, lck);
27270b57cec5SDimitry Andric   }
27280b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
27290b57cec5SDimitry Andric } // __kmpc_destroy_lock
27300b57cec5SDimitry Andric 
27310b57cec5SDimitry Andric /* destroy the lock */
27320b57cec5SDimitry Andric void __kmpc_destroy_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
27330b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
27340b57cec5SDimitry Andric 
27350b57cec5SDimitry Andric #if USE_ITT_BUILD
27360b57cec5SDimitry Andric   kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(user_lock);
27370b57cec5SDimitry Andric   __kmp_itt_lock_destroyed(ilk->lock);
27380b57cec5SDimitry Andric #endif
27390b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
27400b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
27410b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
27420b57cec5SDimitry Andric   if (!codeptr)
27430b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
27440b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_destroy) {
27450b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
27460b57cec5SDimitry Andric         ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
27470b57cec5SDimitry Andric   }
27480b57cec5SDimitry Andric #endif
27490b57cec5SDimitry Andric   KMP_D_LOCK_FUNC(user_lock, destroy)((kmp_dyna_lock_t *)user_lock);
27500b57cec5SDimitry Andric 
27510b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
27520b57cec5SDimitry Andric 
27530b57cec5SDimitry Andric   kmp_user_lock_p lck;
27540b57cec5SDimitry Andric 
27550b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
27560b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
27570b57cec5SDimitry Andric        OMP_NEST_LOCK_T_SIZE)) {
27580b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
27590b57cec5SDimitry Andric   }
27600b57cec5SDimitry Andric #if KMP_USE_FUTEX
27610b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
27620b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
27630b57cec5SDimitry Andric             OMP_NEST_LOCK_T_SIZE)) {
27640b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
27650b57cec5SDimitry Andric   }
27660b57cec5SDimitry Andric #endif
27670b57cec5SDimitry Andric   else {
27680b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_destroy_nest_lock");
27690b57cec5SDimitry Andric   }
27700b57cec5SDimitry Andric 
27710b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
27720b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
27730b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
27740b57cec5SDimitry Andric   if (!codeptr)
27750b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
27760b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_lock_destroy) {
27770b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
27780b57cec5SDimitry Andric         ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
27790b57cec5SDimitry Andric   }
27800b57cec5SDimitry Andric #endif
27810b57cec5SDimitry Andric 
27820b57cec5SDimitry Andric #if USE_ITT_BUILD
27830b57cec5SDimitry Andric   __kmp_itt_lock_destroyed(lck);
27840b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
27850b57cec5SDimitry Andric 
27860b57cec5SDimitry Andric   DESTROY_NESTED_LOCK(lck);
27870b57cec5SDimitry Andric 
27880b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
27890b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
27900b57cec5SDimitry Andric        OMP_NEST_LOCK_T_SIZE)) {
27910b57cec5SDimitry Andric     ;
27920b57cec5SDimitry Andric   }
27930b57cec5SDimitry Andric #if KMP_USE_FUTEX
27940b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
27950b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
27960b57cec5SDimitry Andric             OMP_NEST_LOCK_T_SIZE)) {
27970b57cec5SDimitry Andric     ;
27980b57cec5SDimitry Andric   }
27990b57cec5SDimitry Andric #endif
28000b57cec5SDimitry Andric   else {
28010b57cec5SDimitry Andric     __kmp_user_lock_free(user_lock, gtid, lck);
28020b57cec5SDimitry Andric   }
28030b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
28040b57cec5SDimitry Andric } // __kmpc_destroy_nest_lock
28050b57cec5SDimitry Andric 
28060b57cec5SDimitry Andric void __kmpc_set_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
28070b57cec5SDimitry Andric   KMP_COUNT_BLOCK(OMP_set_lock);
28080b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
28090b57cec5SDimitry Andric   int tag = KMP_EXTRACT_D_TAG(user_lock);
28100b57cec5SDimitry Andric #if USE_ITT_BUILD
28110b57cec5SDimitry Andric   __kmp_itt_lock_acquiring(
28120b57cec5SDimitry Andric       (kmp_user_lock_p)
28130b57cec5SDimitry Andric           user_lock); // itt function will get to the right lock object.
28140b57cec5SDimitry Andric #endif
28150b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
28160b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
28170b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
28180b57cec5SDimitry Andric   if (!codeptr)
28190b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
28200b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquire) {
28210b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
28220b57cec5SDimitry Andric         ompt_mutex_lock, omp_lock_hint_none,
28230b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
28240b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
28250b57cec5SDimitry Andric   }
28260b57cec5SDimitry Andric #endif
28270b57cec5SDimitry Andric #if KMP_USE_INLINED_TAS
28280b57cec5SDimitry Andric   if (tag == locktag_tas && !__kmp_env_consistency_check) {
28290b57cec5SDimitry Andric     KMP_ACQUIRE_TAS_LOCK(user_lock, gtid);
28300b57cec5SDimitry Andric   } else
28310b57cec5SDimitry Andric #elif KMP_USE_INLINED_FUTEX
28320b57cec5SDimitry Andric   if (tag == locktag_futex && !__kmp_env_consistency_check) {
28330b57cec5SDimitry Andric     KMP_ACQUIRE_FUTEX_LOCK(user_lock, gtid);
28340b57cec5SDimitry Andric   } else
28350b57cec5SDimitry Andric #endif
28360b57cec5SDimitry Andric   {
28370b57cec5SDimitry Andric     __kmp_direct_set[tag]((kmp_dyna_lock_t *)user_lock, gtid);
28380b57cec5SDimitry Andric   }
28390b57cec5SDimitry Andric #if USE_ITT_BUILD
28400b57cec5SDimitry Andric   __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
28410b57cec5SDimitry Andric #endif
28420b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
28430b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquired) {
28440b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
28450b57cec5SDimitry Andric         ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
28460b57cec5SDimitry Andric   }
28470b57cec5SDimitry Andric #endif
28480b57cec5SDimitry Andric 
28490b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
28500b57cec5SDimitry Andric 
28510b57cec5SDimitry Andric   kmp_user_lock_p lck;
28520b57cec5SDimitry Andric 
28530b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
28540b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
28550b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
28560b57cec5SDimitry Andric   }
28570b57cec5SDimitry Andric #if KMP_USE_FUTEX
28580b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
28590b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
28600b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
28610b57cec5SDimitry Andric   }
28620b57cec5SDimitry Andric #endif
28630b57cec5SDimitry Andric   else {
28640b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_set_lock");
28650b57cec5SDimitry Andric   }
28660b57cec5SDimitry Andric 
28670b57cec5SDimitry Andric #if USE_ITT_BUILD
28680b57cec5SDimitry Andric   __kmp_itt_lock_acquiring(lck);
28690b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
28700b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
28710b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
28720b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
28730b57cec5SDimitry Andric   if (!codeptr)
28740b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
28750b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquire) {
28760b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
28770b57cec5SDimitry Andric         ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
28780b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)lck, codeptr);
28790b57cec5SDimitry Andric   }
28800b57cec5SDimitry Andric #endif
28810b57cec5SDimitry Andric 
28820b57cec5SDimitry Andric   ACQUIRE_LOCK(lck, gtid);
28830b57cec5SDimitry Andric 
28840b57cec5SDimitry Andric #if USE_ITT_BUILD
28850b57cec5SDimitry Andric   __kmp_itt_lock_acquired(lck);
28860b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
28870b57cec5SDimitry Andric 
28880b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
28890b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquired) {
28900b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
28910b57cec5SDimitry Andric         ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
28920b57cec5SDimitry Andric   }
28930b57cec5SDimitry Andric #endif
28940b57cec5SDimitry Andric 
28950b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
28960b57cec5SDimitry Andric }
28970b57cec5SDimitry Andric 
28980b57cec5SDimitry Andric void __kmpc_set_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
28990b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
29000b57cec5SDimitry Andric 
29010b57cec5SDimitry Andric #if USE_ITT_BUILD
29020b57cec5SDimitry Andric   __kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
29030b57cec5SDimitry Andric #endif
29040b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
29050b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
29060b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
29070b57cec5SDimitry Andric   if (!codeptr)
29080b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
29090b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
29100b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquire) {
29110b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
29120b57cec5SDimitry Andric           ompt_mutex_nest_lock, omp_lock_hint_none,
29130b57cec5SDimitry Andric           __ompt_get_mutex_impl_type(user_lock),
29140b57cec5SDimitry Andric           (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
29150b57cec5SDimitry Andric     }
29160b57cec5SDimitry Andric   }
29170b57cec5SDimitry Andric #endif
29180b57cec5SDimitry Andric   int acquire_status =
29190b57cec5SDimitry Andric       KMP_D_LOCK_FUNC(user_lock, set)((kmp_dyna_lock_t *)user_lock, gtid);
29200b57cec5SDimitry Andric   (void)acquire_status;
29210b57cec5SDimitry Andric #if USE_ITT_BUILD
29220b57cec5SDimitry Andric   __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
29230b57cec5SDimitry Andric #endif
29240b57cec5SDimitry Andric 
29250b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
29260b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
29270b57cec5SDimitry Andric     if (acquire_status == KMP_LOCK_ACQUIRED_FIRST) {
29280b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_acquired) {
29290b57cec5SDimitry Andric         // lock_first
29300b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
29310b57cec5SDimitry Andric             ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
29320b57cec5SDimitry Andric             codeptr);
29330b57cec5SDimitry Andric       }
29340b57cec5SDimitry Andric     } else {
29350b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_nest_lock) {
29360b57cec5SDimitry Andric         // lock_next
29370b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
29380b57cec5SDimitry Andric             ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
29390b57cec5SDimitry Andric       }
29400b57cec5SDimitry Andric     }
29410b57cec5SDimitry Andric   }
29420b57cec5SDimitry Andric #endif
29430b57cec5SDimitry Andric 
29440b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
29450b57cec5SDimitry Andric   int acquire_status;
29460b57cec5SDimitry Andric   kmp_user_lock_p lck;
29470b57cec5SDimitry Andric 
29480b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
29490b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
29500b57cec5SDimitry Andric        OMP_NEST_LOCK_T_SIZE)) {
29510b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
29520b57cec5SDimitry Andric   }
29530b57cec5SDimitry Andric #if KMP_USE_FUTEX
29540b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
29550b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
29560b57cec5SDimitry Andric             OMP_NEST_LOCK_T_SIZE)) {
29570b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
29580b57cec5SDimitry Andric   }
29590b57cec5SDimitry Andric #endif
29600b57cec5SDimitry Andric   else {
29610b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_set_nest_lock");
29620b57cec5SDimitry Andric   }
29630b57cec5SDimitry Andric 
29640b57cec5SDimitry Andric #if USE_ITT_BUILD
29650b57cec5SDimitry Andric   __kmp_itt_lock_acquiring(lck);
29660b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
29670b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
29680b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
29690b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
29700b57cec5SDimitry Andric   if (!codeptr)
29710b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
29720b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
29730b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquire) {
29740b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
29750b57cec5SDimitry Andric           ompt_mutex_nest_lock, omp_lock_hint_none,
29760b57cec5SDimitry Andric           __ompt_get_mutex_impl_type(), (ompt_wait_id_t)(uintptr_t)lck,
29770b57cec5SDimitry Andric           codeptr);
29780b57cec5SDimitry Andric     }
29790b57cec5SDimitry Andric   }
29800b57cec5SDimitry Andric #endif
29810b57cec5SDimitry Andric 
29820b57cec5SDimitry Andric   ACQUIRE_NESTED_LOCK(lck, gtid, &acquire_status);
29830b57cec5SDimitry Andric 
29840b57cec5SDimitry Andric #if USE_ITT_BUILD
29850b57cec5SDimitry Andric   __kmp_itt_lock_acquired(lck);
29860b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
29870b57cec5SDimitry Andric 
29880b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
29890b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
29900b57cec5SDimitry Andric     if (acquire_status == KMP_LOCK_ACQUIRED_FIRST) {
29910b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_acquired) {
29920b57cec5SDimitry Andric         // lock_first
29930b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
29940b57cec5SDimitry Andric             ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
29950b57cec5SDimitry Andric       }
29960b57cec5SDimitry Andric     } else {
29970b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_nest_lock) {
29980b57cec5SDimitry Andric         // lock_next
29990b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
30000b57cec5SDimitry Andric             ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
30010b57cec5SDimitry Andric       }
30020b57cec5SDimitry Andric     }
30030b57cec5SDimitry Andric   }
30040b57cec5SDimitry Andric #endif
30050b57cec5SDimitry Andric 
30060b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
30070b57cec5SDimitry Andric }
30080b57cec5SDimitry Andric 
30090b57cec5SDimitry Andric void __kmpc_unset_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
30100b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
30110b57cec5SDimitry Andric 
30120b57cec5SDimitry Andric   int tag = KMP_EXTRACT_D_TAG(user_lock);
30130b57cec5SDimitry Andric #if USE_ITT_BUILD
30140b57cec5SDimitry Andric   __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
30150b57cec5SDimitry Andric #endif
30160b57cec5SDimitry Andric #if KMP_USE_INLINED_TAS
30170b57cec5SDimitry Andric   if (tag == locktag_tas && !__kmp_env_consistency_check) {
30180b57cec5SDimitry Andric     KMP_RELEASE_TAS_LOCK(user_lock, gtid);
30190b57cec5SDimitry Andric   } else
30200b57cec5SDimitry Andric #elif KMP_USE_INLINED_FUTEX
30210b57cec5SDimitry Andric   if (tag == locktag_futex && !__kmp_env_consistency_check) {
30220b57cec5SDimitry Andric     KMP_RELEASE_FUTEX_LOCK(user_lock, gtid);
30230b57cec5SDimitry Andric   } else
30240b57cec5SDimitry Andric #endif
30250b57cec5SDimitry Andric   {
30260b57cec5SDimitry Andric     __kmp_direct_unset[tag]((kmp_dyna_lock_t *)user_lock, gtid);
30270b57cec5SDimitry Andric   }
30280b57cec5SDimitry Andric 
30290b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
30300b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
30310b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
30320b57cec5SDimitry Andric   if (!codeptr)
30330b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
30340b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_released) {
30350b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
30360b57cec5SDimitry Andric         ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
30370b57cec5SDimitry Andric   }
30380b57cec5SDimitry Andric #endif
30390b57cec5SDimitry Andric 
30400b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
30410b57cec5SDimitry Andric 
30420b57cec5SDimitry Andric   kmp_user_lock_p lck;
30430b57cec5SDimitry Andric 
30440b57cec5SDimitry Andric   /* Can't use serial interval since not block structured */
30450b57cec5SDimitry Andric   /* release the lock */
30460b57cec5SDimitry Andric 
30470b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
30480b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
30490b57cec5SDimitry Andric #if KMP_OS_LINUX &&                                                            \
30500b57cec5SDimitry Andric     (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
30510b57cec5SDimitry Andric // "fast" path implemented to fix customer performance issue
30520b57cec5SDimitry Andric #if USE_ITT_BUILD
30530b57cec5SDimitry Andric     __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
30540b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
30550b57cec5SDimitry Andric     TCW_4(((kmp_user_lock_p)user_lock)->tas.lk.poll, 0);
30560b57cec5SDimitry Andric     KMP_MB();
30570b57cec5SDimitry Andric 
30580b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
30590b57cec5SDimitry Andric     // This is the case, if called from omp_init_lock_with_hint:
30600b57cec5SDimitry Andric     void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
30610b57cec5SDimitry Andric     if (!codeptr)
30620b57cec5SDimitry Andric       codeptr = OMPT_GET_RETURN_ADDRESS(0);
30630b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_released) {
30640b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
30650b57cec5SDimitry Andric           ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
30660b57cec5SDimitry Andric     }
30670b57cec5SDimitry Andric #endif
30680b57cec5SDimitry Andric 
30690b57cec5SDimitry Andric     return;
30700b57cec5SDimitry Andric #else
30710b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
30720b57cec5SDimitry Andric #endif
30730b57cec5SDimitry Andric   }
30740b57cec5SDimitry Andric #if KMP_USE_FUTEX
30750b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
30760b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
30770b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
30780b57cec5SDimitry Andric   }
30790b57cec5SDimitry Andric #endif
30800b57cec5SDimitry Andric   else {
30810b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_unset_lock");
30820b57cec5SDimitry Andric   }
30830b57cec5SDimitry Andric 
30840b57cec5SDimitry Andric #if USE_ITT_BUILD
30850b57cec5SDimitry Andric   __kmp_itt_lock_releasing(lck);
30860b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
30870b57cec5SDimitry Andric 
30880b57cec5SDimitry Andric   RELEASE_LOCK(lck, gtid);
30890b57cec5SDimitry Andric 
30900b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
30910b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
30920b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
30930b57cec5SDimitry Andric   if (!codeptr)
30940b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
30950b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_released) {
30960b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
30970b57cec5SDimitry Andric         ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
30980b57cec5SDimitry Andric   }
30990b57cec5SDimitry Andric #endif
31000b57cec5SDimitry Andric 
31010b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
31020b57cec5SDimitry Andric }
31030b57cec5SDimitry Andric 
31040b57cec5SDimitry Andric /* release the lock */
31050b57cec5SDimitry Andric void __kmpc_unset_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
31060b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
31070b57cec5SDimitry Andric 
31080b57cec5SDimitry Andric #if USE_ITT_BUILD
31090b57cec5SDimitry Andric   __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
31100b57cec5SDimitry Andric #endif
31110b57cec5SDimitry Andric   int release_status =
31120b57cec5SDimitry Andric       KMP_D_LOCK_FUNC(user_lock, unset)((kmp_dyna_lock_t *)user_lock, gtid);
31130b57cec5SDimitry Andric   (void)release_status;
31140b57cec5SDimitry Andric 
31150b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
31160b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
31170b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
31180b57cec5SDimitry Andric   if (!codeptr)
31190b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
31200b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
31210b57cec5SDimitry Andric     if (release_status == KMP_LOCK_RELEASED) {
31220b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_released) {
31230b57cec5SDimitry Andric         // release_lock_last
31240b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
31250b57cec5SDimitry Andric             ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
31260b57cec5SDimitry Andric             codeptr);
31270b57cec5SDimitry Andric       }
31280b57cec5SDimitry Andric     } else if (ompt_enabled.ompt_callback_nest_lock) {
31290b57cec5SDimitry Andric       // release_lock_prev
31300b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
31310b57cec5SDimitry Andric           ompt_scope_end, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
31320b57cec5SDimitry Andric     }
31330b57cec5SDimitry Andric   }
31340b57cec5SDimitry Andric #endif
31350b57cec5SDimitry Andric 
31360b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
31370b57cec5SDimitry Andric 
31380b57cec5SDimitry Andric   kmp_user_lock_p lck;
31390b57cec5SDimitry Andric 
31400b57cec5SDimitry Andric   /* Can't use serial interval since not block structured */
31410b57cec5SDimitry Andric 
31420b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
31430b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
31440b57cec5SDimitry Andric        OMP_NEST_LOCK_T_SIZE)) {
31450b57cec5SDimitry Andric #if KMP_OS_LINUX &&                                                            \
31460b57cec5SDimitry Andric     (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
31470b57cec5SDimitry Andric     // "fast" path implemented to fix customer performance issue
31480b57cec5SDimitry Andric     kmp_tas_lock_t *tl = (kmp_tas_lock_t *)user_lock;
31490b57cec5SDimitry Andric #if USE_ITT_BUILD
31500b57cec5SDimitry Andric     __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
31510b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
31520b57cec5SDimitry Andric 
31530b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
31540b57cec5SDimitry Andric     int release_status = KMP_LOCK_STILL_HELD;
31550b57cec5SDimitry Andric #endif
31560b57cec5SDimitry Andric 
31570b57cec5SDimitry Andric     if (--(tl->lk.depth_locked) == 0) {
31580b57cec5SDimitry Andric       TCW_4(tl->lk.poll, 0);
31590b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
31600b57cec5SDimitry Andric       release_status = KMP_LOCK_RELEASED;
31610b57cec5SDimitry Andric #endif
31620b57cec5SDimitry Andric     }
31630b57cec5SDimitry Andric     KMP_MB();
31640b57cec5SDimitry Andric 
31650b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
31660b57cec5SDimitry Andric     // This is the case, if called from omp_init_lock_with_hint:
31670b57cec5SDimitry Andric     void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
31680b57cec5SDimitry Andric     if (!codeptr)
31690b57cec5SDimitry Andric       codeptr = OMPT_GET_RETURN_ADDRESS(0);
31700b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
31710b57cec5SDimitry Andric       if (release_status == KMP_LOCK_RELEASED) {
31720b57cec5SDimitry Andric         if (ompt_enabled.ompt_callback_mutex_released) {
31730b57cec5SDimitry Andric           // release_lock_last
31740b57cec5SDimitry Andric           ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
31750b57cec5SDimitry Andric               ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
31760b57cec5SDimitry Andric         }
31770b57cec5SDimitry Andric       } else if (ompt_enabled.ompt_callback_nest_lock) {
31780b57cec5SDimitry Andric         // release_lock_previous
31790b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
31800b57cec5SDimitry Andric             ompt_mutex_scope_end, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
31810b57cec5SDimitry Andric       }
31820b57cec5SDimitry Andric     }
31830b57cec5SDimitry Andric #endif
31840b57cec5SDimitry Andric 
31850b57cec5SDimitry Andric     return;
31860b57cec5SDimitry Andric #else
31870b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
31880b57cec5SDimitry Andric #endif
31890b57cec5SDimitry Andric   }
31900b57cec5SDimitry Andric #if KMP_USE_FUTEX
31910b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
31920b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
31930b57cec5SDimitry Andric             OMP_NEST_LOCK_T_SIZE)) {
31940b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
31950b57cec5SDimitry Andric   }
31960b57cec5SDimitry Andric #endif
31970b57cec5SDimitry Andric   else {
31980b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_unset_nest_lock");
31990b57cec5SDimitry Andric   }
32000b57cec5SDimitry Andric 
32010b57cec5SDimitry Andric #if USE_ITT_BUILD
32020b57cec5SDimitry Andric   __kmp_itt_lock_releasing(lck);
32030b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
32040b57cec5SDimitry Andric 
32050b57cec5SDimitry Andric   int release_status;
32060b57cec5SDimitry Andric   release_status = RELEASE_NESTED_LOCK(lck, gtid);
32070b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
32080b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
32090b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
32100b57cec5SDimitry Andric   if (!codeptr)
32110b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
32120b57cec5SDimitry Andric   if (ompt_enabled.enabled) {
32130b57cec5SDimitry Andric     if (release_status == KMP_LOCK_RELEASED) {
32140b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_released) {
32150b57cec5SDimitry Andric         // release_lock_last
32160b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
32170b57cec5SDimitry Andric             ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
32180b57cec5SDimitry Andric       }
32190b57cec5SDimitry Andric     } else if (ompt_enabled.ompt_callback_nest_lock) {
32200b57cec5SDimitry Andric       // release_lock_previous
32210b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
32220b57cec5SDimitry Andric           ompt_mutex_scope_end, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
32230b57cec5SDimitry Andric     }
32240b57cec5SDimitry Andric   }
32250b57cec5SDimitry Andric #endif
32260b57cec5SDimitry Andric 
32270b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
32280b57cec5SDimitry Andric }
32290b57cec5SDimitry Andric 
32300b57cec5SDimitry Andric /* try to acquire the lock */
32310b57cec5SDimitry Andric int __kmpc_test_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
32320b57cec5SDimitry Andric   KMP_COUNT_BLOCK(OMP_test_lock);
32330b57cec5SDimitry Andric 
32340b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
32350b57cec5SDimitry Andric   int rc;
32360b57cec5SDimitry Andric   int tag = KMP_EXTRACT_D_TAG(user_lock);
32370b57cec5SDimitry Andric #if USE_ITT_BUILD
32380b57cec5SDimitry Andric   __kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
32390b57cec5SDimitry Andric #endif
32400b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
32410b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
32420b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
32430b57cec5SDimitry Andric   if (!codeptr)
32440b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
32450b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquire) {
32460b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
324706c3fb27SDimitry Andric         ompt_mutex_test_lock, omp_lock_hint_none,
32480b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
32490b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
32500b57cec5SDimitry Andric   }
32510b57cec5SDimitry Andric #endif
32520b57cec5SDimitry Andric #if KMP_USE_INLINED_TAS
32530b57cec5SDimitry Andric   if (tag == locktag_tas && !__kmp_env_consistency_check) {
32540b57cec5SDimitry Andric     KMP_TEST_TAS_LOCK(user_lock, gtid, rc);
32550b57cec5SDimitry Andric   } else
32560b57cec5SDimitry Andric #elif KMP_USE_INLINED_FUTEX
32570b57cec5SDimitry Andric   if (tag == locktag_futex && !__kmp_env_consistency_check) {
32580b57cec5SDimitry Andric     KMP_TEST_FUTEX_LOCK(user_lock, gtid, rc);
32590b57cec5SDimitry Andric   } else
32600b57cec5SDimitry Andric #endif
32610b57cec5SDimitry Andric   {
32620b57cec5SDimitry Andric     rc = __kmp_direct_test[tag]((kmp_dyna_lock_t *)user_lock, gtid);
32630b57cec5SDimitry Andric   }
32640b57cec5SDimitry Andric   if (rc) {
32650b57cec5SDimitry Andric #if USE_ITT_BUILD
32660b57cec5SDimitry Andric     __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
32670b57cec5SDimitry Andric #endif
32680b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
32690b57cec5SDimitry Andric     if (ompt_enabled.ompt_callback_mutex_acquired) {
32700b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
327106c3fb27SDimitry Andric           ompt_mutex_test_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
32720b57cec5SDimitry Andric     }
32730b57cec5SDimitry Andric #endif
32740b57cec5SDimitry Andric     return FTN_TRUE;
32750b57cec5SDimitry Andric   } else {
32760b57cec5SDimitry Andric #if USE_ITT_BUILD
32770b57cec5SDimitry Andric     __kmp_itt_lock_cancelled((kmp_user_lock_p)user_lock);
32780b57cec5SDimitry Andric #endif
32790b57cec5SDimitry Andric     return FTN_FALSE;
32800b57cec5SDimitry Andric   }
32810b57cec5SDimitry Andric 
32820b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
32830b57cec5SDimitry Andric 
32840b57cec5SDimitry Andric   kmp_user_lock_p lck;
32850b57cec5SDimitry Andric   int rc;
32860b57cec5SDimitry Andric 
32870b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
32880b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
32890b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
32900b57cec5SDimitry Andric   }
32910b57cec5SDimitry Andric #if KMP_USE_FUTEX
32920b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
32930b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
32940b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
32950b57cec5SDimitry Andric   }
32960b57cec5SDimitry Andric #endif
32970b57cec5SDimitry Andric   else {
32980b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_test_lock");
32990b57cec5SDimitry Andric   }
33000b57cec5SDimitry Andric 
33010b57cec5SDimitry Andric #if USE_ITT_BUILD
33020b57cec5SDimitry Andric   __kmp_itt_lock_acquiring(lck);
33030b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
33040b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
33050b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
33060b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
33070b57cec5SDimitry Andric   if (!codeptr)
33080b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
33090b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquire) {
33100b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
331106c3fb27SDimitry Andric         ompt_mutex_test_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
33120b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)lck, codeptr);
33130b57cec5SDimitry Andric   }
33140b57cec5SDimitry Andric #endif
33150b57cec5SDimitry Andric 
33160b57cec5SDimitry Andric   rc = TEST_LOCK(lck, gtid);
33170b57cec5SDimitry Andric #if USE_ITT_BUILD
33180b57cec5SDimitry Andric   if (rc) {
33190b57cec5SDimitry Andric     __kmp_itt_lock_acquired(lck);
33200b57cec5SDimitry Andric   } else {
33210b57cec5SDimitry Andric     __kmp_itt_lock_cancelled(lck);
33220b57cec5SDimitry Andric   }
33230b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
33240b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
33250b57cec5SDimitry Andric   if (rc && ompt_enabled.ompt_callback_mutex_acquired) {
33260b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
332706c3fb27SDimitry Andric         ompt_mutex_test_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
33280b57cec5SDimitry Andric   }
33290b57cec5SDimitry Andric #endif
33300b57cec5SDimitry Andric 
33310b57cec5SDimitry Andric   return (rc ? FTN_TRUE : FTN_FALSE);
33320b57cec5SDimitry Andric 
33330b57cec5SDimitry Andric   /* Can't use serial interval since not block structured */
33340b57cec5SDimitry Andric 
33350b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
33360b57cec5SDimitry Andric }
33370b57cec5SDimitry Andric 
33380b57cec5SDimitry Andric /* try to acquire the lock */
33390b57cec5SDimitry Andric int __kmpc_test_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
33400b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
33410b57cec5SDimitry Andric   int rc;
33420b57cec5SDimitry Andric #if USE_ITT_BUILD
33430b57cec5SDimitry Andric   __kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
33440b57cec5SDimitry Andric #endif
33450b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
33460b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
33470b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
33480b57cec5SDimitry Andric   if (!codeptr)
33490b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
33500b57cec5SDimitry Andric   if (ompt_enabled.ompt_callback_mutex_acquire) {
33510b57cec5SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
335206c3fb27SDimitry Andric         ompt_mutex_test_nest_lock, omp_lock_hint_none,
33530b57cec5SDimitry Andric         __ompt_get_mutex_impl_type(user_lock),
33540b57cec5SDimitry Andric         (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
33550b57cec5SDimitry Andric   }
33560b57cec5SDimitry Andric #endif
33570b57cec5SDimitry Andric   rc = KMP_D_LOCK_FUNC(user_lock, test)((kmp_dyna_lock_t *)user_lock, gtid);
33580b57cec5SDimitry Andric #if USE_ITT_BUILD
33590b57cec5SDimitry Andric   if (rc) {
33600b57cec5SDimitry Andric     __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
33610b57cec5SDimitry Andric   } else {
33620b57cec5SDimitry Andric     __kmp_itt_lock_cancelled((kmp_user_lock_p)user_lock);
33630b57cec5SDimitry Andric   }
33640b57cec5SDimitry Andric #endif
33650b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
33660b57cec5SDimitry Andric   if (ompt_enabled.enabled && rc) {
33670b57cec5SDimitry Andric     if (rc == 1) {
33680b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_acquired) {
33690b57cec5SDimitry Andric         // lock_first
33700b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
337106c3fb27SDimitry Andric             ompt_mutex_test_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
33720b57cec5SDimitry Andric             codeptr);
33730b57cec5SDimitry Andric       }
33740b57cec5SDimitry Andric     } else {
33750b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_nest_lock) {
33760b57cec5SDimitry Andric         // lock_next
33770b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
33780b57cec5SDimitry Andric             ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
33790b57cec5SDimitry Andric       }
33800b57cec5SDimitry Andric     }
33810b57cec5SDimitry Andric   }
33820b57cec5SDimitry Andric #endif
33830b57cec5SDimitry Andric   return rc;
33840b57cec5SDimitry Andric 
33850b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
33860b57cec5SDimitry Andric 
33870b57cec5SDimitry Andric   kmp_user_lock_p lck;
33880b57cec5SDimitry Andric   int rc;
33890b57cec5SDimitry Andric 
33900b57cec5SDimitry Andric   if ((__kmp_user_lock_kind == lk_tas) &&
33910b57cec5SDimitry Andric       (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
33920b57cec5SDimitry Andric        OMP_NEST_LOCK_T_SIZE)) {
33930b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
33940b57cec5SDimitry Andric   }
33950b57cec5SDimitry Andric #if KMP_USE_FUTEX
33960b57cec5SDimitry Andric   else if ((__kmp_user_lock_kind == lk_futex) &&
33970b57cec5SDimitry Andric            (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
33980b57cec5SDimitry Andric             OMP_NEST_LOCK_T_SIZE)) {
33990b57cec5SDimitry Andric     lck = (kmp_user_lock_p)user_lock;
34000b57cec5SDimitry Andric   }
34010b57cec5SDimitry Andric #endif
34020b57cec5SDimitry Andric   else {
34030b57cec5SDimitry Andric     lck = __kmp_lookup_user_lock(user_lock, "omp_test_nest_lock");
34040b57cec5SDimitry Andric   }
34050b57cec5SDimitry Andric 
34060b57cec5SDimitry Andric #if USE_ITT_BUILD
34070b57cec5SDimitry Andric   __kmp_itt_lock_acquiring(lck);
34080b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
34090b57cec5SDimitry Andric 
34100b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
34110b57cec5SDimitry Andric   // This is the case, if called from omp_init_lock_with_hint:
34120b57cec5SDimitry Andric   void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
34130b57cec5SDimitry Andric   if (!codeptr)
34140b57cec5SDimitry Andric     codeptr = OMPT_GET_RETURN_ADDRESS(0);
34150b57cec5SDimitry Andric   if (ompt_enabled.enabled) &&
34160b57cec5SDimitry Andric         ompt_enabled.ompt_callback_mutex_acquire) {
34170b57cec5SDimitry Andric       ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
341806c3fb27SDimitry Andric           ompt_mutex_test_nest_lock, omp_lock_hint_none,
34190b57cec5SDimitry Andric           __ompt_get_mutex_impl_type(), (ompt_wait_id_t)(uintptr_t)lck,
34200b57cec5SDimitry Andric           codeptr);
34210b57cec5SDimitry Andric     }
34220b57cec5SDimitry Andric #endif
34230b57cec5SDimitry Andric 
34240b57cec5SDimitry Andric   rc = TEST_NESTED_LOCK(lck, gtid);
34250b57cec5SDimitry Andric #if USE_ITT_BUILD
34260b57cec5SDimitry Andric   if (rc) {
34270b57cec5SDimitry Andric     __kmp_itt_lock_acquired(lck);
34280b57cec5SDimitry Andric   } else {
34290b57cec5SDimitry Andric     __kmp_itt_lock_cancelled(lck);
34300b57cec5SDimitry Andric   }
34310b57cec5SDimitry Andric #endif /* USE_ITT_BUILD */
34320b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
34330b57cec5SDimitry Andric   if (ompt_enabled.enabled && rc) {
34340b57cec5SDimitry Andric     if (rc == 1) {
34350b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_mutex_acquired) {
34360b57cec5SDimitry Andric         // lock_first
34370b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
343806c3fb27SDimitry Andric             ompt_mutex_test_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
34390b57cec5SDimitry Andric       }
34400b57cec5SDimitry Andric     } else {
34410b57cec5SDimitry Andric       if (ompt_enabled.ompt_callback_nest_lock) {
34420b57cec5SDimitry Andric         // lock_next
34430b57cec5SDimitry Andric         ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
34440b57cec5SDimitry Andric             ompt_mutex_scope_begin, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
34450b57cec5SDimitry Andric       }
34460b57cec5SDimitry Andric     }
34470b57cec5SDimitry Andric   }
34480b57cec5SDimitry Andric #endif
34490b57cec5SDimitry Andric   return rc;
34500b57cec5SDimitry Andric 
34510b57cec5SDimitry Andric   /* Can't use serial interval since not block structured */
34520b57cec5SDimitry Andric 
34530b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
34540b57cec5SDimitry Andric }
34550b57cec5SDimitry Andric 
34560b57cec5SDimitry Andric // Interface to fast scalable reduce methods routines
34570b57cec5SDimitry Andric 
34580b57cec5SDimitry Andric // keep the selected method in a thread local structure for cross-function
34590b57cec5SDimitry Andric // usage: will be used in __kmpc_end_reduce* functions;
34600b57cec5SDimitry Andric // another solution: to re-determine the method one more time in
34610b57cec5SDimitry Andric // __kmpc_end_reduce* functions (new prototype required then)
34620b57cec5SDimitry Andric // AT: which solution is better?
34630b57cec5SDimitry Andric #define __KMP_SET_REDUCTION_METHOD(gtid, rmethod)                              \
34640b57cec5SDimitry Andric   ((__kmp_threads[(gtid)]->th.th_local.packed_reduction_method) = (rmethod))
34650b57cec5SDimitry Andric 
34660b57cec5SDimitry Andric #define __KMP_GET_REDUCTION_METHOD(gtid)                                       \
34670b57cec5SDimitry Andric   (__kmp_threads[(gtid)]->th.th_local.packed_reduction_method)
34680b57cec5SDimitry Andric 
34690b57cec5SDimitry Andric // description of the packed_reduction_method variable: look at the macros in
34700b57cec5SDimitry Andric // kmp.h
34710b57cec5SDimitry Andric 
34720b57cec5SDimitry Andric // used in a critical section reduce block
34730b57cec5SDimitry Andric static __forceinline void
34740b57cec5SDimitry Andric __kmp_enter_critical_section_reduce_block(ident_t *loc, kmp_int32 global_tid,
34750b57cec5SDimitry Andric                                           kmp_critical_name *crit) {
34760b57cec5SDimitry Andric 
34770b57cec5SDimitry Andric   // this lock was visible to a customer and to the threading profile tool as a
34780b57cec5SDimitry Andric   // serial overhead span (although it's used for an internal purpose only)
34790b57cec5SDimitry Andric   //            why was it visible in previous implementation?
34800b57cec5SDimitry Andric   //            should we keep it visible in new reduce block?
34810b57cec5SDimitry Andric   kmp_user_lock_p lck;
34820b57cec5SDimitry Andric 
34830b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
34840b57cec5SDimitry Andric 
34850b57cec5SDimitry Andric   kmp_dyna_lock_t *lk = (kmp_dyna_lock_t *)crit;
34860b57cec5SDimitry Andric   // Check if it is initialized.
34870b57cec5SDimitry Andric   if (*lk == 0) {
34880b57cec5SDimitry Andric     if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
34890b57cec5SDimitry Andric       KMP_COMPARE_AND_STORE_ACQ32((volatile kmp_int32 *)crit, 0,
34900b57cec5SDimitry Andric                                   KMP_GET_D_TAG(__kmp_user_lock_seq));
34910b57cec5SDimitry Andric     } else {
34920b57cec5SDimitry Andric       __kmp_init_indirect_csptr(crit, loc, global_tid,
34930b57cec5SDimitry Andric                                 KMP_GET_I_TAG(__kmp_user_lock_seq));
34940b57cec5SDimitry Andric     }
34950b57cec5SDimitry Andric   }
34960b57cec5SDimitry Andric   // Branch for accessing the actual lock object and set operation. This
34970b57cec5SDimitry Andric   // branching is inevitable since this lock initialization does not follow the
34980b57cec5SDimitry Andric   // normal dispatch path (lock table is not used).
34990b57cec5SDimitry Andric   if (KMP_EXTRACT_D_TAG(lk) != 0) {
35000b57cec5SDimitry Andric     lck = (kmp_user_lock_p)lk;
35010b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(lck != NULL);
35020b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
35030b57cec5SDimitry Andric       __kmp_push_sync(global_tid, ct_critical, loc, lck, __kmp_user_lock_seq);
35040b57cec5SDimitry Andric     }
35050b57cec5SDimitry Andric     KMP_D_LOCK_FUNC(lk, set)(lk, global_tid);
35060b57cec5SDimitry Andric   } else {
35070b57cec5SDimitry Andric     kmp_indirect_lock_t *ilk = *((kmp_indirect_lock_t **)lk);
35080b57cec5SDimitry Andric     lck = ilk->lock;
35090b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(lck != NULL);
35100b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
35110b57cec5SDimitry Andric       __kmp_push_sync(global_tid, ct_critical, loc, lck, __kmp_user_lock_seq);
35120b57cec5SDimitry Andric     }
35130b57cec5SDimitry Andric     KMP_I_LOCK_FUNC(ilk, set)(lck, global_tid);
35140b57cec5SDimitry Andric   }
35150b57cec5SDimitry Andric 
35160b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
35170b57cec5SDimitry Andric 
35180b57cec5SDimitry Andric   // We know that the fast reduction code is only emitted by Intel compilers
35190b57cec5SDimitry Andric   // with 32 byte critical sections. If there isn't enough space, then we
35200b57cec5SDimitry Andric   // have to use a pointer.
35210b57cec5SDimitry Andric   if (__kmp_base_user_lock_size <= INTEL_CRITICAL_SIZE) {
35220b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
35230b57cec5SDimitry Andric   } else {
35240b57cec5SDimitry Andric     lck = __kmp_get_critical_section_ptr(crit, loc, global_tid);
35250b57cec5SDimitry Andric   }
35260b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(lck != NULL);
35270b57cec5SDimitry Andric 
35280b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
35290b57cec5SDimitry Andric     __kmp_push_sync(global_tid, ct_critical, loc, lck);
35300b57cec5SDimitry Andric 
35310b57cec5SDimitry Andric   __kmp_acquire_user_lock_with_checks(lck, global_tid);
35320b57cec5SDimitry Andric 
35330b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
35340b57cec5SDimitry Andric }
35350b57cec5SDimitry Andric 
35360b57cec5SDimitry Andric // used in a critical section reduce block
35370b57cec5SDimitry Andric static __forceinline void
35380b57cec5SDimitry Andric __kmp_end_critical_section_reduce_block(ident_t *loc, kmp_int32 global_tid,
35390b57cec5SDimitry Andric                                         kmp_critical_name *crit) {
35400b57cec5SDimitry Andric 
35410b57cec5SDimitry Andric   kmp_user_lock_p lck;
35420b57cec5SDimitry Andric 
35430b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
35440b57cec5SDimitry Andric 
35450b57cec5SDimitry Andric   if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
35460b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
35470b57cec5SDimitry Andric     if (__kmp_env_consistency_check)
35480b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_critical, loc);
35490b57cec5SDimitry Andric     KMP_D_LOCK_FUNC(lck, unset)((kmp_dyna_lock_t *)lck, global_tid);
35500b57cec5SDimitry Andric   } else {
35510b57cec5SDimitry Andric     kmp_indirect_lock_t *ilk =
35520b57cec5SDimitry Andric         (kmp_indirect_lock_t *)TCR_PTR(*((kmp_indirect_lock_t **)crit));
35530b57cec5SDimitry Andric     if (__kmp_env_consistency_check)
35540b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_critical, loc);
35550b57cec5SDimitry Andric     KMP_I_LOCK_FUNC(ilk, unset)(ilk->lock, global_tid);
35560b57cec5SDimitry Andric   }
35570b57cec5SDimitry Andric 
35580b57cec5SDimitry Andric #else // KMP_USE_DYNAMIC_LOCK
35590b57cec5SDimitry Andric 
35600b57cec5SDimitry Andric   // We know that the fast reduction code is only emitted by Intel compilers
35610b57cec5SDimitry Andric   // with 32 byte critical sections. If there isn't enough space, then we have
35620b57cec5SDimitry Andric   // to use a pointer.
35630b57cec5SDimitry Andric   if (__kmp_base_user_lock_size > 32) {
35640b57cec5SDimitry Andric     lck = *((kmp_user_lock_p *)crit);
35650b57cec5SDimitry Andric     KMP_ASSERT(lck != NULL);
35660b57cec5SDimitry Andric   } else {
35670b57cec5SDimitry Andric     lck = (kmp_user_lock_p)crit;
35680b57cec5SDimitry Andric   }
35690b57cec5SDimitry Andric 
35700b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
35710b57cec5SDimitry Andric     __kmp_pop_sync(global_tid, ct_critical, loc);
35720b57cec5SDimitry Andric 
35730b57cec5SDimitry Andric   __kmp_release_user_lock_with_checks(lck, global_tid);
35740b57cec5SDimitry Andric 
35750b57cec5SDimitry Andric #endif // KMP_USE_DYNAMIC_LOCK
35760b57cec5SDimitry Andric } // __kmp_end_critical_section_reduce_block
35770b57cec5SDimitry Andric 
35780b57cec5SDimitry Andric static __forceinline int
35790b57cec5SDimitry Andric __kmp_swap_teams_for_teams_reduction(kmp_info_t *th, kmp_team_t **team_p,
35800b57cec5SDimitry Andric                                      int *task_state) {
35810b57cec5SDimitry Andric   kmp_team_t *team;
35820b57cec5SDimitry Andric 
35830b57cec5SDimitry Andric   // Check if we are inside the teams construct?
35840b57cec5SDimitry Andric   if (th->th.th_teams_microtask) {
35850b57cec5SDimitry Andric     *team_p = team = th->th.th_team;
35860b57cec5SDimitry Andric     if (team->t.t_level == th->th.th_teams_level) {
35870b57cec5SDimitry Andric       // This is reduction at teams construct.
35880b57cec5SDimitry Andric       KMP_DEBUG_ASSERT(!th->th.th_info.ds.ds_tid); // AC: check that tid == 0
35890b57cec5SDimitry Andric       // Let's swap teams temporarily for the reduction.
35900b57cec5SDimitry Andric       th->th.th_info.ds.ds_tid = team->t.t_master_tid;
35910b57cec5SDimitry Andric       th->th.th_team = team->t.t_parent;
35920b57cec5SDimitry Andric       th->th.th_team_nproc = th->th.th_team->t.t_nproc;
35930b57cec5SDimitry Andric       th->th.th_task_team = th->th.th_team->t.t_task_team[0];
35940b57cec5SDimitry Andric       *task_state = th->th.th_task_state;
35950b57cec5SDimitry Andric       th->th.th_task_state = 0;
35960b57cec5SDimitry Andric 
35970b57cec5SDimitry Andric       return 1;
35980b57cec5SDimitry Andric     }
35990b57cec5SDimitry Andric   }
36000b57cec5SDimitry Andric   return 0;
36010b57cec5SDimitry Andric }
36020b57cec5SDimitry Andric 
36030b57cec5SDimitry Andric static __forceinline void
36040b57cec5SDimitry Andric __kmp_restore_swapped_teams(kmp_info_t *th, kmp_team_t *team, int task_state) {
36050b57cec5SDimitry Andric   // Restore thread structure swapped in __kmp_swap_teams_for_teams_reduction.
36060b57cec5SDimitry Andric   th->th.th_info.ds.ds_tid = 0;
36070b57cec5SDimitry Andric   th->th.th_team = team;
36080b57cec5SDimitry Andric   th->th.th_team_nproc = team->t.t_nproc;
36090b57cec5SDimitry Andric   th->th.th_task_team = team->t.t_task_team[task_state];
3610e8d8bef9SDimitry Andric   __kmp_type_convert(task_state, &(th->th.th_task_state));
36110b57cec5SDimitry Andric }
36120b57cec5SDimitry Andric 
36130b57cec5SDimitry Andric /* 2.a.i. Reduce Block without a terminating barrier */
36140b57cec5SDimitry Andric /*!
36150b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
36160b57cec5SDimitry Andric @param loc source location information
36170b57cec5SDimitry Andric @param global_tid global thread number
36180b57cec5SDimitry Andric @param num_vars number of items (variables) to be reduced
36190b57cec5SDimitry Andric @param reduce_size size of data in bytes to be reduced
36200b57cec5SDimitry Andric @param reduce_data pointer to data to be reduced
36210b57cec5SDimitry Andric @param reduce_func callback function providing reduction operation on two
36220b57cec5SDimitry Andric operands and returning result of reduction in lhs_data
36230b57cec5SDimitry Andric @param lck pointer to the unique lock data structure
3624fe6060f1SDimitry Andric @result 1 for the primary thread, 0 for all other team threads, 2 for all team
36250b57cec5SDimitry Andric threads if atomic reduction needed
36260b57cec5SDimitry Andric 
36270b57cec5SDimitry Andric The nowait version is used for a reduce clause with the nowait argument.
36280b57cec5SDimitry Andric */
36290b57cec5SDimitry Andric kmp_int32
36300b57cec5SDimitry Andric __kmpc_reduce_nowait(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars,
36310b57cec5SDimitry Andric                      size_t reduce_size, void *reduce_data,
36320b57cec5SDimitry Andric                      void (*reduce_func)(void *lhs_data, void *rhs_data),
36330b57cec5SDimitry Andric                      kmp_critical_name *lck) {
36340b57cec5SDimitry Andric 
36350b57cec5SDimitry Andric   KMP_COUNT_BLOCK(REDUCE_nowait);
36360b57cec5SDimitry Andric   int retval = 0;
36370b57cec5SDimitry Andric   PACKED_REDUCTION_METHOD_T packed_reduction_method;
36380b57cec5SDimitry Andric   kmp_info_t *th;
36390b57cec5SDimitry Andric   kmp_team_t *team;
36400b57cec5SDimitry Andric   int teams_swapped = 0, task_state;
36410b57cec5SDimitry Andric   KA_TRACE(10, ("__kmpc_reduce_nowait() enter: called T#%d\n", global_tid));
3642e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
36430b57cec5SDimitry Andric 
36440b57cec5SDimitry Andric   // why do we need this initialization here at all?
36450b57cec5SDimitry Andric   // Reduction clause can not be used as a stand-alone directive.
36460b57cec5SDimitry Andric 
36470b57cec5SDimitry Andric   // do not call __kmp_serial_initialize(), it will be called by
36480b57cec5SDimitry Andric   // __kmp_parallel_initialize() if needed
36490b57cec5SDimitry Andric   // possible detection of false-positive race by the threadchecker ???
36500b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
36510b57cec5SDimitry Andric     __kmp_parallel_initialize();
36520b57cec5SDimitry Andric 
36530b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
36540b57cec5SDimitry Andric 
36550b57cec5SDimitry Andric // check correctness of reduce block nesting
36560b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
36570b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
36580b57cec5SDimitry Andric     __kmp_push_sync(global_tid, ct_reduce, loc, NULL, 0);
36590b57cec5SDimitry Andric #else
36600b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
36610b57cec5SDimitry Andric     __kmp_push_sync(global_tid, ct_reduce, loc, NULL);
36620b57cec5SDimitry Andric #endif
36630b57cec5SDimitry Andric 
36640b57cec5SDimitry Andric   th = __kmp_thread_from_gtid(global_tid);
36650b57cec5SDimitry Andric   teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
36660b57cec5SDimitry Andric 
36670b57cec5SDimitry Andric   // packed_reduction_method value will be reused by __kmp_end_reduce* function,
36680b57cec5SDimitry Andric   // the value should be kept in a variable
36690b57cec5SDimitry Andric   // the variable should be either a construct-specific or thread-specific
36700b57cec5SDimitry Andric   // property, not a team specific property
36710b57cec5SDimitry Andric   //     (a thread can reach the next reduce block on the next construct, reduce
36720b57cec5SDimitry Andric   //     method may differ on the next construct)
36730b57cec5SDimitry Andric   // an ident_t "loc" parameter could be used as a construct-specific property
36740b57cec5SDimitry Andric   // (what if loc == 0?)
36750b57cec5SDimitry Andric   //     (if both construct-specific and team-specific variables were shared,
36760b57cec5SDimitry Andric   //     then unness extra syncs should be needed)
36770b57cec5SDimitry Andric   // a thread-specific variable is better regarding two issues above (next
36780b57cec5SDimitry Andric   // construct and extra syncs)
36790b57cec5SDimitry Andric   // a thread-specific "th_local.reduction_method" variable is used currently
36800b57cec5SDimitry Andric   // each thread executes 'determine' and 'set' lines (no need to execute by one
36810b57cec5SDimitry Andric   // thread, to avoid unness extra syncs)
36820b57cec5SDimitry Andric 
36830b57cec5SDimitry Andric   packed_reduction_method = __kmp_determine_reduction_method(
36840b57cec5SDimitry Andric       loc, global_tid, num_vars, reduce_size, reduce_data, reduce_func, lck);
36850b57cec5SDimitry Andric   __KMP_SET_REDUCTION_METHOD(global_tid, packed_reduction_method);
36860b57cec5SDimitry Andric 
3687480093f4SDimitry Andric   OMPT_REDUCTION_DECL(th, global_tid);
36880b57cec5SDimitry Andric   if (packed_reduction_method == critical_reduce_block) {
36890b57cec5SDimitry Andric 
3690480093f4SDimitry Andric     OMPT_REDUCTION_BEGIN;
3691480093f4SDimitry Andric 
36920b57cec5SDimitry Andric     __kmp_enter_critical_section_reduce_block(loc, global_tid, lck);
36930b57cec5SDimitry Andric     retval = 1;
36940b57cec5SDimitry Andric 
36950b57cec5SDimitry Andric   } else if (packed_reduction_method == empty_reduce_block) {
36960b57cec5SDimitry Andric 
3697480093f4SDimitry Andric     OMPT_REDUCTION_BEGIN;
3698480093f4SDimitry Andric 
36990b57cec5SDimitry Andric     // usage: if team size == 1, no synchronization is required ( Intel
37000b57cec5SDimitry Andric     // platforms only )
37010b57cec5SDimitry Andric     retval = 1;
37020b57cec5SDimitry Andric 
37030b57cec5SDimitry Andric   } else if (packed_reduction_method == atomic_reduce_block) {
37040b57cec5SDimitry Andric 
37050b57cec5SDimitry Andric     retval = 2;
37060b57cec5SDimitry Andric 
37070b57cec5SDimitry Andric     // all threads should do this pop here (because __kmpc_end_reduce_nowait()
37080b57cec5SDimitry Andric     // won't be called by the code gen)
37090b57cec5SDimitry Andric     //     (it's not quite good, because the checking block has been closed by
37100b57cec5SDimitry Andric     //     this 'pop',
37110b57cec5SDimitry Andric     //      but atomic operation has not been executed yet, will be executed
37120b57cec5SDimitry Andric     //      slightly later, literally on next instruction)
37130b57cec5SDimitry Andric     if (__kmp_env_consistency_check)
37140b57cec5SDimitry Andric       __kmp_pop_sync(global_tid, ct_reduce, loc);
37150b57cec5SDimitry Andric 
37160b57cec5SDimitry Andric   } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
37170b57cec5SDimitry Andric                                    tree_reduce_block)) {
37180b57cec5SDimitry Andric 
37190b57cec5SDimitry Andric // AT: performance issue: a real barrier here
3720fe6060f1SDimitry Andric // AT: (if primary thread is slow, other threads are blocked here waiting for
3721fe6060f1SDimitry Andric //      the primary thread to come and release them)
37220b57cec5SDimitry Andric // AT: (it's not what a customer might expect specifying NOWAIT clause)
37230b57cec5SDimitry Andric // AT: (specifying NOWAIT won't result in improvement of performance, it'll
37240b57cec5SDimitry Andric //      be confusing to a customer)
37250b57cec5SDimitry Andric // AT: another implementation of *barrier_gather*nowait() (or some other design)
37260b57cec5SDimitry Andric // might go faster and be more in line with sense of NOWAIT
37270b57cec5SDimitry Andric // AT: TO DO: do epcc test and compare times
37280b57cec5SDimitry Andric 
37290b57cec5SDimitry Andric // this barrier should be invisible to a customer and to the threading profile
37300b57cec5SDimitry Andric // tool (it's neither a terminating barrier nor customer's code, it's
37310b57cec5SDimitry Andric // used for an internal purpose)
37320b57cec5SDimitry Andric #if OMPT_SUPPORT
37330b57cec5SDimitry Andric     // JP: can this barrier potentially leed to task scheduling?
37340b57cec5SDimitry Andric     // JP: as long as there is a barrier in the implementation, OMPT should and
37350b57cec5SDimitry Andric     // will provide the barrier events
37360b57cec5SDimitry Andric     //         so we set-up the necessary frame/return addresses.
37370b57cec5SDimitry Andric     ompt_frame_t *ompt_frame;
37380b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
37390b57cec5SDimitry Andric       __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
37400b57cec5SDimitry Andric       if (ompt_frame->enter_frame.ptr == NULL)
37410b57cec5SDimitry Andric         ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
37420b57cec5SDimitry Andric     }
3743e8d8bef9SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(global_tid);
37440b57cec5SDimitry Andric #endif
37450b57cec5SDimitry Andric #if USE_ITT_NOTIFY
37460b57cec5SDimitry Andric     __kmp_threads[global_tid]->th.th_ident = loc;
37470b57cec5SDimitry Andric #endif
37480b57cec5SDimitry Andric     retval =
37490b57cec5SDimitry Andric         __kmp_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
37500b57cec5SDimitry Andric                       global_tid, FALSE, reduce_size, reduce_data, reduce_func);
37510b57cec5SDimitry Andric     retval = (retval != 0) ? (0) : (1);
37520b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
37530b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
37540b57cec5SDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
37550b57cec5SDimitry Andric     }
37560b57cec5SDimitry Andric #endif
37570b57cec5SDimitry Andric 
3758fe6060f1SDimitry Andric     // all other workers except primary thread should do this pop here
37590b57cec5SDimitry Andric     //     ( none of other workers will get to __kmpc_end_reduce_nowait() )
37600b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
37610b57cec5SDimitry Andric       if (retval == 0) {
37620b57cec5SDimitry Andric         __kmp_pop_sync(global_tid, ct_reduce, loc);
37630b57cec5SDimitry Andric       }
37640b57cec5SDimitry Andric     }
37650b57cec5SDimitry Andric 
37660b57cec5SDimitry Andric   } else {
37670b57cec5SDimitry Andric 
37680b57cec5SDimitry Andric     // should never reach this block
37690b57cec5SDimitry Andric     KMP_ASSERT(0); // "unexpected method"
37700b57cec5SDimitry Andric   }
37710b57cec5SDimitry Andric   if (teams_swapped) {
37720b57cec5SDimitry Andric     __kmp_restore_swapped_teams(th, team, task_state);
37730b57cec5SDimitry Andric   }
37740b57cec5SDimitry Andric   KA_TRACE(
37750b57cec5SDimitry Andric       10,
37760b57cec5SDimitry Andric       ("__kmpc_reduce_nowait() exit: called T#%d: method %08x, returns %08x\n",
37770b57cec5SDimitry Andric        global_tid, packed_reduction_method, retval));
37780b57cec5SDimitry Andric 
37790b57cec5SDimitry Andric   return retval;
37800b57cec5SDimitry Andric }
37810b57cec5SDimitry Andric 
37820b57cec5SDimitry Andric /*!
37830b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
37840b57cec5SDimitry Andric @param loc source location information
37850b57cec5SDimitry Andric @param global_tid global thread id.
37860b57cec5SDimitry Andric @param lck pointer to the unique lock data structure
37870b57cec5SDimitry Andric 
37880b57cec5SDimitry Andric Finish the execution of a reduce nowait.
37890b57cec5SDimitry Andric */
37900b57cec5SDimitry Andric void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
37910b57cec5SDimitry Andric                               kmp_critical_name *lck) {
37920b57cec5SDimitry Andric 
37930b57cec5SDimitry Andric   PACKED_REDUCTION_METHOD_T packed_reduction_method;
37940b57cec5SDimitry Andric 
37950b57cec5SDimitry Andric   KA_TRACE(10, ("__kmpc_end_reduce_nowait() enter: called T#%d\n", global_tid));
3796e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
37970b57cec5SDimitry Andric 
37980b57cec5SDimitry Andric   packed_reduction_method = __KMP_GET_REDUCTION_METHOD(global_tid);
37990b57cec5SDimitry Andric 
3800480093f4SDimitry Andric   OMPT_REDUCTION_DECL(__kmp_thread_from_gtid(global_tid), global_tid);
3801480093f4SDimitry Andric 
38020b57cec5SDimitry Andric   if (packed_reduction_method == critical_reduce_block) {
38030b57cec5SDimitry Andric 
38040b57cec5SDimitry Andric     __kmp_end_critical_section_reduce_block(loc, global_tid, lck);
3805480093f4SDimitry Andric     OMPT_REDUCTION_END;
38060b57cec5SDimitry Andric 
38070b57cec5SDimitry Andric   } else if (packed_reduction_method == empty_reduce_block) {
38080b57cec5SDimitry Andric 
38090b57cec5SDimitry Andric     // usage: if team size == 1, no synchronization is required ( on Intel
38100b57cec5SDimitry Andric     // platforms only )
38110b57cec5SDimitry Andric 
3812480093f4SDimitry Andric     OMPT_REDUCTION_END;
3813480093f4SDimitry Andric 
38140b57cec5SDimitry Andric   } else if (packed_reduction_method == atomic_reduce_block) {
38150b57cec5SDimitry Andric 
3816fe6060f1SDimitry Andric     // neither primary thread nor other workers should get here
38170b57cec5SDimitry Andric     //     (code gen does not generate this call in case 2: atomic reduce block)
38180b57cec5SDimitry Andric     // actually it's better to remove this elseif at all;
38190b57cec5SDimitry Andric     // after removal this value will checked by the 'else' and will assert
38200b57cec5SDimitry Andric 
38210b57cec5SDimitry Andric   } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
38220b57cec5SDimitry Andric                                    tree_reduce_block)) {
38230b57cec5SDimitry Andric 
3824fe6060f1SDimitry Andric     // only primary thread gets here
3825480093f4SDimitry Andric     // OMPT: tree reduction is annotated in the barrier code
38260b57cec5SDimitry Andric 
38270b57cec5SDimitry Andric   } else {
38280b57cec5SDimitry Andric 
38290b57cec5SDimitry Andric     // should never reach this block
38300b57cec5SDimitry Andric     KMP_ASSERT(0); // "unexpected method"
38310b57cec5SDimitry Andric   }
38320b57cec5SDimitry Andric 
38330b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
38340b57cec5SDimitry Andric     __kmp_pop_sync(global_tid, ct_reduce, loc);
38350b57cec5SDimitry Andric 
38360b57cec5SDimitry Andric   KA_TRACE(10, ("__kmpc_end_reduce_nowait() exit: called T#%d: method %08x\n",
38370b57cec5SDimitry Andric                 global_tid, packed_reduction_method));
38380b57cec5SDimitry Andric 
38390b57cec5SDimitry Andric   return;
38400b57cec5SDimitry Andric }
38410b57cec5SDimitry Andric 
38420b57cec5SDimitry Andric /* 2.a.ii. Reduce Block with a terminating barrier */
38430b57cec5SDimitry Andric 
38440b57cec5SDimitry Andric /*!
38450b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
38460b57cec5SDimitry Andric @param loc source location information
38470b57cec5SDimitry Andric @param global_tid global thread number
38480b57cec5SDimitry Andric @param num_vars number of items (variables) to be reduced
38490b57cec5SDimitry Andric @param reduce_size size of data in bytes to be reduced
38500b57cec5SDimitry Andric @param reduce_data pointer to data to be reduced
38510b57cec5SDimitry Andric @param reduce_func callback function providing reduction operation on two
38520b57cec5SDimitry Andric operands and returning result of reduction in lhs_data
38530b57cec5SDimitry Andric @param lck pointer to the unique lock data structure
3854fe6060f1SDimitry Andric @result 1 for the primary thread, 0 for all other team threads, 2 for all team
38550b57cec5SDimitry Andric threads if atomic reduction needed
38560b57cec5SDimitry Andric 
38570b57cec5SDimitry Andric A blocking reduce that includes an implicit barrier.
38580b57cec5SDimitry Andric */
38590b57cec5SDimitry Andric kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars,
38600b57cec5SDimitry Andric                         size_t reduce_size, void *reduce_data,
38610b57cec5SDimitry Andric                         void (*reduce_func)(void *lhs_data, void *rhs_data),
38620b57cec5SDimitry Andric                         kmp_critical_name *lck) {
38630b57cec5SDimitry Andric   KMP_COUNT_BLOCK(REDUCE_wait);
38640b57cec5SDimitry Andric   int retval = 0;
38650b57cec5SDimitry Andric   PACKED_REDUCTION_METHOD_T packed_reduction_method;
38660b57cec5SDimitry Andric   kmp_info_t *th;
38670b57cec5SDimitry Andric   kmp_team_t *team;
38680b57cec5SDimitry Andric   int teams_swapped = 0, task_state;
38690b57cec5SDimitry Andric 
38700b57cec5SDimitry Andric   KA_TRACE(10, ("__kmpc_reduce() enter: called T#%d\n", global_tid));
3871e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
38720b57cec5SDimitry Andric 
38730b57cec5SDimitry Andric   // why do we need this initialization here at all?
38740b57cec5SDimitry Andric   // Reduction clause can not be a stand-alone directive.
38750b57cec5SDimitry Andric 
38760b57cec5SDimitry Andric   // do not call __kmp_serial_initialize(), it will be called by
38770b57cec5SDimitry Andric   // __kmp_parallel_initialize() if needed
38780b57cec5SDimitry Andric   // possible detection of false-positive race by the threadchecker ???
38790b57cec5SDimitry Andric   if (!TCR_4(__kmp_init_parallel))
38800b57cec5SDimitry Andric     __kmp_parallel_initialize();
38810b57cec5SDimitry Andric 
38820b57cec5SDimitry Andric   __kmp_resume_if_soft_paused();
38830b57cec5SDimitry Andric 
38840b57cec5SDimitry Andric // check correctness of reduce block nesting
38850b57cec5SDimitry Andric #if KMP_USE_DYNAMIC_LOCK
38860b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
38870b57cec5SDimitry Andric     __kmp_push_sync(global_tid, ct_reduce, loc, NULL, 0);
38880b57cec5SDimitry Andric #else
38890b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
38900b57cec5SDimitry Andric     __kmp_push_sync(global_tid, ct_reduce, loc, NULL);
38910b57cec5SDimitry Andric #endif
38920b57cec5SDimitry Andric 
38930b57cec5SDimitry Andric   th = __kmp_thread_from_gtid(global_tid);
38940b57cec5SDimitry Andric   teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
38950b57cec5SDimitry Andric 
38960b57cec5SDimitry Andric   packed_reduction_method = __kmp_determine_reduction_method(
38970b57cec5SDimitry Andric       loc, global_tid, num_vars, reduce_size, reduce_data, reduce_func, lck);
38980b57cec5SDimitry Andric   __KMP_SET_REDUCTION_METHOD(global_tid, packed_reduction_method);
38990b57cec5SDimitry Andric 
3900480093f4SDimitry Andric   OMPT_REDUCTION_DECL(th, global_tid);
3901480093f4SDimitry Andric 
39020b57cec5SDimitry Andric   if (packed_reduction_method == critical_reduce_block) {
39030b57cec5SDimitry Andric 
3904480093f4SDimitry Andric     OMPT_REDUCTION_BEGIN;
39050b57cec5SDimitry Andric     __kmp_enter_critical_section_reduce_block(loc, global_tid, lck);
39060b57cec5SDimitry Andric     retval = 1;
39070b57cec5SDimitry Andric 
39080b57cec5SDimitry Andric   } else if (packed_reduction_method == empty_reduce_block) {
39090b57cec5SDimitry Andric 
3910480093f4SDimitry Andric     OMPT_REDUCTION_BEGIN;
39110b57cec5SDimitry Andric     // usage: if team size == 1, no synchronization is required ( Intel
39120b57cec5SDimitry Andric     // platforms only )
39130b57cec5SDimitry Andric     retval = 1;
39140b57cec5SDimitry Andric 
39150b57cec5SDimitry Andric   } else if (packed_reduction_method == atomic_reduce_block) {
39160b57cec5SDimitry Andric 
39170b57cec5SDimitry Andric     retval = 2;
39180b57cec5SDimitry Andric 
39190b57cec5SDimitry Andric   } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
39200b57cec5SDimitry Andric                                    tree_reduce_block)) {
39210b57cec5SDimitry Andric 
39220b57cec5SDimitry Andric // case tree_reduce_block:
39230b57cec5SDimitry Andric // this barrier should be visible to a customer and to the threading profile
39240b57cec5SDimitry Andric // tool (it's a terminating barrier on constructs if NOWAIT not specified)
39250b57cec5SDimitry Andric #if OMPT_SUPPORT
39260b57cec5SDimitry Andric     ompt_frame_t *ompt_frame;
39270b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
39280b57cec5SDimitry Andric       __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
39290b57cec5SDimitry Andric       if (ompt_frame->enter_frame.ptr == NULL)
39300b57cec5SDimitry Andric         ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
39310b57cec5SDimitry Andric     }
3932e8d8bef9SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(global_tid);
39330b57cec5SDimitry Andric #endif
39340b57cec5SDimitry Andric #if USE_ITT_NOTIFY
39350b57cec5SDimitry Andric     __kmp_threads[global_tid]->th.th_ident =
39360b57cec5SDimitry Andric         loc; // needed for correct notification of frames
39370b57cec5SDimitry Andric #endif
39380b57cec5SDimitry Andric     retval =
39390b57cec5SDimitry Andric         __kmp_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
39400b57cec5SDimitry Andric                       global_tid, TRUE, reduce_size, reduce_data, reduce_func);
39410b57cec5SDimitry Andric     retval = (retval != 0) ? (0) : (1);
39420b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
39430b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
39440b57cec5SDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
39450b57cec5SDimitry Andric     }
39460b57cec5SDimitry Andric #endif
39470b57cec5SDimitry Andric 
3948fe6060f1SDimitry Andric     // all other workers except primary thread should do this pop here
3949fe6060f1SDimitry Andric     // (none of other workers except primary will enter __kmpc_end_reduce())
39500b57cec5SDimitry Andric     if (__kmp_env_consistency_check) {
3951fe6060f1SDimitry Andric       if (retval == 0) { // 0: all other workers; 1: primary thread
39520b57cec5SDimitry Andric         __kmp_pop_sync(global_tid, ct_reduce, loc);
39530b57cec5SDimitry Andric       }
39540b57cec5SDimitry Andric     }
39550b57cec5SDimitry Andric 
39560b57cec5SDimitry Andric   } else {
39570b57cec5SDimitry Andric 
39580b57cec5SDimitry Andric     // should never reach this block
39590b57cec5SDimitry Andric     KMP_ASSERT(0); // "unexpected method"
39600b57cec5SDimitry Andric   }
39610b57cec5SDimitry Andric   if (teams_swapped) {
39620b57cec5SDimitry Andric     __kmp_restore_swapped_teams(th, team, task_state);
39630b57cec5SDimitry Andric   }
39640b57cec5SDimitry Andric 
39650b57cec5SDimitry Andric   KA_TRACE(10,
39660b57cec5SDimitry Andric            ("__kmpc_reduce() exit: called T#%d: method %08x, returns %08x\n",
39670b57cec5SDimitry Andric             global_tid, packed_reduction_method, retval));
39680b57cec5SDimitry Andric   return retval;
39690b57cec5SDimitry Andric }
39700b57cec5SDimitry Andric 
39710b57cec5SDimitry Andric /*!
39720b57cec5SDimitry Andric @ingroup SYNCHRONIZATION
39730b57cec5SDimitry Andric @param loc source location information
39740b57cec5SDimitry Andric @param global_tid global thread id.
39750b57cec5SDimitry Andric @param lck pointer to the unique lock data structure
39760b57cec5SDimitry Andric 
39770b57cec5SDimitry Andric Finish the execution of a blocking reduce.
39780b57cec5SDimitry Andric The <tt>lck</tt> pointer must be the same as that used in the corresponding
39790b57cec5SDimitry Andric start function.
39800b57cec5SDimitry Andric */
39810b57cec5SDimitry Andric void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid,
39820b57cec5SDimitry Andric                        kmp_critical_name *lck) {
39830b57cec5SDimitry Andric 
39840b57cec5SDimitry Andric   PACKED_REDUCTION_METHOD_T packed_reduction_method;
39850b57cec5SDimitry Andric   kmp_info_t *th;
39860b57cec5SDimitry Andric   kmp_team_t *team;
39870b57cec5SDimitry Andric   int teams_swapped = 0, task_state;
39880b57cec5SDimitry Andric 
39890b57cec5SDimitry Andric   KA_TRACE(10, ("__kmpc_end_reduce() enter: called T#%d\n", global_tid));
3990e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(global_tid);
39910b57cec5SDimitry Andric 
39920b57cec5SDimitry Andric   th = __kmp_thread_from_gtid(global_tid);
39930b57cec5SDimitry Andric   teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
39940b57cec5SDimitry Andric 
39950b57cec5SDimitry Andric   packed_reduction_method = __KMP_GET_REDUCTION_METHOD(global_tid);
39960b57cec5SDimitry Andric 
39970b57cec5SDimitry Andric   // this barrier should be visible to a customer and to the threading profile
39980b57cec5SDimitry Andric   // tool (it's a terminating barrier on constructs if NOWAIT not specified)
3999480093f4SDimitry Andric   OMPT_REDUCTION_DECL(th, global_tid);
40000b57cec5SDimitry Andric 
40010b57cec5SDimitry Andric   if (packed_reduction_method == critical_reduce_block) {
40020b57cec5SDimitry Andric     __kmp_end_critical_section_reduce_block(loc, global_tid, lck);
40030b57cec5SDimitry Andric 
4004480093f4SDimitry Andric     OMPT_REDUCTION_END;
4005480093f4SDimitry Andric 
40060b57cec5SDimitry Andric // TODO: implicit barrier: should be exposed
40070b57cec5SDimitry Andric #if OMPT_SUPPORT
40080b57cec5SDimitry Andric     ompt_frame_t *ompt_frame;
40090b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
40100b57cec5SDimitry Andric       __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
40110b57cec5SDimitry Andric       if (ompt_frame->enter_frame.ptr == NULL)
40120b57cec5SDimitry Andric         ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
40130b57cec5SDimitry Andric     }
4014e8d8bef9SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(global_tid);
40150b57cec5SDimitry Andric #endif
40160b57cec5SDimitry Andric #if USE_ITT_NOTIFY
40170b57cec5SDimitry Andric     __kmp_threads[global_tid]->th.th_ident = loc;
40180b57cec5SDimitry Andric #endif
40190b57cec5SDimitry Andric     __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
40200b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
40210b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
40220b57cec5SDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
40230b57cec5SDimitry Andric     }
40240b57cec5SDimitry Andric #endif
40250b57cec5SDimitry Andric 
40260b57cec5SDimitry Andric   } else if (packed_reduction_method == empty_reduce_block) {
40270b57cec5SDimitry Andric 
4028480093f4SDimitry Andric     OMPT_REDUCTION_END;
4029480093f4SDimitry Andric 
40300b57cec5SDimitry Andric // usage: if team size==1, no synchronization is required (Intel platforms only)
40310b57cec5SDimitry Andric 
40320b57cec5SDimitry Andric // TODO: implicit barrier: should be exposed
40330b57cec5SDimitry Andric #if OMPT_SUPPORT
40340b57cec5SDimitry Andric     ompt_frame_t *ompt_frame;
40350b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
40360b57cec5SDimitry Andric       __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
40370b57cec5SDimitry Andric       if (ompt_frame->enter_frame.ptr == NULL)
40380b57cec5SDimitry Andric         ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
40390b57cec5SDimitry Andric     }
4040e8d8bef9SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(global_tid);
40410b57cec5SDimitry Andric #endif
40420b57cec5SDimitry Andric #if USE_ITT_NOTIFY
40430b57cec5SDimitry Andric     __kmp_threads[global_tid]->th.th_ident = loc;
40440b57cec5SDimitry Andric #endif
40450b57cec5SDimitry Andric     __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
40460b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
40470b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
40480b57cec5SDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
40490b57cec5SDimitry Andric     }
40500b57cec5SDimitry Andric #endif
40510b57cec5SDimitry Andric 
40520b57cec5SDimitry Andric   } else if (packed_reduction_method == atomic_reduce_block) {
40530b57cec5SDimitry Andric 
40540b57cec5SDimitry Andric #if OMPT_SUPPORT
40550b57cec5SDimitry Andric     ompt_frame_t *ompt_frame;
40560b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
40570b57cec5SDimitry Andric       __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
40580b57cec5SDimitry Andric       if (ompt_frame->enter_frame.ptr == NULL)
40590b57cec5SDimitry Andric         ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
40600b57cec5SDimitry Andric     }
4061e8d8bef9SDimitry Andric     OMPT_STORE_RETURN_ADDRESS(global_tid);
40620b57cec5SDimitry Andric #endif
40630b57cec5SDimitry Andric // TODO: implicit barrier: should be exposed
40640b57cec5SDimitry Andric #if USE_ITT_NOTIFY
40650b57cec5SDimitry Andric     __kmp_threads[global_tid]->th.th_ident = loc;
40660b57cec5SDimitry Andric #endif
40670b57cec5SDimitry Andric     __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
40680b57cec5SDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
40690b57cec5SDimitry Andric     if (ompt_enabled.enabled) {
40700b57cec5SDimitry Andric       ompt_frame->enter_frame = ompt_data_none;
40710b57cec5SDimitry Andric     }
40720b57cec5SDimitry Andric #endif
40730b57cec5SDimitry Andric 
40740b57cec5SDimitry Andric   } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
40750b57cec5SDimitry Andric                                    tree_reduce_block)) {
40760b57cec5SDimitry Andric 
4077fe6060f1SDimitry Andric     // only primary thread executes here (primary releases all other workers)
40780b57cec5SDimitry Andric     __kmp_end_split_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
40790b57cec5SDimitry Andric                             global_tid);
40800b57cec5SDimitry Andric 
40810b57cec5SDimitry Andric   } else {
40820b57cec5SDimitry Andric 
40830b57cec5SDimitry Andric     // should never reach this block
40840b57cec5SDimitry Andric     KMP_ASSERT(0); // "unexpected method"
40850b57cec5SDimitry Andric   }
40860b57cec5SDimitry Andric   if (teams_swapped) {
40870b57cec5SDimitry Andric     __kmp_restore_swapped_teams(th, team, task_state);
40880b57cec5SDimitry Andric   }
40890b57cec5SDimitry Andric 
40900b57cec5SDimitry Andric   if (__kmp_env_consistency_check)
40910b57cec5SDimitry Andric     __kmp_pop_sync(global_tid, ct_reduce, loc);
40920b57cec5SDimitry Andric 
40930b57cec5SDimitry Andric   KA_TRACE(10, ("__kmpc_end_reduce() exit: called T#%d: method %08x\n",
40940b57cec5SDimitry Andric                 global_tid, packed_reduction_method));
40950b57cec5SDimitry Andric 
40960b57cec5SDimitry Andric   return;
40970b57cec5SDimitry Andric }
40980b57cec5SDimitry Andric 
40990b57cec5SDimitry Andric #undef __KMP_GET_REDUCTION_METHOD
41000b57cec5SDimitry Andric #undef __KMP_SET_REDUCTION_METHOD
41010b57cec5SDimitry Andric 
41020b57cec5SDimitry Andric /* end of interface to fast scalable reduce routines */
41030b57cec5SDimitry Andric 
41040b57cec5SDimitry Andric kmp_uint64 __kmpc_get_taskid() {
41050b57cec5SDimitry Andric 
41060b57cec5SDimitry Andric   kmp_int32 gtid;
41070b57cec5SDimitry Andric   kmp_info_t *thread;
41080b57cec5SDimitry Andric 
41090b57cec5SDimitry Andric   gtid = __kmp_get_gtid();
41100b57cec5SDimitry Andric   if (gtid < 0) {
41110b57cec5SDimitry Andric     return 0;
41120b57cec5SDimitry Andric   }
41130b57cec5SDimitry Andric   thread = __kmp_thread_from_gtid(gtid);
41140b57cec5SDimitry Andric   return thread->th.th_current_task->td_task_id;
41150b57cec5SDimitry Andric 
41160b57cec5SDimitry Andric } // __kmpc_get_taskid
41170b57cec5SDimitry Andric 
41180b57cec5SDimitry Andric kmp_uint64 __kmpc_get_parent_taskid() {
41190b57cec5SDimitry Andric 
41200b57cec5SDimitry Andric   kmp_int32 gtid;
41210b57cec5SDimitry Andric   kmp_info_t *thread;
41220b57cec5SDimitry Andric   kmp_taskdata_t *parent_task;
41230b57cec5SDimitry Andric 
41240b57cec5SDimitry Andric   gtid = __kmp_get_gtid();
41250b57cec5SDimitry Andric   if (gtid < 0) {
41260b57cec5SDimitry Andric     return 0;
41270b57cec5SDimitry Andric   }
41280b57cec5SDimitry Andric   thread = __kmp_thread_from_gtid(gtid);
41290b57cec5SDimitry Andric   parent_task = thread->th.th_current_task->td_parent;
41300b57cec5SDimitry Andric   return (parent_task == NULL ? 0 : parent_task->td_task_id);
41310b57cec5SDimitry Andric 
41320b57cec5SDimitry Andric } // __kmpc_get_parent_taskid
41330b57cec5SDimitry Andric 
41340b57cec5SDimitry Andric /*!
41350b57cec5SDimitry Andric @ingroup WORK_SHARING
41360b57cec5SDimitry Andric @param loc  source location information.
41370b57cec5SDimitry Andric @param gtid  global thread number.
41380b57cec5SDimitry Andric @param num_dims  number of associated doacross loops.
41390b57cec5SDimitry Andric @param dims  info on loops bounds.
41400b57cec5SDimitry Andric 
41410b57cec5SDimitry Andric Initialize doacross loop information.
41420b57cec5SDimitry Andric Expect compiler send us inclusive bounds,
41430b57cec5SDimitry Andric e.g. for(i=2;i<9;i+=2) lo=2, up=8, st=2.
41440b57cec5SDimitry Andric */
41450b57cec5SDimitry Andric void __kmpc_doacross_init(ident_t *loc, int gtid, int num_dims,
41460b57cec5SDimitry Andric                           const struct kmp_dim *dims) {
4147e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
41480b57cec5SDimitry Andric   int j, idx;
41490b57cec5SDimitry Andric   kmp_int64 last, trace_count;
41500b57cec5SDimitry Andric   kmp_info_t *th = __kmp_threads[gtid];
41510b57cec5SDimitry Andric   kmp_team_t *team = th->th.th_team;
41520b57cec5SDimitry Andric   kmp_uint32 *flags;
41530b57cec5SDimitry Andric   kmp_disp_t *pr_buf = th->th.th_dispatch;
41540b57cec5SDimitry Andric   dispatch_shared_info_t *sh_buf;
41550b57cec5SDimitry Andric 
41560b57cec5SDimitry Andric   KA_TRACE(
41570b57cec5SDimitry Andric       20,
41580b57cec5SDimitry Andric       ("__kmpc_doacross_init() enter: called T#%d, num dims %d, active %d\n",
41590b57cec5SDimitry Andric        gtid, num_dims, !team->t.t_serialized));
41600b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(dims != NULL);
41610b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(num_dims > 0);
41620b57cec5SDimitry Andric 
41630b57cec5SDimitry Andric   if (team->t.t_serialized) {
41640b57cec5SDimitry Andric     KA_TRACE(20, ("__kmpc_doacross_init() exit: serialized team\n"));
41650b57cec5SDimitry Andric     return; // no dependencies if team is serialized
41660b57cec5SDimitry Andric   }
41670b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(team->t.t_nproc > 1);
41680b57cec5SDimitry Andric   idx = pr_buf->th_doacross_buf_idx++; // Increment index of shared buffer for
41690b57cec5SDimitry Andric   // the next loop
41700b57cec5SDimitry Andric   sh_buf = &team->t.t_disp_buffer[idx % __kmp_dispatch_num_buffers];
41710b57cec5SDimitry Andric 
41720b57cec5SDimitry Andric   // Save bounds info into allocated private buffer
41730b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(pr_buf->th_doacross_info == NULL);
41740b57cec5SDimitry Andric   pr_buf->th_doacross_info = (kmp_int64 *)__kmp_thread_malloc(
41750b57cec5SDimitry Andric       th, sizeof(kmp_int64) * (4 * num_dims + 1));
41760b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
41770b57cec5SDimitry Andric   pr_buf->th_doacross_info[0] =
41780b57cec5SDimitry Andric       (kmp_int64)num_dims; // first element is number of dimensions
41790b57cec5SDimitry Andric   // Save also address of num_done in order to access it later without knowing
41800b57cec5SDimitry Andric   // the buffer index
41810b57cec5SDimitry Andric   pr_buf->th_doacross_info[1] = (kmp_int64)&sh_buf->doacross_num_done;
41820b57cec5SDimitry Andric   pr_buf->th_doacross_info[2] = dims[0].lo;
41830b57cec5SDimitry Andric   pr_buf->th_doacross_info[3] = dims[0].up;
41840b57cec5SDimitry Andric   pr_buf->th_doacross_info[4] = dims[0].st;
41850b57cec5SDimitry Andric   last = 5;
41860b57cec5SDimitry Andric   for (j = 1; j < num_dims; ++j) {
41870b57cec5SDimitry Andric     kmp_int64
41880b57cec5SDimitry Andric         range_length; // To keep ranges of all dimensions but the first dims[0]
41890b57cec5SDimitry Andric     if (dims[j].st == 1) { // most common case
41900b57cec5SDimitry Andric       // AC: should we care of ranges bigger than LLONG_MAX? (not for now)
41910b57cec5SDimitry Andric       range_length = dims[j].up - dims[j].lo + 1;
41920b57cec5SDimitry Andric     } else {
41930b57cec5SDimitry Andric       if (dims[j].st > 0) {
41940b57cec5SDimitry Andric         KMP_DEBUG_ASSERT(dims[j].up > dims[j].lo);
41950b57cec5SDimitry Andric         range_length = (kmp_uint64)(dims[j].up - dims[j].lo) / dims[j].st + 1;
41960b57cec5SDimitry Andric       } else { // negative increment
41970b57cec5SDimitry Andric         KMP_DEBUG_ASSERT(dims[j].lo > dims[j].up);
41980b57cec5SDimitry Andric         range_length =
41990b57cec5SDimitry Andric             (kmp_uint64)(dims[j].lo - dims[j].up) / (-dims[j].st) + 1;
42000b57cec5SDimitry Andric       }
42010b57cec5SDimitry Andric     }
42020b57cec5SDimitry Andric     pr_buf->th_doacross_info[last++] = range_length;
42030b57cec5SDimitry Andric     pr_buf->th_doacross_info[last++] = dims[j].lo;
42040b57cec5SDimitry Andric     pr_buf->th_doacross_info[last++] = dims[j].up;
42050b57cec5SDimitry Andric     pr_buf->th_doacross_info[last++] = dims[j].st;
42060b57cec5SDimitry Andric   }
42070b57cec5SDimitry Andric 
42080b57cec5SDimitry Andric   // Compute total trip count.
42090b57cec5SDimitry Andric   // Start with range of dims[0] which we don't need to keep in the buffer.
42100b57cec5SDimitry Andric   if (dims[0].st == 1) { // most common case
42110b57cec5SDimitry Andric     trace_count = dims[0].up - dims[0].lo + 1;
42120b57cec5SDimitry Andric   } else if (dims[0].st > 0) {
42130b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(dims[0].up > dims[0].lo);
42140b57cec5SDimitry Andric     trace_count = (kmp_uint64)(dims[0].up - dims[0].lo) / dims[0].st + 1;
42150b57cec5SDimitry Andric   } else { // negative increment
42160b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(dims[0].lo > dims[0].up);
42170b57cec5SDimitry Andric     trace_count = (kmp_uint64)(dims[0].lo - dims[0].up) / (-dims[0].st) + 1;
42180b57cec5SDimitry Andric   }
42190b57cec5SDimitry Andric   for (j = 1; j < num_dims; ++j) {
42200b57cec5SDimitry Andric     trace_count *= pr_buf->th_doacross_info[4 * j + 1]; // use kept ranges
42210b57cec5SDimitry Andric   }
42220b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(trace_count > 0);
42230b57cec5SDimitry Andric 
42240b57cec5SDimitry Andric   // Check if shared buffer is not occupied by other loop (idx -
42250b57cec5SDimitry Andric   // __kmp_dispatch_num_buffers)
42260b57cec5SDimitry Andric   if (idx != sh_buf->doacross_buf_idx) {
42270b57cec5SDimitry Andric     // Shared buffer is occupied, wait for it to be free
42280b57cec5SDimitry Andric     __kmp_wait_4((volatile kmp_uint32 *)&sh_buf->doacross_buf_idx, idx,
42290b57cec5SDimitry Andric                  __kmp_eq_4, NULL);
42300b57cec5SDimitry Andric   }
42310b57cec5SDimitry Andric #if KMP_32_BIT_ARCH
42320b57cec5SDimitry Andric   // Check if we are the first thread. After the CAS the first thread gets 0,
42330b57cec5SDimitry Andric   // others get 1 if initialization is in progress, allocated pointer otherwise.
42340b57cec5SDimitry Andric   // Treat pointer as volatile integer (value 0 or 1) until memory is allocated.
42350b57cec5SDimitry Andric   flags = (kmp_uint32 *)KMP_COMPARE_AND_STORE_RET32(
42360b57cec5SDimitry Andric       (volatile kmp_int32 *)&sh_buf->doacross_flags, NULL, 1);
42370b57cec5SDimitry Andric #else
42380b57cec5SDimitry Andric   flags = (kmp_uint32 *)KMP_COMPARE_AND_STORE_RET64(
42390b57cec5SDimitry Andric       (volatile kmp_int64 *)&sh_buf->doacross_flags, NULL, 1LL);
42400b57cec5SDimitry Andric #endif
42410b57cec5SDimitry Andric   if (flags == NULL) {
42420b57cec5SDimitry Andric     // we are the first thread, allocate the array of flags
4243e8d8bef9SDimitry Andric     size_t size =
4244e8d8bef9SDimitry Andric         (size_t)trace_count / 8 + 8; // in bytes, use single bit per iteration
42450b57cec5SDimitry Andric     flags = (kmp_uint32 *)__kmp_thread_calloc(th, size, 1);
42460b57cec5SDimitry Andric     KMP_MB();
42470b57cec5SDimitry Andric     sh_buf->doacross_flags = flags;
42480b57cec5SDimitry Andric   } else if (flags == (kmp_uint32 *)1) {
42490b57cec5SDimitry Andric #if KMP_32_BIT_ARCH
42500b57cec5SDimitry Andric     // initialization is still in progress, need to wait
42510b57cec5SDimitry Andric     while (*(volatile kmp_int32 *)&sh_buf->doacross_flags == 1)
42520b57cec5SDimitry Andric #else
42530b57cec5SDimitry Andric     while (*(volatile kmp_int64 *)&sh_buf->doacross_flags == 1LL)
42540b57cec5SDimitry Andric #endif
42550b57cec5SDimitry Andric       KMP_YIELD(TRUE);
42560b57cec5SDimitry Andric     KMP_MB();
42570b57cec5SDimitry Andric   } else {
42580b57cec5SDimitry Andric     KMP_MB();
42590b57cec5SDimitry Andric   }
42600b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(sh_buf->doacross_flags > (kmp_uint32 *)1); // check ptr value
42610b57cec5SDimitry Andric   pr_buf->th_doacross_flags =
42620b57cec5SDimitry Andric       sh_buf->doacross_flags; // save private copy in order to not
42630b57cec5SDimitry Andric   // touch shared buffer on each iteration
42640b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_doacross_init() exit: T#%d\n", gtid));
42650b57cec5SDimitry Andric }
42660b57cec5SDimitry Andric 
42670b57cec5SDimitry Andric void __kmpc_doacross_wait(ident_t *loc, int gtid, const kmp_int64 *vec) {
4268e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
4269e8d8bef9SDimitry Andric   kmp_int64 shft;
4270e8d8bef9SDimitry Andric   size_t num_dims, i;
42710b57cec5SDimitry Andric   kmp_uint32 flag;
42720b57cec5SDimitry Andric   kmp_int64 iter_number; // iteration number of "collapsed" loop nest
42730b57cec5SDimitry Andric   kmp_info_t *th = __kmp_threads[gtid];
42740b57cec5SDimitry Andric   kmp_team_t *team = th->th.th_team;
42750b57cec5SDimitry Andric   kmp_disp_t *pr_buf;
42760b57cec5SDimitry Andric   kmp_int64 lo, up, st;
42770b57cec5SDimitry Andric 
42780b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_doacross_wait() enter: called T#%d\n", gtid));
42790b57cec5SDimitry Andric   if (team->t.t_serialized) {
42800b57cec5SDimitry Andric     KA_TRACE(20, ("__kmpc_doacross_wait() exit: serialized team\n"));
42810b57cec5SDimitry Andric     return; // no dependencies if team is serialized
42820b57cec5SDimitry Andric   }
42830b57cec5SDimitry Andric 
42840b57cec5SDimitry Andric   // calculate sequential iteration number and check out-of-bounds condition
42850b57cec5SDimitry Andric   pr_buf = th->th.th_dispatch;
42860b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
4287e8d8bef9SDimitry Andric   num_dims = (size_t)pr_buf->th_doacross_info[0];
42880b57cec5SDimitry Andric   lo = pr_buf->th_doacross_info[2];
42890b57cec5SDimitry Andric   up = pr_buf->th_doacross_info[3];
42900b57cec5SDimitry Andric   st = pr_buf->th_doacross_info[4];
42915ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
4292*0fca6ea1SDimitry Andric   SimpleVLA<ompt_dependence_t> deps(num_dims);
42935ffd83dbSDimitry Andric #endif
42940b57cec5SDimitry Andric   if (st == 1) { // most common case
42950b57cec5SDimitry Andric     if (vec[0] < lo || vec[0] > up) {
42960b57cec5SDimitry Andric       KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
42970b57cec5SDimitry Andric                     "bounds [%lld,%lld]\n",
42980b57cec5SDimitry Andric                     gtid, vec[0], lo, up));
42990b57cec5SDimitry Andric       return;
43000b57cec5SDimitry Andric     }
43010b57cec5SDimitry Andric     iter_number = vec[0] - lo;
43020b57cec5SDimitry Andric   } else if (st > 0) {
43030b57cec5SDimitry Andric     if (vec[0] < lo || vec[0] > up) {
43040b57cec5SDimitry Andric       KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
43050b57cec5SDimitry Andric                     "bounds [%lld,%lld]\n",
43060b57cec5SDimitry Andric                     gtid, vec[0], lo, up));
43070b57cec5SDimitry Andric       return;
43080b57cec5SDimitry Andric     }
43090b57cec5SDimitry Andric     iter_number = (kmp_uint64)(vec[0] - lo) / st;
43100b57cec5SDimitry Andric   } else { // negative increment
43110b57cec5SDimitry Andric     if (vec[0] > lo || vec[0] < up) {
43120b57cec5SDimitry Andric       KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
43130b57cec5SDimitry Andric                     "bounds [%lld,%lld]\n",
43140b57cec5SDimitry Andric                     gtid, vec[0], lo, up));
43150b57cec5SDimitry Andric       return;
43160b57cec5SDimitry Andric     }
43170b57cec5SDimitry Andric     iter_number = (kmp_uint64)(lo - vec[0]) / (-st);
43180b57cec5SDimitry Andric   }
43195ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
43205ffd83dbSDimitry Andric   deps[0].variable.value = iter_number;
43215ffd83dbSDimitry Andric   deps[0].dependence_type = ompt_dependence_type_sink;
43225ffd83dbSDimitry Andric #endif
43230b57cec5SDimitry Andric   for (i = 1; i < num_dims; ++i) {
43240b57cec5SDimitry Andric     kmp_int64 iter, ln;
4325e8d8bef9SDimitry Andric     size_t j = i * 4;
43260b57cec5SDimitry Andric     ln = pr_buf->th_doacross_info[j + 1];
43270b57cec5SDimitry Andric     lo = pr_buf->th_doacross_info[j + 2];
43280b57cec5SDimitry Andric     up = pr_buf->th_doacross_info[j + 3];
43290b57cec5SDimitry Andric     st = pr_buf->th_doacross_info[j + 4];
43300b57cec5SDimitry Andric     if (st == 1) {
43310b57cec5SDimitry Andric       if (vec[i] < lo || vec[i] > up) {
43320b57cec5SDimitry Andric         KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
43330b57cec5SDimitry Andric                       "bounds [%lld,%lld]\n",
43340b57cec5SDimitry Andric                       gtid, vec[i], lo, up));
43350b57cec5SDimitry Andric         return;
43360b57cec5SDimitry Andric       }
43370b57cec5SDimitry Andric       iter = vec[i] - lo;
43380b57cec5SDimitry Andric     } else if (st > 0) {
43390b57cec5SDimitry Andric       if (vec[i] < lo || vec[i] > up) {
43400b57cec5SDimitry Andric         KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
43410b57cec5SDimitry Andric                       "bounds [%lld,%lld]\n",
43420b57cec5SDimitry Andric                       gtid, vec[i], lo, up));
43430b57cec5SDimitry Andric         return;
43440b57cec5SDimitry Andric       }
43450b57cec5SDimitry Andric       iter = (kmp_uint64)(vec[i] - lo) / st;
43460b57cec5SDimitry Andric     } else { // st < 0
43470b57cec5SDimitry Andric       if (vec[i] > lo || vec[i] < up) {
43480b57cec5SDimitry Andric         KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
43490b57cec5SDimitry Andric                       "bounds [%lld,%lld]\n",
43500b57cec5SDimitry Andric                       gtid, vec[i], lo, up));
43510b57cec5SDimitry Andric         return;
43520b57cec5SDimitry Andric       }
43530b57cec5SDimitry Andric       iter = (kmp_uint64)(lo - vec[i]) / (-st);
43540b57cec5SDimitry Andric     }
43550b57cec5SDimitry Andric     iter_number = iter + ln * iter_number;
43565ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
43575ffd83dbSDimitry Andric     deps[i].variable.value = iter;
43585ffd83dbSDimitry Andric     deps[i].dependence_type = ompt_dependence_type_sink;
43595ffd83dbSDimitry Andric #endif
43600b57cec5SDimitry Andric   }
43610b57cec5SDimitry Andric   shft = iter_number % 32; // use 32-bit granularity
43620b57cec5SDimitry Andric   iter_number >>= 5; // divided by 32
43630b57cec5SDimitry Andric   flag = 1 << shft;
43640b57cec5SDimitry Andric   while ((flag & pr_buf->th_doacross_flags[iter_number]) == 0) {
43650b57cec5SDimitry Andric     KMP_YIELD(TRUE);
43660b57cec5SDimitry Andric   }
43670b57cec5SDimitry Andric   KMP_MB();
43685ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
43695ffd83dbSDimitry Andric   if (ompt_enabled.ompt_callback_dependences) {
43705ffd83dbSDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_dependences)(
4371e8d8bef9SDimitry Andric         &(OMPT_CUR_TASK_INFO(th)->task_data), deps, (kmp_uint32)num_dims);
43725ffd83dbSDimitry Andric   }
43735ffd83dbSDimitry Andric #endif
43740b57cec5SDimitry Andric   KA_TRACE(20,
43750b57cec5SDimitry Andric            ("__kmpc_doacross_wait() exit: T#%d wait for iter %lld completed\n",
43760b57cec5SDimitry Andric             gtid, (iter_number << 5) + shft));
43770b57cec5SDimitry Andric }
43780b57cec5SDimitry Andric 
43790b57cec5SDimitry Andric void __kmpc_doacross_post(ident_t *loc, int gtid, const kmp_int64 *vec) {
4380e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
4381e8d8bef9SDimitry Andric   kmp_int64 shft;
4382e8d8bef9SDimitry Andric   size_t num_dims, i;
43830b57cec5SDimitry Andric   kmp_uint32 flag;
43840b57cec5SDimitry Andric   kmp_int64 iter_number; // iteration number of "collapsed" loop nest
43850b57cec5SDimitry Andric   kmp_info_t *th = __kmp_threads[gtid];
43860b57cec5SDimitry Andric   kmp_team_t *team = th->th.th_team;
43870b57cec5SDimitry Andric   kmp_disp_t *pr_buf;
43880b57cec5SDimitry Andric   kmp_int64 lo, st;
43890b57cec5SDimitry Andric 
43900b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_doacross_post() enter: called T#%d\n", gtid));
43910b57cec5SDimitry Andric   if (team->t.t_serialized) {
43920b57cec5SDimitry Andric     KA_TRACE(20, ("__kmpc_doacross_post() exit: serialized team\n"));
43930b57cec5SDimitry Andric     return; // no dependencies if team is serialized
43940b57cec5SDimitry Andric   }
43950b57cec5SDimitry Andric 
43960b57cec5SDimitry Andric   // calculate sequential iteration number (same as in "wait" but no
43970b57cec5SDimitry Andric   // out-of-bounds checks)
43980b57cec5SDimitry Andric   pr_buf = th->th.th_dispatch;
43990b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
4400e8d8bef9SDimitry Andric   num_dims = (size_t)pr_buf->th_doacross_info[0];
44010b57cec5SDimitry Andric   lo = pr_buf->th_doacross_info[2];
44020b57cec5SDimitry Andric   st = pr_buf->th_doacross_info[4];
44035ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
4404*0fca6ea1SDimitry Andric   SimpleVLA<ompt_dependence_t> deps(num_dims);
44055ffd83dbSDimitry Andric #endif
44060b57cec5SDimitry Andric   if (st == 1) { // most common case
44070b57cec5SDimitry Andric     iter_number = vec[0] - lo;
44080b57cec5SDimitry Andric   } else if (st > 0) {
44090b57cec5SDimitry Andric     iter_number = (kmp_uint64)(vec[0] - lo) / st;
44100b57cec5SDimitry Andric   } else { // negative increment
44110b57cec5SDimitry Andric     iter_number = (kmp_uint64)(lo - vec[0]) / (-st);
44120b57cec5SDimitry Andric   }
44135ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
44145ffd83dbSDimitry Andric   deps[0].variable.value = iter_number;
44155ffd83dbSDimitry Andric   deps[0].dependence_type = ompt_dependence_type_source;
44165ffd83dbSDimitry Andric #endif
44170b57cec5SDimitry Andric   for (i = 1; i < num_dims; ++i) {
44180b57cec5SDimitry Andric     kmp_int64 iter, ln;
4419e8d8bef9SDimitry Andric     size_t j = i * 4;
44200b57cec5SDimitry Andric     ln = pr_buf->th_doacross_info[j + 1];
44210b57cec5SDimitry Andric     lo = pr_buf->th_doacross_info[j + 2];
44220b57cec5SDimitry Andric     st = pr_buf->th_doacross_info[j + 4];
44230b57cec5SDimitry Andric     if (st == 1) {
44240b57cec5SDimitry Andric       iter = vec[i] - lo;
44250b57cec5SDimitry Andric     } else if (st > 0) {
44260b57cec5SDimitry Andric       iter = (kmp_uint64)(vec[i] - lo) / st;
44270b57cec5SDimitry Andric     } else { // st < 0
44280b57cec5SDimitry Andric       iter = (kmp_uint64)(lo - vec[i]) / (-st);
44290b57cec5SDimitry Andric     }
44300b57cec5SDimitry Andric     iter_number = iter + ln * iter_number;
44315ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
44325ffd83dbSDimitry Andric     deps[i].variable.value = iter;
44335ffd83dbSDimitry Andric     deps[i].dependence_type = ompt_dependence_type_source;
44345ffd83dbSDimitry Andric #endif
44350b57cec5SDimitry Andric   }
44365ffd83dbSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
44375ffd83dbSDimitry Andric   if (ompt_enabled.ompt_callback_dependences) {
44385ffd83dbSDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_dependences)(
4439e8d8bef9SDimitry Andric         &(OMPT_CUR_TASK_INFO(th)->task_data), deps, (kmp_uint32)num_dims);
44405ffd83dbSDimitry Andric   }
44415ffd83dbSDimitry Andric #endif
44420b57cec5SDimitry Andric   shft = iter_number % 32; // use 32-bit granularity
44430b57cec5SDimitry Andric   iter_number >>= 5; // divided by 32
44440b57cec5SDimitry Andric   flag = 1 << shft;
44450b57cec5SDimitry Andric   KMP_MB();
44460b57cec5SDimitry Andric   if ((flag & pr_buf->th_doacross_flags[iter_number]) == 0)
44470b57cec5SDimitry Andric     KMP_TEST_THEN_OR32(&pr_buf->th_doacross_flags[iter_number], flag);
44480b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_doacross_post() exit: T#%d iter %lld posted\n", gtid,
44490b57cec5SDimitry Andric                 (iter_number << 5) + shft));
44500b57cec5SDimitry Andric }
44510b57cec5SDimitry Andric 
44520b57cec5SDimitry Andric void __kmpc_doacross_fini(ident_t *loc, int gtid) {
4453e8d8bef9SDimitry Andric   __kmp_assert_valid_gtid(gtid);
44540b57cec5SDimitry Andric   kmp_int32 num_done;
44550b57cec5SDimitry Andric   kmp_info_t *th = __kmp_threads[gtid];
44560b57cec5SDimitry Andric   kmp_team_t *team = th->th.th_team;
44570b57cec5SDimitry Andric   kmp_disp_t *pr_buf = th->th.th_dispatch;
44580b57cec5SDimitry Andric 
44590b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_doacross_fini() enter: called T#%d\n", gtid));
44600b57cec5SDimitry Andric   if (team->t.t_serialized) {
44610b57cec5SDimitry Andric     KA_TRACE(20, ("__kmpc_doacross_fini() exit: serialized team %p\n", team));
44620b57cec5SDimitry Andric     return; // nothing to do
44630b57cec5SDimitry Andric   }
4464e8d8bef9SDimitry Andric   num_done =
4465e8d8bef9SDimitry Andric       KMP_TEST_THEN_INC32((kmp_uintptr_t)(pr_buf->th_doacross_info[1])) + 1;
44660b57cec5SDimitry Andric   if (num_done == th->th.th_team_nproc) {
44670b57cec5SDimitry Andric     // we are the last thread, need to free shared resources
44680b57cec5SDimitry Andric     int idx = pr_buf->th_doacross_buf_idx - 1;
44690b57cec5SDimitry Andric     dispatch_shared_info_t *sh_buf =
44700b57cec5SDimitry Andric         &team->t.t_disp_buffer[idx % __kmp_dispatch_num_buffers];
44710b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(pr_buf->th_doacross_info[1] ==
44720b57cec5SDimitry Andric                      (kmp_int64)&sh_buf->doacross_num_done);
44730b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(num_done == sh_buf->doacross_num_done);
44740b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(idx == sh_buf->doacross_buf_idx);
44750b57cec5SDimitry Andric     __kmp_thread_free(th, CCAST(kmp_uint32 *, sh_buf->doacross_flags));
44760b57cec5SDimitry Andric     sh_buf->doacross_flags = NULL;
44770b57cec5SDimitry Andric     sh_buf->doacross_num_done = 0;
44780b57cec5SDimitry Andric     sh_buf->doacross_buf_idx +=
44790b57cec5SDimitry Andric         __kmp_dispatch_num_buffers; // free buffer for future re-use
44800b57cec5SDimitry Andric   }
44810b57cec5SDimitry Andric   // free private resources (need to keep buffer index forever)
44820b57cec5SDimitry Andric   pr_buf->th_doacross_flags = NULL;
44830b57cec5SDimitry Andric   __kmp_thread_free(th, (void *)pr_buf->th_doacross_info);
44840b57cec5SDimitry Andric   pr_buf->th_doacross_info = NULL;
44850b57cec5SDimitry Andric   KA_TRACE(20, ("__kmpc_doacross_fini() exit: T#%d\n", gtid));
44860b57cec5SDimitry Andric }
44870b57cec5SDimitry Andric 
4488349cc55cSDimitry Andric /* OpenMP 5.1 Memory Management routines */
44890b57cec5SDimitry Andric void *omp_alloc(size_t size, omp_allocator_handle_t allocator) {
4490349cc55cSDimitry Andric   return __kmp_alloc(__kmp_entry_gtid(), 0, size, allocator);
4491349cc55cSDimitry Andric }
4492349cc55cSDimitry Andric 
4493349cc55cSDimitry Andric void *omp_aligned_alloc(size_t align, size_t size,
4494349cc55cSDimitry Andric                         omp_allocator_handle_t allocator) {
4495349cc55cSDimitry Andric   return __kmp_alloc(__kmp_entry_gtid(), align, size, allocator);
44960b57cec5SDimitry Andric }
44970b57cec5SDimitry Andric 
4498e8d8bef9SDimitry Andric void *omp_calloc(size_t nmemb, size_t size, omp_allocator_handle_t allocator) {
4499349cc55cSDimitry Andric   return __kmp_calloc(__kmp_entry_gtid(), 0, nmemb, size, allocator);
4500349cc55cSDimitry Andric }
4501349cc55cSDimitry Andric 
4502349cc55cSDimitry Andric void *omp_aligned_calloc(size_t align, size_t nmemb, size_t size,
4503349cc55cSDimitry Andric                          omp_allocator_handle_t allocator) {
4504349cc55cSDimitry Andric   return __kmp_calloc(__kmp_entry_gtid(), align, nmemb, size, allocator);
4505e8d8bef9SDimitry Andric }
4506e8d8bef9SDimitry Andric 
4507e8d8bef9SDimitry Andric void *omp_realloc(void *ptr, size_t size, omp_allocator_handle_t allocator,
4508e8d8bef9SDimitry Andric                   omp_allocator_handle_t free_allocator) {
4509349cc55cSDimitry Andric   return __kmp_realloc(__kmp_entry_gtid(), ptr, size, allocator,
4510e8d8bef9SDimitry Andric                        free_allocator);
4511e8d8bef9SDimitry Andric }
4512e8d8bef9SDimitry Andric 
45130b57cec5SDimitry Andric void omp_free(void *ptr, omp_allocator_handle_t allocator) {
4514349cc55cSDimitry Andric   ___kmpc_free(__kmp_entry_gtid(), ptr, allocator);
45150b57cec5SDimitry Andric }
4516349cc55cSDimitry Andric /* end of OpenMP 5.1 Memory Management routines */
45170b57cec5SDimitry Andric 
45180b57cec5SDimitry Andric int __kmpc_get_target_offload(void) {
45190b57cec5SDimitry Andric   if (!__kmp_init_serial) {
45200b57cec5SDimitry Andric     __kmp_serial_initialize();
45210b57cec5SDimitry Andric   }
45220b57cec5SDimitry Andric   return __kmp_target_offload;
45230b57cec5SDimitry Andric }
45240b57cec5SDimitry Andric 
45250b57cec5SDimitry Andric int __kmpc_pause_resource(kmp_pause_status_t level) {
45260b57cec5SDimitry Andric   if (!__kmp_init_serial) {
45270b57cec5SDimitry Andric     return 1; // Can't pause if runtime is not initialized
45280b57cec5SDimitry Andric   }
45290b57cec5SDimitry Andric   return __kmp_pause_resource(level);
45300b57cec5SDimitry Andric }
4531fe6060f1SDimitry Andric 
4532fe6060f1SDimitry Andric void __kmpc_error(ident_t *loc, int severity, const char *message) {
4533fe6060f1SDimitry Andric   if (!__kmp_init_serial)
4534fe6060f1SDimitry Andric     __kmp_serial_initialize();
4535fe6060f1SDimitry Andric 
4536fe6060f1SDimitry Andric   KMP_ASSERT(severity == severity_warning || severity == severity_fatal);
4537fe6060f1SDimitry Andric 
4538fe6060f1SDimitry Andric #if OMPT_SUPPORT
4539fe6060f1SDimitry Andric   if (ompt_enabled.enabled && ompt_enabled.ompt_callback_error) {
4540fe6060f1SDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_error)(
4541fe6060f1SDimitry Andric         (ompt_severity_t)severity, message, KMP_STRLEN(message),
4542fe6060f1SDimitry Andric         OMPT_GET_RETURN_ADDRESS(0));
4543fe6060f1SDimitry Andric   }
4544fe6060f1SDimitry Andric #endif // OMPT_SUPPORT
4545fe6060f1SDimitry Andric 
4546fe6060f1SDimitry Andric   char *src_loc;
4547fe6060f1SDimitry Andric   if (loc && loc->psource) {
4548fe6060f1SDimitry Andric     kmp_str_loc_t str_loc = __kmp_str_loc_init(loc->psource, false);
4549fe6060f1SDimitry Andric     src_loc =
4550bdd1243dSDimitry Andric         __kmp_str_format("%s:%d:%d", str_loc.file, str_loc.line, str_loc.col);
4551fe6060f1SDimitry Andric     __kmp_str_loc_free(&str_loc);
4552fe6060f1SDimitry Andric   } else {
4553fe6060f1SDimitry Andric     src_loc = __kmp_str_format("unknown");
4554fe6060f1SDimitry Andric   }
4555fe6060f1SDimitry Andric 
4556fe6060f1SDimitry Andric   if (severity == severity_warning)
4557fe6060f1SDimitry Andric     KMP_WARNING(UserDirectedWarning, src_loc, message);
4558fe6060f1SDimitry Andric   else
4559fe6060f1SDimitry Andric     KMP_FATAL(UserDirectedError, src_loc, message);
4560fe6060f1SDimitry Andric 
4561fe6060f1SDimitry Andric   __kmp_str_free(&src_loc);
4562fe6060f1SDimitry Andric }
4563fe6060f1SDimitry Andric 
4564349cc55cSDimitry Andric // Mark begin of scope directive.
4565349cc55cSDimitry Andric void __kmpc_scope(ident_t *loc, kmp_int32 gtid, void *reserved) {
4566349cc55cSDimitry Andric // reserved is for extension of scope directive and not used.
4567349cc55cSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
4568349cc55cSDimitry Andric   if (ompt_enabled.enabled && ompt_enabled.ompt_callback_work) {
4569349cc55cSDimitry Andric     kmp_team_t *team = __kmp_threads[gtid]->th.th_team;
4570349cc55cSDimitry Andric     int tid = __kmp_tid_from_gtid(gtid);
4571349cc55cSDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_work)(
4572349cc55cSDimitry Andric         ompt_work_scope, ompt_scope_begin,
4573349cc55cSDimitry Andric         &(team->t.ompt_team_info.parallel_data),
4574349cc55cSDimitry Andric         &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
4575349cc55cSDimitry Andric         OMPT_GET_RETURN_ADDRESS(0));
4576349cc55cSDimitry Andric   }
4577349cc55cSDimitry Andric #endif // OMPT_SUPPORT && OMPT_OPTIONAL
4578349cc55cSDimitry Andric }
4579349cc55cSDimitry Andric 
4580349cc55cSDimitry Andric // Mark end of scope directive
4581349cc55cSDimitry Andric void __kmpc_end_scope(ident_t *loc, kmp_int32 gtid, void *reserved) {
4582349cc55cSDimitry Andric // reserved is for extension of scope directive and not used.
4583349cc55cSDimitry Andric #if OMPT_SUPPORT && OMPT_OPTIONAL
4584349cc55cSDimitry Andric   if (ompt_enabled.enabled && ompt_enabled.ompt_callback_work) {
4585349cc55cSDimitry Andric     kmp_team_t *team = __kmp_threads[gtid]->th.th_team;
4586349cc55cSDimitry Andric     int tid = __kmp_tid_from_gtid(gtid);
4587349cc55cSDimitry Andric     ompt_callbacks.ompt_callback(ompt_callback_work)(
4588349cc55cSDimitry Andric         ompt_work_scope, ompt_scope_end,
4589349cc55cSDimitry Andric         &(team->t.ompt_team_info.parallel_data),
4590349cc55cSDimitry Andric         &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
4591349cc55cSDimitry Andric         OMPT_GET_RETURN_ADDRESS(0));
4592349cc55cSDimitry Andric   }
4593349cc55cSDimitry Andric #endif // OMPT_SUPPORT && OMPT_OPTIONAL
4594349cc55cSDimitry Andric }
4595349cc55cSDimitry Andric 
4596fe6060f1SDimitry Andric #ifdef KMP_USE_VERSION_SYMBOLS
4597fe6060f1SDimitry Andric // For GOMP compatibility there are two versions of each omp_* API.
4598fe6060f1SDimitry Andric // One is the plain C symbol and one is the Fortran symbol with an appended
4599fe6060f1SDimitry Andric // underscore. When we implement a specific ompc_* version of an omp_*
4600fe6060f1SDimitry Andric // function, we want the plain GOMP versioned symbol to alias the ompc_* version
4601fe6060f1SDimitry Andric // instead of the Fortran versions in kmp_ftn_entry.h
4602fe6060f1SDimitry Andric extern "C" {
4603fe6060f1SDimitry Andric // Have to undef these from omp.h so they aren't translated into
4604fe6060f1SDimitry Andric // their ompc counterparts in the KMP_VERSION_OMPC_SYMBOL macros below
4605fe6060f1SDimitry Andric #ifdef omp_set_affinity_format
4606fe6060f1SDimitry Andric #undef omp_set_affinity_format
4607fe6060f1SDimitry Andric #endif
4608fe6060f1SDimitry Andric #ifdef omp_get_affinity_format
4609fe6060f1SDimitry Andric #undef omp_get_affinity_format
4610fe6060f1SDimitry Andric #endif
4611fe6060f1SDimitry Andric #ifdef omp_display_affinity
4612fe6060f1SDimitry Andric #undef omp_display_affinity
4613fe6060f1SDimitry Andric #endif
4614fe6060f1SDimitry Andric #ifdef omp_capture_affinity
4615fe6060f1SDimitry Andric #undef omp_capture_affinity
4616fe6060f1SDimitry Andric #endif
4617fe6060f1SDimitry Andric KMP_VERSION_OMPC_SYMBOL(ompc_set_affinity_format, omp_set_affinity_format, 50,
4618fe6060f1SDimitry Andric                         "OMP_5.0");
4619fe6060f1SDimitry Andric KMP_VERSION_OMPC_SYMBOL(ompc_get_affinity_format, omp_get_affinity_format, 50,
4620fe6060f1SDimitry Andric                         "OMP_5.0");
4621fe6060f1SDimitry Andric KMP_VERSION_OMPC_SYMBOL(ompc_display_affinity, omp_display_affinity, 50,
4622fe6060f1SDimitry Andric                         "OMP_5.0");
4623fe6060f1SDimitry Andric KMP_VERSION_OMPC_SYMBOL(ompc_capture_affinity, omp_capture_affinity, 50,
4624fe6060f1SDimitry Andric                         "OMP_5.0");
4625fe6060f1SDimitry Andric } // extern "C"
4626fe6060f1SDimitry Andric #endif
4627