1629ff9f7SJohn Marino /* Copyright (C) 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
2629ff9f7SJohn Marino Contributed by Richard Henderson <rth@redhat.com>.
3629ff9f7SJohn Marino
4629ff9f7SJohn Marino This file is part of the GNU OpenMP Library (libgomp).
5629ff9f7SJohn Marino
6629ff9f7SJohn Marino Libgomp is free software; you can redistribute it and/or modify it
7629ff9f7SJohn Marino under the terms of the GNU General Public License as published by
8629ff9f7SJohn Marino the Free Software Foundation; either version 3, or (at your option)
9629ff9f7SJohn Marino any later version.
10629ff9f7SJohn Marino
11629ff9f7SJohn Marino Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12629ff9f7SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13629ff9f7SJohn Marino FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14629ff9f7SJohn Marino more details.
15629ff9f7SJohn Marino
16629ff9f7SJohn Marino Under Section 7 of GPL version 3, you are granted additional
17629ff9f7SJohn Marino permissions described in the GCC Runtime Library Exception, version
18629ff9f7SJohn Marino 3.1, as published by the Free Software Foundation.
19629ff9f7SJohn Marino
20629ff9f7SJohn Marino You should have received a copy of the GNU General Public License and
21629ff9f7SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
22629ff9f7SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23629ff9f7SJohn Marino <http://www.gnu.org/licenses/>. */
24629ff9f7SJohn Marino
25629ff9f7SJohn Marino /* This file handles the maintainence of tasks in response to task
26629ff9f7SJohn Marino creation and termination. */
27629ff9f7SJohn Marino
28629ff9f7SJohn Marino #include "libgomp.h"
29629ff9f7SJohn Marino #include <stdlib.h>
30629ff9f7SJohn Marino #include <string.h>
31629ff9f7SJohn Marino
32629ff9f7SJohn Marino
33629ff9f7SJohn Marino /* Create a new task data structure. */
34629ff9f7SJohn Marino
35629ff9f7SJohn Marino void
gomp_init_task(struct gomp_task * task,struct gomp_task * parent_task,struct gomp_task_icv * prev_icv)36629ff9f7SJohn Marino gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
37629ff9f7SJohn Marino struct gomp_task_icv *prev_icv)
38629ff9f7SJohn Marino {
39629ff9f7SJohn Marino task->parent = parent_task;
40629ff9f7SJohn Marino task->icv = *prev_icv;
41629ff9f7SJohn Marino task->kind = GOMP_TASK_IMPLICIT;
42629ff9f7SJohn Marino task->in_taskwait = false;
43629ff9f7SJohn Marino task->in_tied_task = false;
44629ff9f7SJohn Marino task->final_task = false;
45629ff9f7SJohn Marino task->children = NULL;
46629ff9f7SJohn Marino gomp_sem_init (&task->taskwait_sem, 0);
47629ff9f7SJohn Marino }
48629ff9f7SJohn Marino
49629ff9f7SJohn Marino /* Clean up a task, after completing it. */
50629ff9f7SJohn Marino
51629ff9f7SJohn Marino void
gomp_end_task(void)52629ff9f7SJohn Marino gomp_end_task (void)
53629ff9f7SJohn Marino {
54629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
55629ff9f7SJohn Marino struct gomp_task *task = thr->task;
56629ff9f7SJohn Marino
57629ff9f7SJohn Marino gomp_finish_task (task);
58629ff9f7SJohn Marino thr->task = task->parent;
59629ff9f7SJohn Marino }
60629ff9f7SJohn Marino
61629ff9f7SJohn Marino static inline void
gomp_clear_parent(struct gomp_task * children)62629ff9f7SJohn Marino gomp_clear_parent (struct gomp_task *children)
63629ff9f7SJohn Marino {
64629ff9f7SJohn Marino struct gomp_task *task = children;
65629ff9f7SJohn Marino
66629ff9f7SJohn Marino if (task)
67629ff9f7SJohn Marino do
68629ff9f7SJohn Marino {
69629ff9f7SJohn Marino task->parent = NULL;
70629ff9f7SJohn Marino task = task->next_child;
71629ff9f7SJohn Marino }
72629ff9f7SJohn Marino while (task != children);
73629ff9f7SJohn Marino }
74629ff9f7SJohn Marino
75629ff9f7SJohn Marino /* Called when encountering an explicit task directive. If IF_CLAUSE is
76629ff9f7SJohn Marino false, then we must not delay in executing the task. If UNTIED is true,
77629ff9f7SJohn Marino then the task may be executed by any member of the team. */
78629ff9f7SJohn Marino
79629ff9f7SJohn Marino void
GOMP_task(void (* fn)(void *),void * data,void (* cpyfn)(void *,void *),long arg_size,long arg_align,bool if_clause,unsigned flags)80629ff9f7SJohn Marino GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
81629ff9f7SJohn Marino long arg_size, long arg_align, bool if_clause, unsigned flags)
82629ff9f7SJohn Marino {
83629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
84629ff9f7SJohn Marino struct gomp_team *team = thr->ts.team;
85629ff9f7SJohn Marino
86629ff9f7SJohn Marino #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
87629ff9f7SJohn Marino /* If pthread_mutex_* is used for omp_*lock*, then each task must be
88629ff9f7SJohn Marino tied to one thread all the time. This means UNTIED tasks must be
89629ff9f7SJohn Marino tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
90629ff9f7SJohn Marino might be running on different thread than FN. */
91629ff9f7SJohn Marino if (cpyfn)
92629ff9f7SJohn Marino if_clause = false;
93629ff9f7SJohn Marino if (flags & 1)
94629ff9f7SJohn Marino flags &= ~1;
95629ff9f7SJohn Marino #endif
96629ff9f7SJohn Marino
97629ff9f7SJohn Marino if (!if_clause || team == NULL
98629ff9f7SJohn Marino || (thr->task && thr->task->final_task)
99629ff9f7SJohn Marino || team->task_count > 64 * team->nthreads)
100629ff9f7SJohn Marino {
101629ff9f7SJohn Marino struct gomp_task task;
102629ff9f7SJohn Marino
103629ff9f7SJohn Marino gomp_init_task (&task, thr->task, gomp_icv (false));
104629ff9f7SJohn Marino task.kind = GOMP_TASK_IFFALSE;
105629ff9f7SJohn Marino task.final_task = (thr->task && thr->task->final_task) || (flags & 2);
106629ff9f7SJohn Marino if (thr->task)
107629ff9f7SJohn Marino task.in_tied_task = thr->task->in_tied_task;
108629ff9f7SJohn Marino thr->task = &task;
109629ff9f7SJohn Marino if (__builtin_expect (cpyfn != NULL, 0))
110629ff9f7SJohn Marino {
111629ff9f7SJohn Marino char buf[arg_size + arg_align - 1];
112629ff9f7SJohn Marino char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
113629ff9f7SJohn Marino & ~(uintptr_t) (arg_align - 1));
114629ff9f7SJohn Marino cpyfn (arg, data);
115629ff9f7SJohn Marino fn (arg);
116629ff9f7SJohn Marino }
117629ff9f7SJohn Marino else
118629ff9f7SJohn Marino fn (data);
119*5ce9237cSJohn Marino /* Access to "children" is normally done inside a task_lock
120*5ce9237cSJohn Marino mutex region, but the only way this particular task.children
121*5ce9237cSJohn Marino can be set is if this thread's task work function (fn)
122*5ce9237cSJohn Marino creates children. So since the setter is *this* thread, we
123*5ce9237cSJohn Marino need no barriers here when testing for non-NULL. We can have
124*5ce9237cSJohn Marino task.children set by the current thread then changed by a
125*5ce9237cSJohn Marino child thread, but seeing a stale non-NULL value is not a
126*5ce9237cSJohn Marino problem. Once past the task_lock acquisition, this thread
127*5ce9237cSJohn Marino will see the real value of task.children. */
128*5ce9237cSJohn Marino if (task.children != NULL)
129629ff9f7SJohn Marino {
130629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
131629ff9f7SJohn Marino gomp_clear_parent (task.children);
132629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
133629ff9f7SJohn Marino }
134629ff9f7SJohn Marino gomp_end_task ();
135629ff9f7SJohn Marino }
136629ff9f7SJohn Marino else
137629ff9f7SJohn Marino {
138629ff9f7SJohn Marino struct gomp_task *task;
139629ff9f7SJohn Marino struct gomp_task *parent = thr->task;
140629ff9f7SJohn Marino char *arg;
141629ff9f7SJohn Marino bool do_wake;
142629ff9f7SJohn Marino
143629ff9f7SJohn Marino task = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
144629ff9f7SJohn Marino arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
145629ff9f7SJohn Marino & ~(uintptr_t) (arg_align - 1));
146629ff9f7SJohn Marino gomp_init_task (task, parent, gomp_icv (false));
147629ff9f7SJohn Marino task->kind = GOMP_TASK_IFFALSE;
148629ff9f7SJohn Marino task->in_tied_task = parent->in_tied_task;
149629ff9f7SJohn Marino thr->task = task;
150629ff9f7SJohn Marino if (cpyfn)
151629ff9f7SJohn Marino cpyfn (arg, data);
152629ff9f7SJohn Marino else
153629ff9f7SJohn Marino memcpy (arg, data, arg_size);
154629ff9f7SJohn Marino thr->task = parent;
155629ff9f7SJohn Marino task->kind = GOMP_TASK_WAITING;
156629ff9f7SJohn Marino task->fn = fn;
157629ff9f7SJohn Marino task->fn_data = arg;
158629ff9f7SJohn Marino task->in_tied_task = true;
159629ff9f7SJohn Marino task->final_task = (flags & 2) >> 1;
160629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
161629ff9f7SJohn Marino if (parent->children)
162629ff9f7SJohn Marino {
163629ff9f7SJohn Marino task->next_child = parent->children;
164629ff9f7SJohn Marino task->prev_child = parent->children->prev_child;
165629ff9f7SJohn Marino task->next_child->prev_child = task;
166629ff9f7SJohn Marino task->prev_child->next_child = task;
167629ff9f7SJohn Marino }
168629ff9f7SJohn Marino else
169629ff9f7SJohn Marino {
170629ff9f7SJohn Marino task->next_child = task;
171629ff9f7SJohn Marino task->prev_child = task;
172629ff9f7SJohn Marino }
173629ff9f7SJohn Marino parent->children = task;
174629ff9f7SJohn Marino if (team->task_queue)
175629ff9f7SJohn Marino {
176629ff9f7SJohn Marino task->next_queue = team->task_queue;
177629ff9f7SJohn Marino task->prev_queue = team->task_queue->prev_queue;
178629ff9f7SJohn Marino task->next_queue->prev_queue = task;
179629ff9f7SJohn Marino task->prev_queue->next_queue = task;
180629ff9f7SJohn Marino }
181629ff9f7SJohn Marino else
182629ff9f7SJohn Marino {
183629ff9f7SJohn Marino task->next_queue = task;
184629ff9f7SJohn Marino task->prev_queue = task;
185629ff9f7SJohn Marino team->task_queue = task;
186629ff9f7SJohn Marino }
187629ff9f7SJohn Marino ++team->task_count;
188629ff9f7SJohn Marino gomp_team_barrier_set_task_pending (&team->barrier);
189629ff9f7SJohn Marino do_wake = team->task_running_count + !parent->in_tied_task
190629ff9f7SJohn Marino < team->nthreads;
191629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
192629ff9f7SJohn Marino if (do_wake)
193629ff9f7SJohn Marino gomp_team_barrier_wake (&team->barrier, 1);
194629ff9f7SJohn Marino }
195629ff9f7SJohn Marino }
196629ff9f7SJohn Marino
197629ff9f7SJohn Marino void
gomp_barrier_handle_tasks(gomp_barrier_state_t state)198629ff9f7SJohn Marino gomp_barrier_handle_tasks (gomp_barrier_state_t state)
199629ff9f7SJohn Marino {
200629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
201629ff9f7SJohn Marino struct gomp_team *team = thr->ts.team;
202629ff9f7SJohn Marino struct gomp_task *task = thr->task;
203629ff9f7SJohn Marino struct gomp_task *child_task = NULL;
204629ff9f7SJohn Marino struct gomp_task *to_free = NULL;
205629ff9f7SJohn Marino
206629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
207629ff9f7SJohn Marino if (gomp_barrier_last_thread (state))
208629ff9f7SJohn Marino {
209629ff9f7SJohn Marino if (team->task_count == 0)
210629ff9f7SJohn Marino {
211629ff9f7SJohn Marino gomp_team_barrier_done (&team->barrier, state);
212629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
213629ff9f7SJohn Marino gomp_team_barrier_wake (&team->barrier, 0);
214629ff9f7SJohn Marino return;
215629ff9f7SJohn Marino }
216629ff9f7SJohn Marino gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
217629ff9f7SJohn Marino }
218629ff9f7SJohn Marino
219629ff9f7SJohn Marino while (1)
220629ff9f7SJohn Marino {
221629ff9f7SJohn Marino if (team->task_queue != NULL)
222629ff9f7SJohn Marino {
223629ff9f7SJohn Marino struct gomp_task *parent;
224629ff9f7SJohn Marino
225629ff9f7SJohn Marino child_task = team->task_queue;
226629ff9f7SJohn Marino parent = child_task->parent;
227629ff9f7SJohn Marino if (parent && parent->children == child_task)
228629ff9f7SJohn Marino parent->children = child_task->next_child;
229629ff9f7SJohn Marino child_task->prev_queue->next_queue = child_task->next_queue;
230629ff9f7SJohn Marino child_task->next_queue->prev_queue = child_task->prev_queue;
231629ff9f7SJohn Marino if (child_task->next_queue != child_task)
232629ff9f7SJohn Marino team->task_queue = child_task->next_queue;
233629ff9f7SJohn Marino else
234629ff9f7SJohn Marino team->task_queue = NULL;
235629ff9f7SJohn Marino child_task->kind = GOMP_TASK_TIED;
236629ff9f7SJohn Marino team->task_running_count++;
237629ff9f7SJohn Marino if (team->task_count == team->task_running_count)
238629ff9f7SJohn Marino gomp_team_barrier_clear_task_pending (&team->barrier);
239629ff9f7SJohn Marino }
240629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
241629ff9f7SJohn Marino if (to_free)
242629ff9f7SJohn Marino {
243629ff9f7SJohn Marino gomp_finish_task (to_free);
244629ff9f7SJohn Marino free (to_free);
245629ff9f7SJohn Marino to_free = NULL;
246629ff9f7SJohn Marino }
247629ff9f7SJohn Marino if (child_task)
248629ff9f7SJohn Marino {
249629ff9f7SJohn Marino thr->task = child_task;
250629ff9f7SJohn Marino child_task->fn (child_task->fn_data);
251629ff9f7SJohn Marino thr->task = task;
252629ff9f7SJohn Marino }
253629ff9f7SJohn Marino else
254629ff9f7SJohn Marino return;
255629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
256629ff9f7SJohn Marino if (child_task)
257629ff9f7SJohn Marino {
258629ff9f7SJohn Marino struct gomp_task *parent = child_task->parent;
259629ff9f7SJohn Marino if (parent)
260629ff9f7SJohn Marino {
261629ff9f7SJohn Marino child_task->prev_child->next_child = child_task->next_child;
262629ff9f7SJohn Marino child_task->next_child->prev_child = child_task->prev_child;
263629ff9f7SJohn Marino if (parent->children == child_task)
264629ff9f7SJohn Marino {
265629ff9f7SJohn Marino if (child_task->next_child != child_task)
266629ff9f7SJohn Marino parent->children = child_task->next_child;
267629ff9f7SJohn Marino else
268629ff9f7SJohn Marino {
269*5ce9237cSJohn Marino /* We access task->children in GOMP_taskwait
270*5ce9237cSJohn Marino outside of the task lock mutex region, so
271*5ce9237cSJohn Marino need a release barrier here to ensure memory
272*5ce9237cSJohn Marino written by child_task->fn above is flushed
273*5ce9237cSJohn Marino before the NULL is written. */
274*5ce9237cSJohn Marino __atomic_store_n (&parent->children, NULL,
275*5ce9237cSJohn Marino MEMMODEL_RELEASE);
276629ff9f7SJohn Marino if (parent->in_taskwait)
277629ff9f7SJohn Marino gomp_sem_post (&parent->taskwait_sem);
278629ff9f7SJohn Marino }
279629ff9f7SJohn Marino }
280629ff9f7SJohn Marino }
281629ff9f7SJohn Marino gomp_clear_parent (child_task->children);
282629ff9f7SJohn Marino to_free = child_task;
283629ff9f7SJohn Marino child_task = NULL;
284629ff9f7SJohn Marino team->task_running_count--;
285629ff9f7SJohn Marino if (--team->task_count == 0
286629ff9f7SJohn Marino && gomp_team_barrier_waiting_for_tasks (&team->barrier))
287629ff9f7SJohn Marino {
288629ff9f7SJohn Marino gomp_team_barrier_done (&team->barrier, state);
289629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
290629ff9f7SJohn Marino gomp_team_barrier_wake (&team->barrier, 0);
291629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
292629ff9f7SJohn Marino }
293629ff9f7SJohn Marino }
294629ff9f7SJohn Marino }
295629ff9f7SJohn Marino }
296629ff9f7SJohn Marino
297629ff9f7SJohn Marino /* Called when encountering a taskwait directive. */
298629ff9f7SJohn Marino
299629ff9f7SJohn Marino void
GOMP_taskwait(void)300629ff9f7SJohn Marino GOMP_taskwait (void)
301629ff9f7SJohn Marino {
302629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
303629ff9f7SJohn Marino struct gomp_team *team = thr->ts.team;
304629ff9f7SJohn Marino struct gomp_task *task = thr->task;
305629ff9f7SJohn Marino struct gomp_task *child_task = NULL;
306629ff9f7SJohn Marino struct gomp_task *to_free = NULL;
307629ff9f7SJohn Marino
308*5ce9237cSJohn Marino /* The acquire barrier on load of task->children here synchronizes
309*5ce9237cSJohn Marino with the write of a NULL in gomp_barrier_handle_tasks. It is
310*5ce9237cSJohn Marino not necessary that we synchronize with other non-NULL writes at
311*5ce9237cSJohn Marino this point, but we must ensure that all writes to memory by a
312*5ce9237cSJohn Marino child thread task work function are seen before we exit from
313*5ce9237cSJohn Marino GOMP_taskwait. */
314*5ce9237cSJohn Marino if (task == NULL
315*5ce9237cSJohn Marino || __atomic_load_n (&task->children, MEMMODEL_ACQUIRE) == NULL)
316629ff9f7SJohn Marino return;
317629ff9f7SJohn Marino
318629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
319629ff9f7SJohn Marino while (1)
320629ff9f7SJohn Marino {
321629ff9f7SJohn Marino if (task->children == NULL)
322629ff9f7SJohn Marino {
323629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
324629ff9f7SJohn Marino if (to_free)
325629ff9f7SJohn Marino {
326629ff9f7SJohn Marino gomp_finish_task (to_free);
327629ff9f7SJohn Marino free (to_free);
328629ff9f7SJohn Marino }
329629ff9f7SJohn Marino return;
330629ff9f7SJohn Marino }
331629ff9f7SJohn Marino if (task->children->kind == GOMP_TASK_WAITING)
332629ff9f7SJohn Marino {
333629ff9f7SJohn Marino child_task = task->children;
334629ff9f7SJohn Marino task->children = child_task->next_child;
335629ff9f7SJohn Marino child_task->prev_queue->next_queue = child_task->next_queue;
336629ff9f7SJohn Marino child_task->next_queue->prev_queue = child_task->prev_queue;
337629ff9f7SJohn Marino if (team->task_queue == child_task)
338629ff9f7SJohn Marino {
339629ff9f7SJohn Marino if (child_task->next_queue != child_task)
340629ff9f7SJohn Marino team->task_queue = child_task->next_queue;
341629ff9f7SJohn Marino else
342629ff9f7SJohn Marino team->task_queue = NULL;
343629ff9f7SJohn Marino }
344629ff9f7SJohn Marino child_task->kind = GOMP_TASK_TIED;
345629ff9f7SJohn Marino team->task_running_count++;
346629ff9f7SJohn Marino if (team->task_count == team->task_running_count)
347629ff9f7SJohn Marino gomp_team_barrier_clear_task_pending (&team->barrier);
348629ff9f7SJohn Marino }
349629ff9f7SJohn Marino else
350629ff9f7SJohn Marino /* All tasks we are waiting for are already running
351629ff9f7SJohn Marino in other threads. Wait for them. */
352629ff9f7SJohn Marino task->in_taskwait = true;
353629ff9f7SJohn Marino gomp_mutex_unlock (&team->task_lock);
354629ff9f7SJohn Marino if (to_free)
355629ff9f7SJohn Marino {
356629ff9f7SJohn Marino gomp_finish_task (to_free);
357629ff9f7SJohn Marino free (to_free);
358629ff9f7SJohn Marino to_free = NULL;
359629ff9f7SJohn Marino }
360629ff9f7SJohn Marino if (child_task)
361629ff9f7SJohn Marino {
362629ff9f7SJohn Marino thr->task = child_task;
363629ff9f7SJohn Marino child_task->fn (child_task->fn_data);
364629ff9f7SJohn Marino thr->task = task;
365629ff9f7SJohn Marino }
366629ff9f7SJohn Marino else
367629ff9f7SJohn Marino {
368629ff9f7SJohn Marino gomp_sem_wait (&task->taskwait_sem);
369629ff9f7SJohn Marino task->in_taskwait = false;
370629ff9f7SJohn Marino return;
371629ff9f7SJohn Marino }
372629ff9f7SJohn Marino gomp_mutex_lock (&team->task_lock);
373629ff9f7SJohn Marino if (child_task)
374629ff9f7SJohn Marino {
375629ff9f7SJohn Marino child_task->prev_child->next_child = child_task->next_child;
376629ff9f7SJohn Marino child_task->next_child->prev_child = child_task->prev_child;
377629ff9f7SJohn Marino if (task->children == child_task)
378629ff9f7SJohn Marino {
379629ff9f7SJohn Marino if (child_task->next_child != child_task)
380629ff9f7SJohn Marino task->children = child_task->next_child;
381629ff9f7SJohn Marino else
382629ff9f7SJohn Marino task->children = NULL;
383629ff9f7SJohn Marino }
384629ff9f7SJohn Marino gomp_clear_parent (child_task->children);
385629ff9f7SJohn Marino to_free = child_task;
386629ff9f7SJohn Marino child_task = NULL;
387629ff9f7SJohn Marino team->task_count--;
388629ff9f7SJohn Marino team->task_running_count--;
389629ff9f7SJohn Marino }
390629ff9f7SJohn Marino }
391629ff9f7SJohn Marino }
392629ff9f7SJohn Marino
393629ff9f7SJohn Marino /* Called when encountering a taskyield directive. */
394629ff9f7SJohn Marino
395629ff9f7SJohn Marino void
GOMP_taskyield(void)396629ff9f7SJohn Marino GOMP_taskyield (void)
397629ff9f7SJohn Marino {
398629ff9f7SJohn Marino /* Nothing at the moment. */
399629ff9f7SJohn Marino }
400629ff9f7SJohn Marino
401629ff9f7SJohn Marino int
omp_in_final(void)402629ff9f7SJohn Marino omp_in_final (void)
403629ff9f7SJohn Marino {
404629ff9f7SJohn Marino struct gomp_thread *thr = gomp_thread ();
405629ff9f7SJohn Marino return thr->task && thr->task->final_task;
406629ff9f7SJohn Marino }
407629ff9f7SJohn Marino
408629ff9f7SJohn Marino ialias (omp_in_final)
409