00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "libgomp.h"
00029 #include <stdlib.h>
00030 #include <string.h>
00031
00032
00033
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
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
00075
00076
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
00088
00089
00090
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
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
00324
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 }