OSDN Git Service

* include/backward/hashtable.h (_S_num_primes): Change to 29.
[pf3gnuchains/gcc-fork.git] / libgomp / task.c
1 /* Copyright (C) 2007, 2008 Free Software Foundation, Inc.
2    Contributed by Richard Henderson <rth@redhat.com>.
3
4    This file is part of the GNU OpenMP Library (libgomp).
5
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.
10
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.
15
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.  */
20
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.  */
27
28 /* This file handles the maintainence of tasks in response to task
29    creation and termination.  */
30
31 #include "libgomp.h"
32 #include <stdlib.h>
33 #include <string.h>
34
35
36 /* Create a new task data structure.  */
37
38 void
39 gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
40                 struct gomp_task_icv *prev_icv)
41 {
42   task->parent = parent_task;
43   task->icv = *prev_icv;
44   task->kind = GOMP_TASK_IMPLICIT;
45   task->in_taskwait = false;
46   task->in_tied_task = false;
47   task->children = NULL;
48   gomp_sem_init (&task->taskwait_sem, 0);
49 }
50
51 /* Clean up a task, after completing it.  */
52
53 void
54 gomp_end_task (void)
55 {
56   struct gomp_thread *thr = gomp_thread ();
57   struct gomp_task *task = thr->task;
58
59   gomp_finish_task (task);
60   thr->task = task->parent;
61 }
62
63 static inline void
64 gomp_clear_parent (struct gomp_task *children)
65 {
66   struct gomp_task *task = children;
67
68   if (task)
69     do
70       {
71         task->parent = NULL;
72         task = task->next_child;
73       }
74     while (task != children);
75 }
76
77 /* Called when encountering an explicit task directive.  If IF_CLAUSE is
78    false, then we must not delay in executing the task.  If UNTIED is true,
79    then the task may be executed by any member of the team.  */
80
81 void
82 GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
83            long arg_size, long arg_align, bool if_clause,
84            unsigned flags __attribute__((unused)))
85 {
86   struct gomp_thread *thr = gomp_thread ();
87   struct gomp_team *team = thr->ts.team;
88
89 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
90   /* If pthread_mutex_* is used for omp_*lock*, then each task must be
91      tied to one thread all the time.  This means UNTIED tasks must be
92      tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
93      might be running on different thread than FN.  */
94   if (cpyfn)
95     if_clause = false;
96   if (flags & 1)
97     flags &= ~1;
98 #endif
99
100   if (!if_clause || team == NULL
101       || team->task_count > 64 * team->nthreads)
102     {
103       struct gomp_task task;
104
105       gomp_init_task (&task, thr->task, gomp_icv (false));
106       task.kind = GOMP_TASK_IFFALSE;
107       if (thr->task)
108         task.in_tied_task = thr->task->in_tied_task;
109       thr->task = &task;
110       if (__builtin_expect (cpyfn != NULL, 0))
111         {
112           char buf[arg_size + arg_align - 1];
113           char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
114                                 & ~(uintptr_t) (arg_align - 1));
115           cpyfn (arg, data);
116           fn (arg);
117         }
118       else
119         fn (data);
120       if (task.children)
121         {
122           gomp_mutex_lock (&team->task_lock);
123           gomp_clear_parent (task.children);
124           gomp_mutex_unlock (&team->task_lock);
125         }
126       gomp_end_task ();
127     }
128   else
129     {
130       struct gomp_task *task;
131       struct gomp_task *parent = thr->task;
132       char *arg;
133       bool do_wake;
134
135       task = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
136       arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
137                       & ~(uintptr_t) (arg_align - 1));
138       gomp_init_task (task, parent, gomp_icv (false));
139       task->kind = GOMP_TASK_IFFALSE;
140       task->in_tied_task = parent->in_tied_task;
141       thr->task = task;
142       if (cpyfn)
143         cpyfn (arg, data);
144       else
145         memcpy (arg, data, arg_size);
146       thr->task = parent;
147       task->kind = GOMP_TASK_WAITING;
148       task->fn = fn;
149       task->fn_data = arg;
150       task->in_tied_task = true;
151       gomp_mutex_lock (&team->task_lock);
152       if (parent->children)
153         {
154           task->next_child = parent->children;
155           task->prev_child = parent->children->prev_child;
156           task->next_child->prev_child = task;
157           task->prev_child->next_child = task;
158         }
159       else
160         {
161           task->next_child = task;
162           task->prev_child = task;
163         }
164       parent->children = task;
165       if (team->task_queue)
166         {
167           task->next_queue = team->task_queue;
168           task->prev_queue = team->task_queue->prev_queue;
169           task->next_queue->prev_queue = task;
170           task->prev_queue->next_queue = task;
171         }
172       else
173         {
174           task->next_queue = task;
175           task->prev_queue = task;
176           team->task_queue = task;
177         }
178       ++team->task_count;
179       gomp_team_barrier_set_task_pending (&team->barrier);
180       do_wake = team->task_running_count + !parent->in_tied_task
181                 < team->nthreads;
182       gomp_mutex_unlock (&team->task_lock);
183       if (do_wake)
184         gomp_team_barrier_wake (&team->barrier, 1);
185     }
186 }
187
188 void
189 gomp_barrier_handle_tasks (gomp_barrier_state_t state)
190 {
191   struct gomp_thread *thr = gomp_thread ();
192   struct gomp_team *team = thr->ts.team;
193   struct gomp_task *task = thr->task;
194   struct gomp_task *child_task = NULL;
195   struct gomp_task *to_free = NULL;
196
197   gomp_mutex_lock (&team->task_lock);
198   if (gomp_barrier_last_thread (state))
199     {
200       if (team->task_count == 0)
201         {
202           gomp_team_barrier_done (&team->barrier, state);
203           gomp_mutex_unlock (&team->task_lock);
204           gomp_team_barrier_wake (&team->barrier, 0);
205           return;
206         }
207       gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
208     }
209
210   while (1)
211     {
212       if (team->task_queue != NULL)
213         {
214           struct gomp_task *parent;
215
216           child_task = team->task_queue;
217           parent = child_task->parent;
218           if (parent && parent->children == child_task)
219             parent->children = child_task->next_child;
220           child_task->prev_queue->next_queue = child_task->next_queue;
221           child_task->next_queue->prev_queue = child_task->prev_queue;
222           if (child_task->next_queue != child_task)
223             team->task_queue = child_task->next_queue;
224           else
225             team->task_queue = NULL;
226           child_task->kind = GOMP_TASK_TIED;
227           team->task_running_count++;
228           if (team->task_count == team->task_running_count)
229             gomp_team_barrier_clear_task_pending (&team->barrier);
230         }
231       gomp_mutex_unlock (&team->task_lock);
232       if (to_free)
233         {
234           gomp_finish_task (to_free);
235           free (to_free);
236           to_free = NULL;
237         }
238       if (child_task)
239         {
240           thr->task = child_task;
241           child_task->fn (child_task->fn_data);
242           thr->task = task;
243         }
244       else
245         return;
246       gomp_mutex_lock (&team->task_lock);
247       if (child_task)
248         {
249           struct gomp_task *parent = child_task->parent;
250           if (parent)
251             {
252               child_task->prev_child->next_child = child_task->next_child;
253               child_task->next_child->prev_child = child_task->prev_child;
254               if (parent->children == child_task)
255                 {
256                   if (child_task->next_child != child_task)
257                     parent->children = child_task->next_child;
258                   else
259                     {
260                       parent->children = NULL;
261                       if (parent->in_taskwait)
262                         gomp_sem_post (&parent->taskwait_sem);
263                     }
264                 }
265             }
266           gomp_clear_parent (child_task->children);
267           to_free = child_task;
268           child_task = NULL;
269           team->task_running_count--;
270           if (--team->task_count == 0
271               && gomp_team_barrier_waiting_for_tasks (&team->barrier))
272             {
273               gomp_team_barrier_done (&team->barrier, state);
274               gomp_mutex_unlock (&team->task_lock);
275               gomp_team_barrier_wake (&team->barrier, 0);
276             }
277         }
278     }
279 }
280
281 /* Called when encountering a taskwait directive.  */
282
283 void
284 GOMP_taskwait (void)
285 {
286   struct gomp_thread *thr = gomp_thread ();
287   struct gomp_team *team = thr->ts.team;
288   struct gomp_task *task = thr->task;
289   struct gomp_task *child_task = NULL;
290   struct gomp_task *to_free = NULL;
291
292   if (task == NULL || task->children == NULL)
293     return;
294   gomp_mutex_lock (&team->task_lock);
295   while (1)
296     {
297       if (task->children == NULL)
298         {
299           gomp_mutex_unlock (&team->task_lock);
300           if (to_free)
301             {
302               gomp_finish_task (to_free);
303               free (to_free);
304             }
305           return;
306         }
307       if (task->children->kind == GOMP_TASK_WAITING)
308         {
309           child_task = task->children;
310           task->children = child_task->next_child;
311           child_task->prev_queue->next_queue = child_task->next_queue;
312           child_task->next_queue->prev_queue = child_task->prev_queue;
313           if (team->task_queue == child_task)
314             {
315               if (child_task->next_queue != child_task)
316                 team->task_queue = child_task->next_queue;
317               else
318                 team->task_queue = NULL;
319             }
320           child_task->kind = GOMP_TASK_TIED;
321           team->task_running_count++;
322           if (team->task_count == team->task_running_count)
323             gomp_team_barrier_clear_task_pending (&team->barrier);
324         }
325       else
326         /* All tasks we are waiting for are already running
327            in other threads.  Wait for them.  */
328         task->in_taskwait = true;
329       gomp_mutex_unlock (&team->task_lock);
330       if (to_free)
331         {
332           gomp_finish_task (to_free);
333           free (to_free);
334           to_free = NULL;
335         }
336       if (child_task)
337         {
338           thr->task = child_task;
339           child_task->fn (child_task->fn_data);
340           thr->task = task;
341         }
342       else
343         {
344           gomp_sem_wait (&task->taskwait_sem);
345           task->in_taskwait = false;
346           return;
347         }
348       gomp_mutex_lock (&team->task_lock);
349       if (child_task)
350         {
351           child_task->prev_child->next_child = child_task->next_child;
352           child_task->next_child->prev_child = child_task->prev_child;
353           if (task->children == child_task)
354             {
355               if (child_task->next_child != child_task)
356                 task->children = child_task->next_child;
357               else
358                 task->children = NULL;
359             }
360           gomp_clear_parent (child_task->children);
361           to_free = child_task;
362           child_task = NULL;
363           team->task_count--;
364           team->task_running_count--;
365         }
366     }
367 }