task.c

Go to the documentation of this file.
00001 /* Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
00002    Contributed by Richard Henderson <rth@redhat.com>.
00003 
00004    This file is part of the GNU OpenMP Library (libgomp).
00005 
00006    Libgomp is free software; you can redistribute it and/or modify it
00007    under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 3, or (at your option)
00009    any later version.
00010 
00011    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
00012    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00014    more details.
00015 
00016    Under Section 7 of GPL version 3, you are granted additional
00017    permissions described in the GCC Runtime Library Exception, version
00018    3.1, as published by the Free Software Foundation.
00019 
00020    You should have received a copy of the GNU General Public License and
00021    a copy of the GCC Runtime Library Exception along with this program;
00022    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023    <http://www.gnu.org/licenses/>.  */
00024 
00025 /* This file handles the maintainence of tasks in response to task
00026    creation and termination.  */
00027 
00028 #include "libgomp.h"
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 
00033 /* Create a new task data structure.  */
00034 
00035 void
00036 gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
00037         struct gomp_task_icv *prev_icv)
00038 {
00039   task->parent = parent_task;
00040   task->icv = *prev_icv;
00041   task->kind = GOMP_TASK_IMPLICIT;
00042   task->in_taskwait = false;
00043   task->in_tied_task = false;
00044   task->children = NULL;
00045   gomp_sem_init (&task->taskwait_sem, 0);
00046 }
00047 
00048 /* Clean up a task, after completing it.  */
00049 
00050 void
00051 gomp_end_task (void)
00052 {
00053   struct gomp_thread *thr = gomp_thread ();
00054   struct gomp_task *task = thr->task;
00055 
00056   gomp_finish_task (task);
00057   thr->task = task->parent;
00058 }
00059 
00060 static inline void
00061 gomp_clear_parent (struct gomp_task *children)
00062 {
00063   struct gomp_task *task = children;
00064 
00065   if (task)
00066     do
00067       {
00068     task->parent = NULL;
00069     task = task->next_child;
00070       }
00071     while (task != children);
00072 }
00073 
00074 /* Called when encountering an explicit task directive.  If IF_CLAUSE is
00075    false, then we must not delay in executing the task.  If UNTIED is true,
00076    then the task may be executed by any member of the team.  */
00077 
00078 void
00079 GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
00080        long arg_size, long arg_align, bool if_clause,
00081        unsigned flags __attribute__((unused)))
00082 {
00083   struct gomp_thread *thr = gomp_thread ();
00084   struct gomp_team *team = thr->ts.team;
00085 
00086 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
00087   /* If pthread_mutex_* is used for omp_*lock*, then each task must be
00088      tied to one thread all the time.  This means UNTIED tasks must be
00089      tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
00090      might be running on different thread than FN.  */
00091   if (cpyfn)
00092     if_clause = false;
00093   if (flags & 1)
00094     flags &= ~1;
00095 #endif
00096 
00097   if (!if_clause || team == NULL
00098       || team->task_count > 64 * team->nthreads)
00099     {
00100       struct gomp_task task;
00101 
00102       gomp_init_task (&task, thr->task, gomp_icv (false));
00103       task.kind = GOMP_TASK_IFFALSE;
00104       if (thr->task)
00105     task.in_tied_task = thr->task->in_tied_task;
00106       thr->task = &task;
00107       if (__builtin_expect (cpyfn != NULL, 0))
00108     {
00109       char buf[arg_size + arg_align - 1];
00110       char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
00111                 & ~(uintptr_t) (arg_align - 1));
00112       cpyfn (arg, data);
00113       fn (arg);
00114     }
00115       else
00116     fn (data);
00117       if (task.children)
00118     {
00119       gomp_mutex_lock (&team->task_lock);
00120       gomp_clear_parent (task.children);
00121       gomp_mutex_unlock (&team->task_lock);
00122     }
00123       gomp_end_task ();
00124     }
00125   else
00126     {
00127       struct gomp_task *task;
00128       struct gomp_task *parent = thr->task;
00129       char *arg;
00130       bool do_wake;
00131 
00132       task = gomp_malloc (sizeof (*task) + arg_size + arg_align - 1);
00133       arg = (char *) (((uintptr_t) (task + 1) + arg_align - 1)
00134               & ~(uintptr_t) (arg_align - 1));
00135       gomp_init_task (task, parent, gomp_icv (false));
00136       task->kind = GOMP_TASK_IFFALSE;
00137       task->in_tied_task = parent->in_tied_task;
00138       thr->task = task;
00139       if (cpyfn)
00140     cpyfn (arg, data);
00141       else
00142     memcpy (arg, data, arg_size);
00143       thr->task = parent;
00144       task->kind = GOMP_TASK_WAITING;
00145       task->fn = fn;
00146       task->fn_data = arg;
00147       task->in_tied_task = true;
00148       gomp_mutex_lock (&team->task_lock);
00149       if (parent->children)
00150     {
00151       task->next_child = parent->children;
00152       task->prev_child = parent->children->prev_child;
00153       task->next_child->prev_child = task;
00154       task->prev_child->next_child = task;
00155     }
00156       else
00157     {
00158       task->next_child = task;
00159       task->prev_child = task;
00160     }
00161       parent->children = task;
00162       if (team->task_queue)
00163     {
00164       task->next_queue = team->task_queue;
00165       task->prev_queue = team->task_queue->prev_queue;
00166       task->next_queue->prev_queue = task;
00167       task->prev_queue->next_queue = task;
00168     }
00169       else
00170     {
00171       task->next_queue = task;
00172       task->prev_queue = task;
00173       team->task_queue = task;
00174     }
00175       ++team->task_count;
00176       gomp_team_barrier_set_task_pending (&team->barrier);
00177       do_wake = team->task_running_count + !parent->in_tied_task
00178         < team->nthreads;
00179       gomp_mutex_unlock (&team->task_lock);
00180       if (do_wake)
00181     gomp_team_barrier_wake (&team->barrier, 1);
00182     }
00183 }
00184 
00185 void
00186 gomp_barrier_handle_tasks (gomp_barrier_state_t state)
00187 {
00188   struct gomp_thread *thr = gomp_thread ();
00189   struct gomp_team *team = thr->ts.team;
00190   struct gomp_task *task = thr->task;
00191   struct gomp_task *child_task = NULL;
00192   struct gomp_task *to_free = NULL;
00193 
00194   gomp_mutex_lock (&team->task_lock);
00195   if (gomp_barrier_last_thread (state))
00196     {
00197       if (team->task_count == 0)
00198     {
00199       gomp_team_barrier_done (&team->barrier, state);
00200       gomp_mutex_unlock (&team->task_lock);
00201       gomp_team_barrier_wake (&team->barrier, 0);
00202       return;
00203     }
00204       gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
00205     }
00206 
00207   while (1)
00208     {
00209       if (team->task_queue != NULL)
00210     {
00211       struct gomp_task *parent;
00212 
00213       child_task = team->task_queue;
00214       parent = child_task->parent;
00215       if (parent && parent->children == child_task)
00216         parent->children = child_task->next_child;
00217       child_task->prev_queue->next_queue = child_task->next_queue;
00218       child_task->next_queue->prev_queue = child_task->prev_queue;
00219       if (child_task->next_queue != child_task)
00220         team->task_queue = child_task->next_queue;
00221       else
00222         team->task_queue = NULL;
00223       child_task->kind = GOMP_TASK_TIED;
00224       team->task_running_count++;
00225       if (team->task_count == team->task_running_count)
00226         gomp_team_barrier_clear_task_pending (&team->barrier);
00227     }
00228       gomp_mutex_unlock (&team->task_lock);
00229       if (to_free)
00230     {
00231       gomp_finish_task (to_free);
00232       free (to_free);
00233       to_free = NULL;
00234     }
00235       if (child_task)
00236     {
00237       thr->task = child_task;
00238       child_task->fn (child_task->fn_data);
00239       thr->task = task;
00240     }
00241       else
00242     return;
00243       gomp_mutex_lock (&team->task_lock);
00244       if (child_task)
00245     {
00246       struct gomp_task *parent = child_task->parent;
00247       if (parent)
00248         {
00249           child_task->prev_child->next_child = child_task->next_child;
00250           child_task->next_child->prev_child = child_task->prev_child;
00251           if (parent->children == child_task)
00252         {
00253           if (child_task->next_child != child_task)
00254             parent->children = child_task->next_child;
00255           else
00256             {
00257               parent->children = NULL;
00258               if (parent->in_taskwait)
00259             gomp_sem_post (&parent->taskwait_sem);
00260             }
00261         }
00262         }
00263       gomp_clear_parent (child_task->children);
00264       to_free = child_task;
00265       child_task = NULL;
00266       team->task_running_count--;
00267       if (--team->task_count == 0
00268           && gomp_team_barrier_waiting_for_tasks (&team->barrier))
00269         {
00270           gomp_team_barrier_done (&team->barrier, state);
00271           gomp_mutex_unlock (&team->task_lock);
00272           gomp_team_barrier_wake (&team->barrier, 0);
00273         }
00274     }
00275     }
00276 }
00277 
00278 /* Called when encountering a taskwait directive.  */
00279 
00280 void
00281 GOMP_taskwait (void)
00282 {
00283   struct gomp_thread *thr = gomp_thread ();
00284   struct gomp_team *team = thr->ts.team;
00285   struct gomp_task *task = thr->task;
00286   struct gomp_task *child_task = NULL;
00287   struct gomp_task *to_free = NULL;
00288 
00289   if (task == NULL || task->children == NULL)
00290     return;
00291   gomp_mutex_lock (&team->task_lock);
00292   while (1)
00293     {
00294       if (task->children == NULL)
00295     {
00296       gomp_mutex_unlock (&team->task_lock);
00297       if (to_free)
00298         {
00299           gomp_finish_task (to_free);
00300           free (to_free);
00301         }
00302       return;
00303     }
00304       if (task->children->kind == GOMP_TASK_WAITING)
00305     {
00306       child_task = task->children;
00307       task->children = child_task->next_child;
00308       child_task->prev_queue->next_queue = child_task->next_queue;
00309       child_task->next_queue->prev_queue = child_task->prev_queue;
00310       if (team->task_queue == child_task)
00311         {
00312           if (child_task->next_queue != child_task)
00313         team->task_queue = child_task->next_queue;
00314           else
00315         team->task_queue = NULL;
00316         }
00317       child_task->kind = GOMP_TASK_TIED;
00318       team->task_running_count++;
00319       if (team->task_count == team->task_running_count)
00320         gomp_team_barrier_clear_task_pending (&team->barrier);
00321     }
00322       else
00323     /* All tasks we are waiting for are already running
00324        in other threads.  Wait for them.  */
00325     task->in_taskwait = true;
00326       gomp_mutex_unlock (&team->task_lock);
00327       if (to_free)
00328     {
00329       gomp_finish_task (to_free);
00330       free (to_free);
00331       to_free = NULL;
00332     }
00333       if (child_task)
00334     {
00335       thr->task = child_task;
00336       child_task->fn (child_task->fn_data);
00337       thr->task = task;
00338     }
00339       else
00340     {
00341       gomp_sem_wait (&task->taskwait_sem);
00342       task->in_taskwait = false;
00343       return;
00344     }
00345       gomp_mutex_lock (&team->task_lock);
00346       if (child_task)
00347     {
00348       child_task->prev_child->next_child = child_task->next_child;
00349       child_task->next_child->prev_child = child_task->prev_child;
00350       if (task->children == child_task)
00351         {
00352           if (child_task->next_child != child_task)
00353         task->children = child_task->next_child;
00354           else
00355         task->children = NULL;
00356         }
00357       gomp_clear_parent (child_task->children);
00358       to_free = child_task;
00359       child_task = NULL;
00360       team->task_count--;
00361       team->task_running_count--;
00362     }
00363     }
00364 }

Generated on Fri Apr 5 05:38:10 2013 for Libgomp by  doxygen 1.4.7