1 /* Copyright (C) 2007, 2008, 2009 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 General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
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 General Public License for
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This file handles the maintainence of tasks in response to task
26 creation and termination. */
33 /* Create a new task data structure. */
36 gomp_init_task (struct gomp_task
*task
, struct gomp_task
*parent_task
,
37 struct gomp_task_icv
*prev_icv
)
39 task
->parent
= parent_task
;
40 task
->icv
= *prev_icv
;
41 task
->kind
= GOMP_TASK_IMPLICIT
;
42 task
->in_taskwait
= false;
43 task
->in_tied_task
= false;
44 task
->children
= NULL
;
45 gomp_sem_init (&task
->taskwait_sem
, 0);
48 /* Clean up a task, after completing it. */
53 struct gomp_thread
*thr
= gomp_thread ();
54 struct gomp_task
*task
= thr
->task
;
56 gomp_finish_task (task
);
57 thr
->task
= task
->parent
;
61 gomp_clear_parent (struct gomp_task
*children
)
63 struct gomp_task
*task
= children
;
69 task
= task
->next_child
;
71 while (task
!= children
);
74 /* Called when encountering an explicit task directive. If IF_CLAUSE is
75 false, then we must not delay in executing the task. If UNTIED is true,
76 then the task may be executed by any member of the team. */
79 GOMP_task (void (*fn
) (void *), void *data
, void (*cpyfn
) (void *, void *),
80 long arg_size
, long arg_align
, bool if_clause
,
81 unsigned flags
__attribute__((unused
)))
83 struct gomp_thread
*thr
= gomp_thread ();
84 struct gomp_team
*team
= thr
->ts
.team
;
86 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
87 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
88 tied to one thread all the time. This means UNTIED tasks must be
89 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
90 might be running on different thread than FN. */
97 if (!if_clause
|| team
== NULL
98 || team
->task_count
> 64 * team
->nthreads
)
100 struct gomp_task task
;
102 gomp_init_task (&task
, thr
->task
, gomp_icv (false));
103 task
.kind
= GOMP_TASK_IFFALSE
;
105 task
.in_tied_task
= thr
->task
->in_tied_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));
119 gomp_mutex_lock (&team
->task_lock
);
120 gomp_clear_parent (task
.children
);
121 gomp_mutex_unlock (&team
->task_lock
);
127 struct gomp_task
*task
;
128 struct gomp_task
*parent
= thr
->task
;
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 task
->in_tied_task
= parent
->in_tied_task
;
142 memcpy (arg
, data
, arg_size
);
144 task
->kind
= GOMP_TASK_WAITING
;
147 task
->in_tied_task
= true;
148 gomp_mutex_lock (&team
->task_lock
);
149 if (parent
->children
)
151 task
->next_child
= parent
->children
;
152 task
->prev_child
= parent
->children
->prev_child
;
153 task
->next_child
->prev_child
= task
;
154 task
->prev_child
->next_child
= task
;
158 task
->next_child
= task
;
159 task
->prev_child
= task
;
161 parent
->children
= task
;
162 if (team
->task_queue
)
164 task
->next_queue
= team
->task_queue
;
165 task
->prev_queue
= team
->task_queue
->prev_queue
;
166 task
->next_queue
->prev_queue
= task
;
167 task
->prev_queue
->next_queue
= task
;
171 task
->next_queue
= task
;
172 task
->prev_queue
= task
;
173 team
->task_queue
= task
;
176 gomp_team_barrier_set_task_pending (&team
->barrier
);
177 do_wake
= team
->task_running_count
+ !parent
->in_tied_task
179 gomp_mutex_unlock (&team
->task_lock
);
181 gomp_team_barrier_wake (&team
->barrier
, 1);
186 gomp_barrier_handle_tasks (gomp_barrier_state_t state
)
188 struct gomp_thread
*thr
= gomp_thread ();
189 struct gomp_team
*team
= thr
->ts
.team
;
190 struct gomp_task
*task
= thr
->task
;
191 struct gomp_task
*child_task
= NULL
;
192 struct gomp_task
*to_free
= NULL
;
194 gomp_mutex_lock (&team
->task_lock
);
195 if (gomp_barrier_last_thread (state
))
197 if (team
->task_count
== 0)
199 gomp_team_barrier_done (&team
->barrier
, state
);
200 gomp_mutex_unlock (&team
->task_lock
);
201 gomp_team_barrier_wake (&team
->barrier
, 0);
204 gomp_team_barrier_set_waiting_for_tasks (&team
->barrier
);
209 if (team
->task_queue
!= NULL
)
211 struct gomp_task
*parent
;
213 child_task
= team
->task_queue
;
214 parent
= child_task
->parent
;
215 if (parent
&& parent
->children
== child_task
)
216 parent
->children
= child_task
->next_child
;
217 child_task
->prev_queue
->next_queue
= child_task
->next_queue
;
218 child_task
->next_queue
->prev_queue
= child_task
->prev_queue
;
219 if (child_task
->next_queue
!= child_task
)
220 team
->task_queue
= child_task
->next_queue
;
222 team
->task_queue
= NULL
;
223 child_task
->kind
= GOMP_TASK_TIED
;
224 team
->task_running_count
++;
225 if (team
->task_count
== team
->task_running_count
)
226 gomp_team_barrier_clear_task_pending (&team
->barrier
);
228 gomp_mutex_unlock (&team
->task_lock
);
231 gomp_finish_task (to_free
);
237 thr
->task
= child_task
;
238 child_task
->fn (child_task
->fn_data
);
243 gomp_mutex_lock (&team
->task_lock
);
246 struct gomp_task
*parent
= child_task
->parent
;
249 child_task
->prev_child
->next_child
= child_task
->next_child
;
250 child_task
->next_child
->prev_child
= child_task
->prev_child
;
251 if (parent
->children
== child_task
)
253 if (child_task
->next_child
!= child_task
)
254 parent
->children
= child_task
->next_child
;
257 parent
->children
= NULL
;
258 if (parent
->in_taskwait
)
259 gomp_sem_post (&parent
->taskwait_sem
);
263 gomp_clear_parent (child_task
->children
);
264 to_free
= child_task
;
266 team
->task_running_count
--;
267 if (--team
->task_count
== 0
268 && gomp_team_barrier_waiting_for_tasks (&team
->barrier
))
270 gomp_team_barrier_done (&team
->barrier
, state
);
271 gomp_mutex_unlock (&team
->task_lock
);
272 gomp_team_barrier_wake (&team
->barrier
, 0);
278 /* Called when encountering a taskwait directive. */
283 struct gomp_thread
*thr
= gomp_thread ();
284 struct gomp_team
*team
= thr
->ts
.team
;
285 struct gomp_task
*task
= thr
->task
;
286 struct gomp_task
*child_task
= NULL
;
287 struct gomp_task
*to_free
= NULL
;
289 if (task
== NULL
|| task
->children
== NULL
)
291 gomp_mutex_lock (&team
->task_lock
);
294 if (task
->children
== NULL
)
296 gomp_mutex_unlock (&team
->task_lock
);
299 gomp_finish_task (to_free
);
304 if (task
->children
->kind
== GOMP_TASK_WAITING
)
306 child_task
= task
->children
;
307 task
->children
= child_task
->next_child
;
308 child_task
->prev_queue
->next_queue
= child_task
->next_queue
;
309 child_task
->next_queue
->prev_queue
= child_task
->prev_queue
;
310 if (team
->task_queue
== child_task
)
312 if (child_task
->next_queue
!= child_task
)
313 team
->task_queue
= child_task
->next_queue
;
315 team
->task_queue
= NULL
;
317 child_task
->kind
= GOMP_TASK_TIED
;
318 team
->task_running_count
++;
319 if (team
->task_count
== team
->task_running_count
)
320 gomp_team_barrier_clear_task_pending (&team
->barrier
);
323 /* All tasks we are waiting for are already running
324 in other threads. Wait for them. */
325 task
->in_taskwait
= true;
326 gomp_mutex_unlock (&team
->task_lock
);
329 gomp_finish_task (to_free
);
335 thr
->task
= child_task
;
336 child_task
->fn (child_task
->fn_data
);
341 gomp_sem_wait (&task
->taskwait_sem
);
342 task
->in_taskwait
= false;
345 gomp_mutex_lock (&team
->task_lock
);
348 child_task
->prev_child
->next_child
= child_task
->next_child
;
349 child_task
->next_child
->prev_child
= child_task
->prev_child
;
350 if (task
->children
== child_task
)
352 if (child_task
->next_child
!= child_task
)
353 task
->children
= child_task
->next_child
;
355 task
->children
= NULL
;
357 gomp_clear_parent (child_task
->children
);
358 to_free
= child_task
;
361 team
->task_running_count
--;