source: trunk/sys/libgomp/task.c @ 8

Last change on this file since 8 was 1, checked in by alain, 8 years ago

First import

File size: 9.9 KB
Line 
1/* Copyright (C) 2007, 2008, 2009 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 General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   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 General Public License for
14   more details.
15
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.
19
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/>.  */
24
25/* This file handles the maintainence of tasks in response to task
26   creation and termination.  */
27
28#include <gomp/libgomp.h>
29#include <stdlib.h>
30#include <string.h>
31
32
33/* Create a new task data structure.  */
34
35void
36gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
37                struct gomp_task_icv *prev_icv)
38{
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);
46}
47
48/* Clean up a task, after completing it.  */
49
50void
51gomp_end_task (void)
52{
53  struct gomp_thread *thr = gomp_thread ();
54  struct gomp_task *task = thr->task;
55
56  gomp_finish_task (task);
57  thr->task = task->parent;
58}
59
60static inline void
61gomp_clear_parent (struct gomp_task *children)
62{
63  struct gomp_task *task = children;
64
65  if (task)
66    do
67      {
68        task->parent = NULL;
69        task = task->next_child;
70      }
71    while (task != children);
72}
73
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.  */
77
78void
79GOMP_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)))
82{
83  struct gomp_thread *thr = gomp_thread ();
84  struct gomp_team *team = thr->ts.team;
85
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.  */
91  if (cpyfn)
92    if_clause = false;
93  if (flags & 1)
94    flags &= ~1;
95#endif
96
97  if (!if_clause || team == NULL
98      || (unsigned int)team->task_count > 64 * (unsigned int)team->nthreads)
99    {
100      struct gomp_task task;
101
102      gomp_init_task (&task, thr->task, gomp_icv (false));
103      task.kind = GOMP_TASK_IFFALSE;
104      if (thr->task)
105        task.in_tied_task = thr->task->in_tied_task;
106      thr->task = &task;
107      if (__builtin_expect (cpyfn != NULL, 0))
108        {
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);
114        }
115      else
116        fn (data);
117      if (task.children)
118        {
119          gomp_mutex_lock (&team->task_lock);
120          gomp_clear_parent (task.children);
121          gomp_mutex_unlock (&team->task_lock);
122        }
123      gomp_end_task ();
124    }
125  else
126    {
127      struct gomp_task *task;
128      struct gomp_task *parent = thr->task;
129      char *arg;
130      bool do_wake;
131
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;
138      thr->task = task;
139      if (cpyfn)
140        cpyfn (arg, data);
141      else
142        memcpy (arg, data, arg_size);
143      thr->task = parent;
144      task->kind = GOMP_TASK_WAITING;
145      task->fn = fn;
146      task->fn_data = arg;
147      task->in_tied_task = true;
148      gomp_mutex_lock (&team->task_lock);
149      if (parent->children)
150        {
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;
155        }
156      else
157        {
158          task->next_child = task;
159          task->prev_child = task;
160        }
161      parent->children = task;
162      if (team->task_queue)
163        {
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;
168        }
169      else
170        {
171          task->next_queue = task;
172          task->prev_queue = task;
173          team->task_queue = task;
174        }
175      ++team->task_count;
176      gomp_team_barrier_set_task_pending (&team->barrier);
177      do_wake = team->task_running_count + !parent->in_tied_task
178        < (int)team->nthreads;
179      gomp_mutex_unlock (&team->task_lock);
180      if (do_wake)
181        gomp_team_barrier_wake (&team->barrier, 1);
182    }
183}
184
185void
186gomp_barrier_handle_tasks (gomp_barrier_state_t state)
187{
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;
193
194  gomp_mutex_lock (&team->task_lock);
195  if (gomp_barrier_last_thread (state))
196    {
197      if (team->task_count == 0)
198        {
199          gomp_team_barrier_done (&team->barrier, state);
200          gomp_mutex_unlock (&team->task_lock);
201          gomp_team_barrier_wake (&team->barrier, 0);
202          return;
203        }
204      gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
205    }
206
207  while (1)
208    {
209      if (team->task_queue != NULL)
210        {
211          struct gomp_task *parent;
212
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;
221          else
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);
227        }
228      gomp_mutex_unlock (&team->task_lock);
229      if (to_free)
230        {
231          gomp_finish_task (to_free);
232          free (to_free);
233          to_free = NULL;
234        }
235      if (child_task)
236        {
237          thr->task = child_task;
238          child_task->fn (child_task->fn_data);
239          thr->task = task;
240        }
241      else
242        return;
243      gomp_mutex_lock (&team->task_lock);
244      if (child_task)
245        {
246          struct gomp_task *parent = child_task->parent;
247          if (parent)
248            {
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)
252                {
253                  if (child_task->next_child != child_task)
254                    parent->children = child_task->next_child;
255                  else
256                    {
257                      parent->children = NULL;
258                      if (parent->in_taskwait)
259                        gomp_sem_post (&parent->taskwait_sem);
260                    }
261                }
262            }
263          gomp_clear_parent (child_task->children);
264          to_free = child_task;
265          child_task = NULL;
266          team->task_running_count--;
267          if (--team->task_count == 0
268              && gomp_team_barrier_waiting_for_tasks (&team->barrier))
269            {
270              gomp_team_barrier_done (&team->barrier, state);
271              gomp_mutex_unlock (&team->task_lock);
272              gomp_team_barrier_wake (&team->barrier, 0);
273            }
274        }
275    }
276}
277
278/* Called when encountering a taskwait directive.  */
279
280void
281GOMP_taskwait (void)
282{
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;
288
289  if (task == NULL || task->children == NULL)
290    return;
291  gomp_mutex_lock (&team->task_lock);
292  while (1)
293    {
294      if (task->children == NULL)
295        {
296          gomp_mutex_unlock (&team->task_lock);
297          if (to_free)
298            {
299              gomp_finish_task (to_free);
300              free (to_free);
301            }
302          return;
303        }
304      if (task->children->kind == GOMP_TASK_WAITING)
305        {
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)
311            {
312              if (child_task->next_queue != child_task)
313                team->task_queue = child_task->next_queue;
314              else
315                team->task_queue = NULL;
316            }
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);
321        }
322      else
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);
327      if (to_free)
328        {
329          gomp_finish_task (to_free);
330          free (to_free);
331          to_free = NULL;
332        }
333      if (child_task)
334        {
335          thr->task = child_task;
336          child_task->fn (child_task->fn_data);
337          thr->task = task;
338        }
339      else
340        {
341          gomp_sem_wait (&task->taskwait_sem);
342          task->in_taskwait = false;
343          return;
344        }
345      gomp_mutex_lock (&team->task_lock);
346      if (child_task)
347        {
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)
351            {
352              if (child_task->next_child != child_task)
353                task->children = child_task->next_child;
354              else
355                task->children = NULL;
356            }
357          gomp_clear_parent (child_task->children);
358          to_free = child_task;
359          child_task = NULL;
360          team->task_count--;
361          team->task_running_count--;
362        }
363    }
364}
Note: See TracBrowser for help on using the repository browser.