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
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. */
36 /* Create a new task data structure. */
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. */
55 struct gomp_thread
*thr
= gomp_thread ();
56 struct gomp_task
*task
= thr
->task
;
58 gomp_finish_task (task
);
59 thr
->task
= task
->parent
;
63 gomp_clear_parent (struct gomp_task
*children
)
65 struct gomp_task
*task
= children
;
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. */
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. */
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
;
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
;
141 memcpy (arg
, data
, arg_size
);
143 task
->kind
= GOMP_TASK_WAITING
;
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
;
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
;
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
);
178 gomp_team_barrier_wake (&team
->barrier
, 1);
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);
201 gomp_team_barrier_set_waiting_for_tasks (&team
->barrier
);
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
;
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
);
228 gomp_finish_task (to_free
);
234 thr
->task
= child_task
;
235 child_task
->fn (child_task
->fn_data
);
240 gomp_mutex_lock (&team
->task_lock
);
243 struct gomp_task
*parent
= child_task
->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
;
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
;
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. */
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
)
288 gomp_mutex_lock (&team
->task_lock
);
291 if (task
->children
== NULL
)
293 gomp_mutex_unlock (&team
->task_lock
);
296 gomp_finish_task (to_free
);
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
;
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
);
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
);
326 gomp_finish_task (to_free
);
332 thr
->task
= child_task
;
333 child_task
->fn (child_task
->fn_data
);
338 gomp_sem_wait (&task
->taskwait_sem
);
339 task
->in_taskwait
= false;
342 gomp_mutex_lock (&team
->task_lock
);
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
;
352 task
->children
= NULL
;
354 gomp_clear_parent (child_task
->children
);
355 to_free
= child_task
;
358 team
->task_running_count
--;