* utils.c (create_subprog_decl): If this is for the 'main' entry
[official-gcc.git] / libgomp / task.c
blob903948ceca314631e3f30b81dbb880c7d610f7de
1 /* Copyright (C) 2007, 2008 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
14 more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with libgomp; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 /* As a special exception, if you link this library with other files, some
22 of which are compiled with GCC, to produce an executable, this library
23 does not by itself cause the resulting executable to be covered by the
24 GNU General Public License. This exception does not however invalidate
25 any other reasons why the executable file might be covered by the GNU
26 General Public License. */
28 /* This file handles the maintainence of tasks in response to task
29 creation and termination. */
31 #include "libgomp.h"
32 #include <stdlib.h>
33 #include <string.h>
36 /* Create a new task data structure. */
38 void
39 gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
40 struct gomp_task_icv *prev_icv)
42 task->parent = parent_task;
43 task->icv = *prev_icv;
44 task->kind = GOMP_TASK_IMPLICIT;
45 task->in_taskwait = false;
46 task->children = NULL;
47 gomp_sem_init (&task->taskwait_sem, 0);
50 /* Clean up a task, after completing it. */
52 void
53 gomp_end_task (void)
55 struct gomp_thread *thr = gomp_thread ();
56 struct gomp_task *task = thr->task;
58 gomp_finish_task (task);
59 thr->task = task->parent;
62 static inline void
63 gomp_clear_parent (struct gomp_task *children)
65 struct gomp_task *task = children;
67 if (task)
70 task->parent = NULL;
71 task = task->next_child;
73 while (task != children);
76 /* Called when encountering an explicit task directive. If IF_CLAUSE is
77 false, then we must not delay in executing the task. If UNTIED is true,
78 then the task may be executed by any member of the team. */
80 void
81 GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
82 long arg_size, long arg_align, bool if_clause,
83 unsigned flags __attribute__((unused)))
85 struct gomp_thread *thr = gomp_thread ();
86 struct gomp_team *team = thr->ts.team;
88 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
89 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
90 tied to one thread all the time. This means UNTIED tasks must be
91 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
92 might be running on different thread than FN. */
93 if (cpyfn)
94 if_clause = false;
95 if (flags & 1)
96 flags &= ~1;
97 #endif
99 if (!if_clause || team == NULL
100 || team->task_count > 64 * team->nthreads)
102 struct gomp_task task;
104 gomp_init_task (&task, thr->task, gomp_icv (false));
105 task.kind = GOMP_TASK_IFFALSE;
106 thr->task = &task;
107 if (__builtin_expect (cpyfn != NULL, 0))
109 char buf[arg_size + arg_align - 1];
110 char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
111 & ~(uintptr_t) (arg_align - 1));
112 cpyfn (arg, data);
113 fn (arg);
115 else
116 fn (data);
117 if (task.children)
119 gomp_mutex_lock (&team->task_lock);
120 gomp_clear_parent (task.children);
121 gomp_mutex_unlock (&team->task_lock);
123 gomp_end_task ();
125 else
127 struct gomp_task *task;
128 struct gomp_task *parent = thr->task;
129 char *arg;
130 bool do_wake;
132 task = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
133 arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
134 & ~(uintptr_t) (arg_align - 1));
135 gomp_init_task (task, parent, gomp_icv (false));
136 task->kind = GOMP_TASK_IFFALSE;
137 thr->task = task;
138 if (cpyfn)
139 cpyfn (arg, data);
140 else
141 memcpy (arg, data, arg_size);
142 thr->task = parent;
143 task->kind = GOMP_TASK_WAITING;
144 task->fn = fn;
145 task->fn_data = arg;
146 gomp_mutex_lock (&team->task_lock);
147 if (parent->children)
149 task->next_child = parent->children;
150 task->prev_child = parent->children->prev_child;
151 task->next_child->prev_child = task;
152 task->prev_child->next_child = task;
154 else
156 task->next_child = task;
157 task->prev_child = task;
159 parent->children = task;
160 if (team->task_queue)
162 task->next_queue = team->task_queue;
163 task->prev_queue = team->task_queue->prev_queue;
164 task->next_queue->prev_queue = task;
165 task->prev_queue->next_queue = task;
167 else
169 task->next_queue = task;
170 task->prev_queue = task;
171 team->task_queue = task;
173 if (team->task_count++ == 0)
174 gomp_team_barrier_set_task_pending (&team->barrier);
175 do_wake = team->task_running_count < team->nthreads;
176 gomp_mutex_unlock (&team->task_lock);
177 if (do_wake)
178 gomp_team_barrier_wake (&team->barrier, 1);
182 void
183 gomp_barrier_handle_tasks (gomp_barrier_state_t state)
185 struct gomp_thread *thr = gomp_thread ();
186 struct gomp_team *team = thr->ts.team;
187 struct gomp_task *task = thr->task;
188 struct gomp_task *child_task = NULL;
189 struct gomp_task *to_free = NULL;
191 gomp_mutex_lock (&team->task_lock);
192 if (gomp_barrier_last_thread (state))
194 if (team->task_count == 0)
196 gomp_team_barrier_done (&team->barrier, state);
197 gomp_mutex_unlock (&team->task_lock);
198 gomp_team_barrier_wake (&team->barrier, 0);
199 return;
201 gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
204 while (1)
206 if (team->task_queue != NULL)
208 struct gomp_task *parent;
210 child_task = team->task_queue;
211 parent = child_task->parent;
212 if (parent && parent->children == child_task)
213 parent->children = child_task->next_child;
214 child_task->prev_queue->next_queue = child_task->next_queue;
215 child_task->next_queue->prev_queue = child_task->prev_queue;
216 if (child_task->next_queue != child_task)
217 team->task_queue = child_task->next_queue;
218 else
219 team->task_queue = NULL;
220 child_task->kind = GOMP_TASK_TIED;
221 team->task_running_count++;
222 if (team->task_count == team->task_running_count)
223 gomp_team_barrier_clear_task_pending (&team->barrier);
225 gomp_mutex_unlock (&team->task_lock);
226 if (to_free)
228 gomp_finish_task (to_free);
229 free (to_free);
230 to_free = NULL;
232 if (child_task)
234 thr->task = child_task;
235 child_task->fn (child_task->fn_data);
236 thr->task = task;
238 else
239 return;
240 gomp_mutex_lock (&team->task_lock);
241 if (child_task)
243 struct gomp_task *parent = child_task->parent;
244 if (parent)
246 child_task->prev_child->next_child = child_task->next_child;
247 child_task->next_child->prev_child = child_task->prev_child;
248 if (parent->children == child_task)
250 if (child_task->next_child != child_task)
251 parent->children = child_task->next_child;
252 else
254 parent->children = NULL;
255 if (parent->in_taskwait)
256 gomp_sem_post (&parent->taskwait_sem);
260 gomp_clear_parent (child_task->children);
261 to_free = child_task;
262 child_task = NULL;
263 team->task_running_count--;
264 if (--team->task_count == 0
265 && gomp_team_barrier_waiting_for_tasks (&team->barrier))
267 gomp_team_barrier_done (&team->barrier, state);
268 gomp_mutex_unlock (&team->task_lock);
269 gomp_team_barrier_wake (&team->barrier, 0);
275 /* Called when encountering a taskwait directive. */
277 void
278 GOMP_taskwait (void)
280 struct gomp_thread *thr = gomp_thread ();
281 struct gomp_team *team = thr->ts.team;
282 struct gomp_task *task = thr->task;
283 struct gomp_task *child_task = NULL;
284 struct gomp_task *to_free = NULL;
286 if (task == NULL || task->children == NULL)
287 return;
288 gomp_mutex_lock (&team->task_lock);
289 while (1)
291 if (task->children == NULL)
293 gomp_mutex_unlock (&team->task_lock);
294 if (to_free)
296 gomp_finish_task (to_free);
297 free (to_free);
299 return;
301 if (task->children->kind == GOMP_TASK_WAITING)
303 child_task = task->children;
304 task->children = child_task->next_child;
305 child_task->prev_queue->next_queue = child_task->next_queue;
306 child_task->next_queue->prev_queue = child_task->prev_queue;
307 if (team->task_queue == child_task)
309 if (child_task->next_queue != child_task)
310 team->task_queue = child_task->next_queue;
311 else
312 team->task_queue = NULL;
314 child_task->kind = GOMP_TASK_TIED;
315 team->task_running_count++;
316 if (team->task_count == team->task_running_count)
317 gomp_team_barrier_clear_task_pending (&team->barrier);
319 else
320 /* All tasks we are waiting for are already running
321 in other threads. Wait for them. */
322 task->in_taskwait = true;
323 gomp_mutex_unlock (&team->task_lock);
324 if (to_free)
326 gomp_finish_task (to_free);
327 free (to_free);
328 to_free = NULL;
330 if (child_task)
332 thr->task = child_task;
333 child_task->fn (child_task->fn_data);
334 thr->task = task;
336 else
338 gomp_sem_wait (&task->taskwait_sem);
339 task->in_taskwait = false;
340 return;
342 gomp_mutex_lock (&team->task_lock);
343 if (child_task)
345 child_task->prev_child->next_child = child_task->next_child;
346 child_task->next_child->prev_child = child_task->prev_child;
347 if (task->children == child_task)
349 if (child_task->next_child != child_task)
350 task->children = child_task->next_child;
351 else
352 task->children = NULL;
354 gomp_clear_parent (child_task->children);
355 to_free = child_task;
356 child_task = NULL;
357 team->task_count--;
358 team->task_running_count--;