LLVM OpenMP* Runtime Library
kmp_taskdeps.cpp
1 /*
2  * kmp_taskdeps.cpp
3  */
4 
5 
6 //===----------------------------------------------------------------------===//
7 //
8 // The LLVM Compiler Infrastructure
9 //
10 // This file is dual licensed under the MIT and the University of Illinois Open
11 // Source Licenses. See LICENSE.txt for details.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 
16 //#define KMP_SUPPORT_GRAPH_OUTPUT 1
17 
18 #include "kmp.h"
19 #include "kmp_io.h"
20 #include "kmp_wait_release.h"
21 
22 #if OMP_40_ENABLED
23 
24 // TODO: Improve memory allocation? keep a list of pre-allocated structures?
25 // allocate in blocks? re-use list finished list entries?
26 // TODO: don't use atomic ref counters for stack-allocated nodes.
27 // TODO: find an alternate to atomic refs for heap-allocated nodes?
28 // TODO: Finish graph output support
29 // TODO: kmp_lock_t seems a tad to big (and heavy weight) for this. Check other
30 // runtime locks
31 // TODO: Any ITT support needed?
32 
33 #ifdef KMP_SUPPORT_GRAPH_OUTPUT
34 static kmp_int32 kmp_node_id_seed = 0;
35 #endif
36 
37 static void __kmp_init_node(kmp_depnode_t *node) {
38  node->dn.task = NULL; // set to null initially, it will point to the right
39  // task once dependences have been processed
40  node->dn.successors = NULL;
41  __kmp_init_lock(&node->dn.lock);
42  node->dn.nrefs = 1; // init creates the first reference to the node
43 #ifdef KMP_SUPPORT_GRAPH_OUTPUT
44  node->dn.id = KMP_TEST_THEN_INC32(&kmp_node_id_seed);
45 #endif
46 }
47 
48 static inline kmp_depnode_t *__kmp_node_ref(kmp_depnode_t *node) {
49  KMP_TEST_THEN_INC32(CCAST(kmp_int32 *, &node->dn.nrefs));
50  return node;
51 }
52 
53 static inline void __kmp_node_deref(kmp_info_t *thread, kmp_depnode_t *node) {
54  if (!node)
55  return;
56 
57  kmp_int32 n = KMP_TEST_THEN_DEC32(CCAST(kmp_int32 *, &node->dn.nrefs)) - 1;
58  if (n == 0) {
59  KMP_ASSERT(node->dn.nrefs == 0);
60 #if USE_FAST_MEMORY
61  __kmp_fast_free(thread, node);
62 #else
63  __kmp_thread_free(thread, node);
64 #endif
65  }
66 }
67 
68 #define KMP_ACQUIRE_DEPNODE(gtid, n) __kmp_acquire_lock(&(n)->dn.lock, (gtid))
69 #define KMP_RELEASE_DEPNODE(gtid, n) __kmp_release_lock(&(n)->dn.lock, (gtid))
70 
71 static void __kmp_depnode_list_free(kmp_info_t *thread, kmp_depnode_list *list);
72 
73 enum { KMP_DEPHASH_OTHER_SIZE = 97, KMP_DEPHASH_MASTER_SIZE = 997 };
74 
75 static inline kmp_int32 __kmp_dephash_hash(kmp_intptr_t addr, size_t hsize) {
76  // TODO alternate to try: set = (((Addr64)(addrUsefulBits * 9.618)) %
77  // m_num_sets );
78  return ((addr >> 6) ^ (addr >> 2)) % hsize;
79 }
80 
81 static kmp_dephash_t *__kmp_dephash_create(kmp_info_t *thread,
82  kmp_taskdata_t *current_task) {
83  kmp_dephash_t *h;
84 
85  size_t h_size;
86 
87  if (current_task->td_flags.tasktype == TASK_IMPLICIT)
88  h_size = KMP_DEPHASH_MASTER_SIZE;
89  else
90  h_size = KMP_DEPHASH_OTHER_SIZE;
91 
92  kmp_int32 size =
93  h_size * sizeof(kmp_dephash_entry_t *) + sizeof(kmp_dephash_t);
94 
95 #if USE_FAST_MEMORY
96  h = (kmp_dephash_t *)__kmp_fast_allocate(thread, size);
97 #else
98  h = (kmp_dephash_t *)__kmp_thread_malloc(thread, size);
99 #endif
100  h->size = h_size;
101 
102 #ifdef KMP_DEBUG
103  h->nelements = 0;
104  h->nconflicts = 0;
105 #endif
106  h->buckets = (kmp_dephash_entry **)(h + 1);
107 
108  for (size_t i = 0; i < h_size; i++)
109  h->buckets[i] = 0;
110 
111  return h;
112 }
113 
114 void __kmp_dephash_free_entries(kmp_info_t *thread, kmp_dephash_t *h) {
115  for (size_t i = 0; i < h->size; i++) {
116  if (h->buckets[i]) {
117  kmp_dephash_entry_t *next;
118  for (kmp_dephash_entry_t *entry = h->buckets[i]; entry; entry = next) {
119  next = entry->next_in_bucket;
120  __kmp_depnode_list_free(thread, entry->last_ins);
121  __kmp_node_deref(thread, entry->last_out);
122 #if USE_FAST_MEMORY
123  __kmp_fast_free(thread, entry);
124 #else
125  __kmp_thread_free(thread, entry);
126 #endif
127  }
128  h->buckets[i] = 0;
129  }
130  }
131 }
132 
133 void __kmp_dephash_free(kmp_info_t *thread, kmp_dephash_t *h) {
134  __kmp_dephash_free_entries(thread, h);
135 #if USE_FAST_MEMORY
136  __kmp_fast_free(thread, h);
137 #else
138  __kmp_thread_free(thread, h);
139 #endif
140 }
141 
142 static kmp_dephash_entry *
143 __kmp_dephash_find(kmp_info_t *thread, kmp_dephash_t *h, kmp_intptr_t addr) {
144  kmp_int32 bucket = __kmp_dephash_hash(addr, h->size);
145 
146  kmp_dephash_entry_t *entry;
147  for (entry = h->buckets[bucket]; entry; entry = entry->next_in_bucket)
148  if (entry->addr == addr)
149  break;
150 
151  if (entry == NULL) {
152 // create entry. This is only done by one thread so no locking required
153 #if USE_FAST_MEMORY
154  entry = (kmp_dephash_entry_t *)__kmp_fast_allocate(
155  thread, sizeof(kmp_dephash_entry_t));
156 #else
157  entry = (kmp_dephash_entry_t *)__kmp_thread_malloc(
158  thread, sizeof(kmp_dephash_entry_t));
159 #endif
160  entry->addr = addr;
161  entry->last_out = NULL;
162  entry->last_ins = NULL;
163  entry->next_in_bucket = h->buckets[bucket];
164  h->buckets[bucket] = entry;
165 #ifdef KMP_DEBUG
166  h->nelements++;
167  if (entry->next_in_bucket)
168  h->nconflicts++;
169 #endif
170  }
171  return entry;
172 }
173 
174 static kmp_depnode_list_t *__kmp_add_node(kmp_info_t *thread,
175  kmp_depnode_list_t *list,
176  kmp_depnode_t *node) {
177  kmp_depnode_list_t *new_head;
178 
179 #if USE_FAST_MEMORY
180  new_head = (kmp_depnode_list_t *)__kmp_fast_allocate(
181  thread, sizeof(kmp_depnode_list_t));
182 #else
183  new_head = (kmp_depnode_list_t *)__kmp_thread_malloc(
184  thread, sizeof(kmp_depnode_list_t));
185 #endif
186 
187  new_head->node = __kmp_node_ref(node);
188  new_head->next = list;
189 
190  return new_head;
191 }
192 
193 static void __kmp_depnode_list_free(kmp_info_t *thread,
194  kmp_depnode_list *list) {
195  kmp_depnode_list *next;
196 
197  for (; list; list = next) {
198  next = list->next;
199 
200  __kmp_node_deref(thread, list->node);
201 #if USE_FAST_MEMORY
202  __kmp_fast_free(thread, list);
203 #else
204  __kmp_thread_free(thread, list);
205 #endif
206  }
207 }
208 
209 static inline void __kmp_track_dependence(kmp_depnode_t *source,
210  kmp_depnode_t *sink,
211  kmp_task_t *sink_task) {
212 #ifdef KMP_SUPPORT_GRAPH_OUTPUT
213  kmp_taskdata_t *task_source = KMP_TASK_TO_TASKDATA(source->dn.task);
214  // do not use sink->dn.task as that is only filled after the dependencies
215  // are already processed!
216  kmp_taskdata_t *task_sink = KMP_TASK_TO_TASKDATA(sink_task);
217 
218  __kmp_printf("%d(%s) -> %d(%s)\n", source->dn.id,
219  task_source->td_ident->psource, sink->dn.id,
220  task_sink->td_ident->psource);
221 #endif
222 #if OMPT_SUPPORT && OMPT_TRACE
223  // OMPT tracks dependences between task (a=source, b=sink) in which
224  // task a blocks the execution of b through the ompt_new_dependence_callback
225  if (ompt_enabled &&
226  ompt_callbacks.ompt_callback(ompt_event_task_dependence_pair)) {
227  kmp_taskdata_t *task_source = KMP_TASK_TO_TASKDATA(source->dn.task);
228  kmp_taskdata_t *task_sink = KMP_TASK_TO_TASKDATA(sink_task);
229 
230  ompt_callbacks.ompt_callback(ompt_event_task_dependence_pair)(
231  task_source->ompt_task_info.task_id, task_sink->ompt_task_info.task_id);
232  }
233 #endif /* OMPT_SUPPORT && OMPT_TRACE */
234 }
235 
236 template <bool filter>
237 static inline kmp_int32
238 __kmp_process_deps(kmp_int32 gtid, kmp_depnode_t *node, kmp_dephash_t *hash,
239  bool dep_barrier, kmp_int32 ndeps,
240  kmp_depend_info_t *dep_list, kmp_task_t *task) {
241  KA_TRACE(30, ("__kmp_process_deps<%d>: T#%d processing %d dependencies : "
242  "dep_barrier = %d\n",
243  filter, gtid, ndeps, dep_barrier));
244 
245  kmp_info_t *thread = __kmp_threads[gtid];
246  kmp_int32 npredecessors = 0;
247  for (kmp_int32 i = 0; i < ndeps; i++) {
248  const kmp_depend_info_t *dep = &dep_list[i];
249 
250  KMP_DEBUG_ASSERT(dep->flags.in);
251 
252  if (filter && dep->base_addr == 0)
253  continue; // skip filtered entries
254 
255  kmp_dephash_entry_t *info =
256  __kmp_dephash_find(thread, hash, dep->base_addr);
257  kmp_depnode_t *last_out = info->last_out;
258 
259  if (dep->flags.out && info->last_ins) {
260  for (kmp_depnode_list_t *p = info->last_ins; p; p = p->next) {
261  kmp_depnode_t *indep = p->node;
262  if (indep->dn.task) {
263  KMP_ACQUIRE_DEPNODE(gtid, indep);
264  if (indep->dn.task) {
265  __kmp_track_dependence(indep, node, task);
266  indep->dn.successors =
267  __kmp_add_node(thread, indep->dn.successors, node);
268  KA_TRACE(40, ("__kmp_process_deps<%d>: T#%d adding dependence from "
269  "%p to %p\n",
270  filter, gtid, KMP_TASK_TO_TASKDATA(indep->dn.task),
271  KMP_TASK_TO_TASKDATA(task)));
272  npredecessors++;
273  }
274  KMP_RELEASE_DEPNODE(gtid, indep);
275  }
276  }
277 
278  __kmp_depnode_list_free(thread, info->last_ins);
279  info->last_ins = NULL;
280 
281  } else if (last_out && last_out->dn.task) {
282  KMP_ACQUIRE_DEPNODE(gtid, last_out);
283  if (last_out->dn.task) {
284  __kmp_track_dependence(last_out, node, task);
285  last_out->dn.successors =
286  __kmp_add_node(thread, last_out->dn.successors, node);
287  KA_TRACE(
288  40,
289  ("__kmp_process_deps<%d>: T#%d adding dependence from %p to %p\n",
290  filter, gtid, KMP_TASK_TO_TASKDATA(last_out->dn.task),
291  KMP_TASK_TO_TASKDATA(task)));
292 
293  npredecessors++;
294  }
295  KMP_RELEASE_DEPNODE(gtid, last_out);
296  }
297 
298  if (dep_barrier) {
299  // if this is a sync point in the serial sequence, then the previous
300  // outputs are guaranteed to be completed after
301  // the execution of this task so the previous output nodes can be cleared.
302  __kmp_node_deref(thread, last_out);
303  info->last_out = NULL;
304  } else {
305  if (dep->flags.out) {
306  __kmp_node_deref(thread, last_out);
307  info->last_out = __kmp_node_ref(node);
308  } else
309  info->last_ins = __kmp_add_node(thread, info->last_ins, node);
310  }
311  }
312 
313  KA_TRACE(30, ("__kmp_process_deps<%d>: T#%d found %d predecessors\n", filter,
314  gtid, npredecessors));
315 
316  return npredecessors;
317 }
318 
319 #define NO_DEP_BARRIER (false)
320 #define DEP_BARRIER (true)
321 
322 // returns true if the task has any outstanding dependence
323 static bool __kmp_check_deps(kmp_int32 gtid, kmp_depnode_t *node,
324  kmp_task_t *task, kmp_dephash_t *hash,
325  bool dep_barrier, kmp_int32 ndeps,
326  kmp_depend_info_t *dep_list,
327  kmp_int32 ndeps_noalias,
328  kmp_depend_info_t *noalias_dep_list) {
329  int i;
330 
331 #if KMP_DEBUG
332  kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
333 #endif
334  KA_TRACE(20, ("__kmp_check_deps: T#%d checking dependencies for task %p : %d "
335  "possibly aliased dependencies, %d non-aliased depedencies : "
336  "dep_barrier=%d .\n",
337  gtid, taskdata, ndeps, ndeps_noalias, dep_barrier));
338 
339  // Filter deps in dep_list
340  // TODO: Different algorithm for large dep_list ( > 10 ? )
341  for (i = 0; i < ndeps; i++) {
342  if (dep_list[i].base_addr != 0)
343  for (int j = i + 1; j < ndeps; j++)
344  if (dep_list[i].base_addr == dep_list[j].base_addr) {
345  dep_list[i].flags.in |= dep_list[j].flags.in;
346  dep_list[i].flags.out |= dep_list[j].flags.out;
347  dep_list[j].base_addr = 0; // Mark j element as void
348  }
349  }
350 
351  // doesn't need to be atomic as no other thread is going to be accessing this
352  // node just yet.
353  // npredecessors is set -1 to ensure that none of the releasing tasks queues
354  // this task before we have finished processing all the dependencies
355  node->dn.npredecessors = -1;
356 
357  // used to pack all npredecessors additions into a single atomic operation at
358  // the end
359  int npredecessors;
360 
361  npredecessors = __kmp_process_deps<true>(gtid, node, hash, dep_barrier, ndeps,
362  dep_list, task);
363  npredecessors += __kmp_process_deps<false>(
364  gtid, node, hash, dep_barrier, ndeps_noalias, noalias_dep_list, task);
365 
366  node->dn.task = task;
367  KMP_MB();
368 
369  // Account for our initial fake value
370  npredecessors++;
371 
372  // Update predecessors and obtain current value to check if there are still
373  // any outstandig dependences (some tasks may have finished while we processed
374  // the dependences)
375  npredecessors =
376  KMP_TEST_THEN_ADD32(CCAST(kmp_int32 *, &node->dn.npredecessors),
377  npredecessors) +
378  npredecessors;
379 
380  KA_TRACE(20, ("__kmp_check_deps: T#%d found %d predecessors for task %p \n",
381  gtid, npredecessors, taskdata));
382 
383  // beyond this point the task could be queued (and executed) by a releasing
384  // task...
385  return npredecessors > 0 ? true : false;
386 }
387 
388 void __kmp_release_deps(kmp_int32 gtid, kmp_taskdata_t *task) {
389  kmp_info_t *thread = __kmp_threads[gtid];
390  kmp_depnode_t *node = task->td_depnode;
391 
392  if (task->td_dephash) {
393  KA_TRACE(
394  40, ("__kmp_release_deps: T#%d freeing dependencies hash of task %p.\n",
395  gtid, task));
396  __kmp_dephash_free(thread, task->td_dephash);
397  task->td_dephash = NULL;
398  }
399 
400  if (!node)
401  return;
402 
403  KA_TRACE(20, ("__kmp_release_deps: T#%d notifying successors of task %p.\n",
404  gtid, task));
405 
406  KMP_ACQUIRE_DEPNODE(gtid, node);
407  node->dn.task =
408  NULL; // mark this task as finished, so no new dependencies are generated
409  KMP_RELEASE_DEPNODE(gtid, node);
410 
411  kmp_depnode_list_t *next;
412  for (kmp_depnode_list_t *p = node->dn.successors; p; p = next) {
413  kmp_depnode_t *successor = p->node;
414  kmp_int32 npredecessors =
415  KMP_TEST_THEN_DEC32(CCAST(kmp_int32 *, &successor->dn.npredecessors)) -
416  1;
417  // successor task can be NULL for wait_depends or because deps are still
418  // being processed
419  if (npredecessors == 0) {
420  KMP_MB();
421  if (successor->dn.task) {
422  KA_TRACE(20, ("__kmp_release_deps: T#%d successor %p of %p scheduled "
423  "for execution.\n",
424  gtid, successor->dn.task, task));
425  __kmp_omp_task(gtid, successor->dn.task, false);
426  }
427  }
428 
429  next = p->next;
430  __kmp_node_deref(thread, p->node);
431 #if USE_FAST_MEMORY
432  __kmp_fast_free(thread, p);
433 #else
434  __kmp_thread_free(thread, p);
435 #endif
436  }
437 
438  __kmp_node_deref(thread, node);
439 
440  KA_TRACE(
441  20,
442  ("__kmp_release_deps: T#%d all successors of %p notified of completion\n",
443  gtid, task));
444 }
445 
462 kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid,
463  kmp_task_t *new_task, kmp_int32 ndeps,
464  kmp_depend_info_t *dep_list,
465  kmp_int32 ndeps_noalias,
466  kmp_depend_info_t *noalias_dep_list) {
467 
468  kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
469  KA_TRACE(10, ("__kmpc_omp_task_with_deps(enter): T#%d loc=%p task=%p\n", gtid,
470  loc_ref, new_taskdata));
471 
472  kmp_info_t *thread = __kmp_threads[gtid];
473  kmp_taskdata_t *current_task = thread->th.th_current_task;
474 
475 #if OMPT_SUPPORT && OMPT_TRACE
476  /* OMPT grab all dependences if requested by the tool */
477  if (ompt_enabled && ndeps + ndeps_noalias > 0 &&
478  ompt_callbacks.ompt_callback(ompt_event_task_dependences)) {
479  kmp_int32 i;
480 
481  new_taskdata->ompt_task_info.ndeps = ndeps + ndeps_noalias;
482  new_taskdata->ompt_task_info.deps =
483  (ompt_task_dependence_t *)KMP_OMPT_DEPS_ALLOC(
484  thread, (ndeps + ndeps_noalias) * sizeof(ompt_task_dependence_t));
485 
486  KMP_ASSERT(new_taskdata->ompt_task_info.deps != NULL);
487 
488  for (i = 0; i < ndeps; i++) {
489  new_taskdata->ompt_task_info.deps[i].variable_addr =
490  (void *)dep_list[i].base_addr;
491  if (dep_list[i].flags.in && dep_list[i].flags.out)
492  new_taskdata->ompt_task_info.deps[i].dependence_flags =
493  ompt_task_dependence_type_inout;
494  else if (dep_list[i].flags.out)
495  new_taskdata->ompt_task_info.deps[i].dependence_flags =
496  ompt_task_dependence_type_out;
497  else if (dep_list[i].flags.in)
498  new_taskdata->ompt_task_info.deps[i].dependence_flags =
499  ompt_task_dependence_type_in;
500  }
501  for (i = 0; i < ndeps_noalias; i++) {
502  new_taskdata->ompt_task_info.deps[ndeps + i].variable_addr =
503  (void *)noalias_dep_list[i].base_addr;
504  if (noalias_dep_list[i].flags.in && noalias_dep_list[i].flags.out)
505  new_taskdata->ompt_task_info.deps[ndeps + i].dependence_flags =
506  ompt_task_dependence_type_inout;
507  else if (noalias_dep_list[i].flags.out)
508  new_taskdata->ompt_task_info.deps[ndeps + i].dependence_flags =
509  ompt_task_dependence_type_out;
510  else if (noalias_dep_list[i].flags.in)
511  new_taskdata->ompt_task_info.deps[ndeps + i].dependence_flags =
512  ompt_task_dependence_type_in;
513  }
514  }
515 #endif /* OMPT_SUPPORT && OMPT_TRACE */
516 
517  bool serial = current_task->td_flags.team_serial ||
518  current_task->td_flags.tasking_ser ||
519  current_task->td_flags.final;
520 #if OMP_45_ENABLED
521  kmp_task_team_t *task_team = thread->th.th_task_team;
522  serial = serial && !(task_team && task_team->tt.tt_found_proxy_tasks);
523 #endif
524 
525  if (!serial && (ndeps > 0 || ndeps_noalias > 0)) {
526  /* if no dependencies have been tracked yet, create the dependence hash */
527  if (current_task->td_dephash == NULL)
528  current_task->td_dephash = __kmp_dephash_create(thread, current_task);
529 
530 #if USE_FAST_MEMORY
531  kmp_depnode_t *node =
532  (kmp_depnode_t *)__kmp_fast_allocate(thread, sizeof(kmp_depnode_t));
533 #else
534  kmp_depnode_t *node =
535  (kmp_depnode_t *)__kmp_thread_malloc(thread, sizeof(kmp_depnode_t));
536 #endif
537 
538  __kmp_init_node(node);
539  new_taskdata->td_depnode = node;
540 
541  if (__kmp_check_deps(gtid, node, new_task, current_task->td_dephash,
542  NO_DEP_BARRIER, ndeps, dep_list, ndeps_noalias,
543  noalias_dep_list)) {
544  KA_TRACE(10, ("__kmpc_omp_task_with_deps(exit): T#%d task had blocking "
545  "dependencies: "
546  "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n",
547  gtid, loc_ref, new_taskdata));
548  return TASK_CURRENT_NOT_QUEUED;
549  }
550  } else {
551  KA_TRACE(10, ("__kmpc_omp_task_with_deps(exit): T#%d ignored dependencies "
552  "for task (serialized)"
553  "loc=%p task=%p\n",
554  gtid, loc_ref, new_taskdata));
555  }
556 
557  KA_TRACE(10, ("__kmpc_omp_task_with_deps(exit): T#%d task had no blocking "
558  "dependencies : "
559  "loc=%p task=%p, transferring to __kmpc_omp_task\n",
560  gtid, loc_ref, new_taskdata));
561 
562  return __kmpc_omp_task(loc_ref, gtid, new_task);
563 }
564 
576 void __kmpc_omp_wait_deps(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 ndeps,
577  kmp_depend_info_t *dep_list, kmp_int32 ndeps_noalias,
578  kmp_depend_info_t *noalias_dep_list) {
579  KA_TRACE(10, ("__kmpc_omp_wait_deps(enter): T#%d loc=%p\n", gtid, loc_ref));
580 
581  if (ndeps == 0 && ndeps_noalias == 0) {
582  KA_TRACE(10, ("__kmpc_omp_wait_deps(exit): T#%d has no dependencies to "
583  "wait upon : loc=%p\n",
584  gtid, loc_ref));
585  return;
586  }
587 
588  kmp_info_t *thread = __kmp_threads[gtid];
589  kmp_taskdata_t *current_task = thread->th.th_current_task;
590 
591  // We can return immediately as:
592  // - dependences are not computed in serial teams (except with proxy tasks)
593  // - if the dephash is not yet created it means we have nothing to wait for
594  bool ignore = current_task->td_flags.team_serial ||
595  current_task->td_flags.tasking_ser ||
596  current_task->td_flags.final;
597 #if OMP_45_ENABLED
598  ignore = ignore && thread->th.th_task_team != NULL &&
599  thread->th.th_task_team->tt.tt_found_proxy_tasks == FALSE;
600 #endif
601  ignore = ignore || current_task->td_dephash == NULL;
602 
603  if (ignore) {
604  KA_TRACE(10, ("__kmpc_omp_wait_deps(exit): T#%d has no blocking "
605  "dependencies : loc=%p\n",
606  gtid, loc_ref));
607  return;
608  }
609 
610  kmp_depnode_t node;
611  __kmp_init_node(&node);
612 
613  if (!__kmp_check_deps(gtid, &node, NULL, current_task->td_dephash,
614  DEP_BARRIER, ndeps, dep_list, ndeps_noalias,
615  noalias_dep_list)) {
616  KA_TRACE(10, ("__kmpc_omp_wait_deps(exit): T#%d has no blocking "
617  "dependencies : loc=%p\n",
618  gtid, loc_ref));
619  return;
620  }
621 
622  int thread_finished = FALSE;
623  kmp_flag_32 flag((volatile kmp_uint32 *)&(node.dn.npredecessors), 0U);
624  while (node.dn.npredecessors > 0) {
625  flag.execute_tasks(thread, gtid, FALSE, &thread_finished,
626 #if USE_ITT_BUILD
627  NULL,
628 #endif
629  __kmp_task_stealing_constraint);
630  }
631 
632  KA_TRACE(10, ("__kmpc_omp_wait_deps(exit): T#%d finished waiting : loc=%p\n",
633  gtid, loc_ref));
634 }
635 
636 #endif /* OMP_40_ENABLED */
void __kmpc_omp_wait_deps(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list)
kmp_int32 __kmpc_omp_task_with_deps(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list)
Definition: kmp.h:208