OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgomp/] [task.c] - Blame information for rev 735

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 735 jeremybenn
/* Copyright (C) 2007, 2008, 2009, 2011 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 "libgomp.h"
29
#include <stdlib.h>
30
#include <string.h>
31
 
32
 
33
/* Create a new task data structure.  */
34
 
35
void
36
gomp_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->final_task = false;
45
  task->children = NULL;
46
  gomp_sem_init (&task->taskwait_sem, 0);
47
}
48
 
49
/* Clean up a task, after completing it.  */
50
 
51
void
52
gomp_end_task (void)
53
{
54
  struct gomp_thread *thr = gomp_thread ();
55
  struct gomp_task *task = thr->task;
56
 
57
  gomp_finish_task (task);
58
  thr->task = task->parent;
59
}
60
 
61
static inline void
62
gomp_clear_parent (struct gomp_task *children)
63
{
64
  struct gomp_task *task = children;
65
 
66
  if (task)
67
    do
68
      {
69
        task->parent = NULL;
70
        task = task->next_child;
71
      }
72
    while (task != children);
73
}
74
 
75
/* Called when encountering an explicit task directive.  If IF_CLAUSE is
76
   false, then we must not delay in executing the task.  If UNTIED is true,
77
   then the task may be executed by any member of the team.  */
78
 
79
void
80
GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
81
           long arg_size, long arg_align, bool if_clause, unsigned flags)
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
      || (thr->task && thr->task->final_task)
99
      || team->task_count > 64 * team->nthreads)
100
    {
101
      struct gomp_task task;
102
 
103
      gomp_init_task (&task, thr->task, gomp_icv (false));
104
      task.kind = GOMP_TASK_IFFALSE;
105
      task.final_task = (thr->task && thr->task->final_task) || (flags & 2);
106
      if (thr->task)
107
        task.in_tied_task = thr->task->in_tied_task;
108
      thr->task = &task;
109
      if (__builtin_expect (cpyfn != NULL, 0))
110
        {
111
          char buf[arg_size + arg_align - 1];
112
          char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
113
                                & ~(uintptr_t) (arg_align - 1));
114
          cpyfn (arg, data);
115
          fn (arg);
116
        }
117
      else
118
        fn (data);
119
      if (team != NULL)
120
        {
121
          gomp_mutex_lock (&team->task_lock);
122
          if (task.children != NULL)
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
      task->final_task = (flags & 2) >> 1;
152
      gomp_mutex_lock (&team->task_lock);
153
      if (parent->children)
154
        {
155
          task->next_child = parent->children;
156
          task->prev_child = parent->children->prev_child;
157
          task->next_child->prev_child = task;
158
          task->prev_child->next_child = task;
159
        }
160
      else
161
        {
162
          task->next_child = task;
163
          task->prev_child = task;
164
        }
165
      parent->children = task;
166
      if (team->task_queue)
167
        {
168
          task->next_queue = team->task_queue;
169
          task->prev_queue = team->task_queue->prev_queue;
170
          task->next_queue->prev_queue = task;
171
          task->prev_queue->next_queue = task;
172
        }
173
      else
174
        {
175
          task->next_queue = task;
176
          task->prev_queue = task;
177
          team->task_queue = task;
178
        }
179
      ++team->task_count;
180
      gomp_team_barrier_set_task_pending (&team->barrier);
181
      do_wake = team->task_running_count + !parent->in_tied_task
182
                < team->nthreads;
183
      gomp_mutex_unlock (&team->task_lock);
184
      if (do_wake)
185
        gomp_team_barrier_wake (&team->barrier, 1);
186
    }
187
}
188
 
189
void
190
gomp_barrier_handle_tasks (gomp_barrier_state_t state)
191
{
192
  struct gomp_thread *thr = gomp_thread ();
193
  struct gomp_team *team = thr->ts.team;
194
  struct gomp_task *task = thr->task;
195
  struct gomp_task *child_task = NULL;
196
  struct gomp_task *to_free = NULL;
197
 
198
  gomp_mutex_lock (&team->task_lock);
199
  if (gomp_barrier_last_thread (state))
200
    {
201
      if (team->task_count == 0)
202
        {
203
          gomp_team_barrier_done (&team->barrier, state);
204
          gomp_mutex_unlock (&team->task_lock);
205
          gomp_team_barrier_wake (&team->barrier, 0);
206
          return;
207
        }
208
      gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
209
    }
210
 
211
  while (1)
212
    {
213
      if (team->task_queue != NULL)
214
        {
215
          struct gomp_task *parent;
216
 
217
          child_task = team->task_queue;
218
          parent = child_task->parent;
219
          if (parent && parent->children == child_task)
220
            parent->children = child_task->next_child;
221
          child_task->prev_queue->next_queue = child_task->next_queue;
222
          child_task->next_queue->prev_queue = child_task->prev_queue;
223
          if (child_task->next_queue != child_task)
224
            team->task_queue = child_task->next_queue;
225
          else
226
            team->task_queue = NULL;
227
          child_task->kind = GOMP_TASK_TIED;
228
          team->task_running_count++;
229
          if (team->task_count == team->task_running_count)
230
            gomp_team_barrier_clear_task_pending (&team->barrier);
231
        }
232
      gomp_mutex_unlock (&team->task_lock);
233
      if (to_free)
234
        {
235
          gomp_finish_task (to_free);
236
          free (to_free);
237
          to_free = NULL;
238
        }
239
      if (child_task)
240
        {
241
          thr->task = child_task;
242
          child_task->fn (child_task->fn_data);
243
          thr->task = task;
244
        }
245
      else
246
        return;
247
      gomp_mutex_lock (&team->task_lock);
248
      if (child_task)
249
        {
250
          struct gomp_task *parent = child_task->parent;
251
          if (parent)
252
            {
253
              child_task->prev_child->next_child = child_task->next_child;
254
              child_task->next_child->prev_child = child_task->prev_child;
255
              if (parent->children == child_task)
256
                {
257
                  if (child_task->next_child != child_task)
258
                    parent->children = child_task->next_child;
259
                  else
260
                    {
261
                      parent->children = NULL;
262
                      if (parent->in_taskwait)
263
                        gomp_sem_post (&parent->taskwait_sem);
264
                    }
265
                }
266
            }
267
          gomp_clear_parent (child_task->children);
268
          to_free = child_task;
269
          child_task = NULL;
270
          team->task_running_count--;
271
          if (--team->task_count == 0
272
              && gomp_team_barrier_waiting_for_tasks (&team->barrier))
273
            {
274
              gomp_team_barrier_done (&team->barrier, state);
275
              gomp_mutex_unlock (&team->task_lock);
276
              gomp_team_barrier_wake (&team->barrier, 0);
277
              gomp_mutex_lock (&team->task_lock);
278
            }
279
        }
280
    }
281
}
282
 
283
/* Called when encountering a taskwait directive.  */
284
 
285
void
286
GOMP_taskwait (void)
287
{
288
  struct gomp_thread *thr = gomp_thread ();
289
  struct gomp_team *team = thr->ts.team;
290
  struct gomp_task *task = thr->task;
291
  struct gomp_task *child_task = NULL;
292
  struct gomp_task *to_free = NULL;
293
 
294
  if (task == NULL || team == NULL)
295
    return;
296
 
297
  gomp_mutex_lock (&team->task_lock);
298
  while (1)
299
    {
300
      if (task->children == NULL)
301
        {
302
          gomp_mutex_unlock (&team->task_lock);
303
          if (to_free)
304
            {
305
              gomp_finish_task (to_free);
306
              free (to_free);
307
            }
308
          return;
309
        }
310
      if (task->children->kind == GOMP_TASK_WAITING)
311
        {
312
          child_task = task->children;
313
          task->children = child_task->next_child;
314
          child_task->prev_queue->next_queue = child_task->next_queue;
315
          child_task->next_queue->prev_queue = child_task->prev_queue;
316
          if (team->task_queue == child_task)
317
            {
318
              if (child_task->next_queue != child_task)
319
                team->task_queue = child_task->next_queue;
320
              else
321
                team->task_queue = NULL;
322
            }
323
          child_task->kind = GOMP_TASK_TIED;
324
          team->task_running_count++;
325
          if (team->task_count == team->task_running_count)
326
            gomp_team_barrier_clear_task_pending (&team->barrier);
327
        }
328
      else
329
        /* All tasks we are waiting for are already running
330
           in other threads.  Wait for them.  */
331
        task->in_taskwait = true;
332
      gomp_mutex_unlock (&team->task_lock);
333
      if (to_free)
334
        {
335
          gomp_finish_task (to_free);
336
          free (to_free);
337
          to_free = NULL;
338
        }
339
      if (child_task)
340
        {
341
          thr->task = child_task;
342
          child_task->fn (child_task->fn_data);
343
          thr->task = task;
344
        }
345
      else
346
        {
347
          gomp_sem_wait (&task->taskwait_sem);
348
          task->in_taskwait = false;
349
          return;
350
        }
351
      gomp_mutex_lock (&team->task_lock);
352
      if (child_task)
353
        {
354
          child_task->prev_child->next_child = child_task->next_child;
355
          child_task->next_child->prev_child = child_task->prev_child;
356
          if (task->children == child_task)
357
            {
358
              if (child_task->next_child != child_task)
359
                task->children = child_task->next_child;
360
              else
361
                task->children = NULL;
362
            }
363
          gomp_clear_parent (child_task->children);
364
          to_free = child_task;
365
          child_task = NULL;
366
          team->task_count--;
367
          team->task_running_count--;
368
        }
369
    }
370
}
371
 
372
/* Called when encountering a taskyield directive.  */
373
 
374
void
375
GOMP_taskyield (void)
376
{
377
  /* Nothing at the moment.  */
378
}
379
 
380
int
381
omp_in_final (void)
382
{
383
  struct gomp_thread *thr = gomp_thread ();
384
  return thr->task && thr->task->final_task;
385
}
386
 
387
ialias (omp_in_final)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.