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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [libgomp/] [team.c] - Diff between revs 816 and 826

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
/* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
   Contributed by Richard Henderson <rth@redhat.com>.
   Contributed by Richard Henderson <rth@redhat.com>.
 
 
   This file is part of the GNU OpenMP Library (libgomp).
   This file is part of the GNU OpenMP Library (libgomp).
 
 
   Libgomp is free software; you can redistribute it and/or modify it
   Libgomp is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   more details.
 
 
   Under Section 7 of GPL version 3, you are granted additional
   Under Section 7 of GPL version 3, you are granted additional
   permissions described in the GCC Runtime Library Exception, version
   permissions described in the GCC Runtime Library Exception, version
   3.1, as published by the Free Software Foundation.
   3.1, as published by the Free Software Foundation.
 
 
   You should have received a copy of the GNU General Public License and
   You should have received a copy of the GNU General Public License and
   a copy of the GCC Runtime Library Exception along with this program;
   a copy of the GCC Runtime Library Exception along with this program;
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   <http://www.gnu.org/licenses/>.  */
   <http://www.gnu.org/licenses/>.  */
 
 
/* This file handles the maintainence of threads in response to team
/* This file handles the maintainence of threads in response to team
   creation and termination.  */
   creation and termination.  */
 
 
#include "libgomp.h"
#include "libgomp.h"
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
 
 
/* This attribute contains PTHREAD_CREATE_DETACHED.  */
/* This attribute contains PTHREAD_CREATE_DETACHED.  */
pthread_attr_t gomp_thread_attr;
pthread_attr_t gomp_thread_attr;
 
 
/* This key is for the thread destructor.  */
/* This key is for the thread destructor.  */
pthread_key_t gomp_thread_destructor;
pthread_key_t gomp_thread_destructor;
 
 
 
 
/* This is the libgomp per-thread data structure.  */
/* This is the libgomp per-thread data structure.  */
#ifdef HAVE_TLS
#ifdef HAVE_TLS
__thread struct gomp_thread gomp_tls_data;
__thread struct gomp_thread gomp_tls_data;
#else
#else
pthread_key_t gomp_tls_key;
pthread_key_t gomp_tls_key;
#endif
#endif
 
 
 
 
/* This structure is used to communicate across pthread_create.  */
/* This structure is used to communicate across pthread_create.  */
 
 
struct gomp_thread_start_data
struct gomp_thread_start_data
{
{
  void (*fn) (void *);
  void (*fn) (void *);
  void *fn_data;
  void *fn_data;
  struct gomp_team_state ts;
  struct gomp_team_state ts;
  struct gomp_task *task;
  struct gomp_task *task;
  struct gomp_thread_pool *thread_pool;
  struct gomp_thread_pool *thread_pool;
  bool nested;
  bool nested;
};
};
 
 
 
 
/* This function is a pthread_create entry point.  This contains the idle
/* This function is a pthread_create entry point.  This contains the idle
   loop in which a thread waits to be called up to become part of a team.  */
   loop in which a thread waits to be called up to become part of a team.  */
 
 
static void *
static void *
gomp_thread_start (void *xdata)
gomp_thread_start (void *xdata)
{
{
  struct gomp_thread_start_data *data = xdata;
  struct gomp_thread_start_data *data = xdata;
  struct gomp_thread *thr;
  struct gomp_thread *thr;
  struct gomp_thread_pool *pool;
  struct gomp_thread_pool *pool;
  void (*local_fn) (void *);
  void (*local_fn) (void *);
  void *local_data;
  void *local_data;
 
 
#ifdef HAVE_TLS
#ifdef HAVE_TLS
  thr = &gomp_tls_data;
  thr = &gomp_tls_data;
#else
#else
  struct gomp_thread local_thr;
  struct gomp_thread local_thr;
  thr = &local_thr;
  thr = &local_thr;
  pthread_setspecific (gomp_tls_key, thr);
  pthread_setspecific (gomp_tls_key, thr);
#endif
#endif
  gomp_sem_init (&thr->release, 0);
  gomp_sem_init (&thr->release, 0);
 
 
  /* Extract what we need from data.  */
  /* Extract what we need from data.  */
  local_fn = data->fn;
  local_fn = data->fn;
  local_data = data->fn_data;
  local_data = data->fn_data;
  thr->thread_pool = data->thread_pool;
  thr->thread_pool = data->thread_pool;
  thr->ts = data->ts;
  thr->ts = data->ts;
  thr->task = data->task;
  thr->task = data->task;
 
 
  thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
  thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
 
 
  /* Make thread pool local. */
  /* Make thread pool local. */
  pool = thr->thread_pool;
  pool = thr->thread_pool;
 
 
  if (data->nested)
  if (data->nested)
    {
    {
      struct gomp_team *team = thr->ts.team;
      struct gomp_team *team = thr->ts.team;
      struct gomp_task *task = thr->task;
      struct gomp_task *task = thr->task;
 
 
      gomp_barrier_wait (&team->barrier);
      gomp_barrier_wait (&team->barrier);
 
 
      local_fn (local_data);
      local_fn (local_data);
      gomp_team_barrier_wait (&team->barrier);
      gomp_team_barrier_wait (&team->barrier);
      gomp_finish_task (task);
      gomp_finish_task (task);
      gomp_barrier_wait_last (&team->barrier);
      gomp_barrier_wait_last (&team->barrier);
    }
    }
  else
  else
    {
    {
      pool->threads[thr->ts.team_id] = thr;
      pool->threads[thr->ts.team_id] = thr;
 
 
      gomp_barrier_wait (&pool->threads_dock);
      gomp_barrier_wait (&pool->threads_dock);
      do
      do
        {
        {
          struct gomp_team *team = thr->ts.team;
          struct gomp_team *team = thr->ts.team;
          struct gomp_task *task = thr->task;
          struct gomp_task *task = thr->task;
 
 
          local_fn (local_data);
          local_fn (local_data);
          gomp_team_barrier_wait (&team->barrier);
          gomp_team_barrier_wait (&team->barrier);
          gomp_finish_task (task);
          gomp_finish_task (task);
 
 
          gomp_barrier_wait (&pool->threads_dock);
          gomp_barrier_wait (&pool->threads_dock);
 
 
          local_fn = thr->fn;
          local_fn = thr->fn;
          local_data = thr->data;
          local_data = thr->data;
          thr->fn = NULL;
          thr->fn = NULL;
        }
        }
      while (local_fn);
      while (local_fn);
    }
    }
 
 
  gomp_sem_destroy (&thr->release);
  gomp_sem_destroy (&thr->release);
  return NULL;
  return NULL;
}
}
 
 
 
 
/* Create a new team data structure.  */
/* Create a new team data structure.  */
 
 
struct gomp_team *
struct gomp_team *
gomp_new_team (unsigned nthreads)
gomp_new_team (unsigned nthreads)
{
{
  struct gomp_team *team;
  struct gomp_team *team;
  size_t size;
  size_t size;
  int i;
  int i;
 
 
  size = sizeof (*team) + nthreads * (sizeof (team->ordered_release[0])
  size = sizeof (*team) + nthreads * (sizeof (team->ordered_release[0])
                                      + sizeof (team->implicit_task[0]));
                                      + sizeof (team->implicit_task[0]));
  team = gomp_malloc (size);
  team = gomp_malloc (size);
 
 
  team->work_share_chunk = 8;
  team->work_share_chunk = 8;
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
  team->single_count = 0;
  team->single_count = 0;
#else
#else
  gomp_mutex_init (&team->work_share_list_free_lock);
  gomp_mutex_init (&team->work_share_list_free_lock);
#endif
#endif
  gomp_init_work_share (&team->work_shares[0], false, nthreads);
  gomp_init_work_share (&team->work_shares[0], false, nthreads);
  team->work_shares[0].next_alloc = NULL;
  team->work_shares[0].next_alloc = NULL;
  team->work_share_list_free = NULL;
  team->work_share_list_free = NULL;
  team->work_share_list_alloc = &team->work_shares[1];
  team->work_share_list_alloc = &team->work_shares[1];
  for (i = 1; i < 7; i++)
  for (i = 1; i < 7; i++)
    team->work_shares[i].next_free = &team->work_shares[i + 1];
    team->work_shares[i].next_free = &team->work_shares[i + 1];
  team->work_shares[i].next_free = NULL;
  team->work_shares[i].next_free = NULL;
 
 
  team->nthreads = nthreads;
  team->nthreads = nthreads;
  gomp_barrier_init (&team->barrier, nthreads);
  gomp_barrier_init (&team->barrier, nthreads);
 
 
  gomp_sem_init (&team->master_release, 0);
  gomp_sem_init (&team->master_release, 0);
  team->ordered_release = (void *) &team->implicit_task[nthreads];
  team->ordered_release = (void *) &team->implicit_task[nthreads];
  team->ordered_release[0] = &team->master_release;
  team->ordered_release[0] = &team->master_release;
 
 
  gomp_mutex_init (&team->task_lock);
  gomp_mutex_init (&team->task_lock);
  team->task_queue = NULL;
  team->task_queue = NULL;
  team->task_count = 0;
  team->task_count = 0;
  team->task_running_count = 0;
  team->task_running_count = 0;
 
 
  return team;
  return team;
}
}
 
 
 
 
/* Free a team data structure.  */
/* Free a team data structure.  */
 
 
static void
static void
free_team (struct gomp_team *team)
free_team (struct gomp_team *team)
{
{
  gomp_barrier_destroy (&team->barrier);
  gomp_barrier_destroy (&team->barrier);
  gomp_mutex_destroy (&team->task_lock);
  gomp_mutex_destroy (&team->task_lock);
  free (team);
  free (team);
}
}
 
 
/* Allocate and initialize a thread pool. */
/* Allocate and initialize a thread pool. */
 
 
static struct gomp_thread_pool *gomp_new_thread_pool (void)
static struct gomp_thread_pool *gomp_new_thread_pool (void)
{
{
  struct gomp_thread_pool *pool
  struct gomp_thread_pool *pool
    = gomp_malloc (sizeof(struct gomp_thread_pool));
    = gomp_malloc (sizeof(struct gomp_thread_pool));
  pool->threads = NULL;
  pool->threads = NULL;
  pool->threads_size = 0;
  pool->threads_size = 0;
  pool->threads_used = 0;
  pool->threads_used = 0;
  pool->last_team = NULL;
  pool->last_team = NULL;
  return pool;
  return pool;
}
}
 
 
static void
static void
gomp_free_pool_helper (void *thread_pool)
gomp_free_pool_helper (void *thread_pool)
{
{
  struct gomp_thread_pool *pool
  struct gomp_thread_pool *pool
    = (struct gomp_thread_pool *) thread_pool;
    = (struct gomp_thread_pool *) thread_pool;
  gomp_barrier_wait_last (&pool->threads_dock);
  gomp_barrier_wait_last (&pool->threads_dock);
  gomp_sem_destroy (&gomp_thread ()->release);
  gomp_sem_destroy (&gomp_thread ()->release);
  pthread_exit (NULL);
  pthread_exit (NULL);
}
}
 
 
/* Free a thread pool and release its threads. */
/* Free a thread pool and release its threads. */
 
 
static void
static void
gomp_free_thread (void *arg __attribute__((unused)))
gomp_free_thread (void *arg __attribute__((unused)))
{
{
  struct gomp_thread *thr = gomp_thread ();
  struct gomp_thread *thr = gomp_thread ();
  struct gomp_thread_pool *pool = thr->thread_pool;
  struct gomp_thread_pool *pool = thr->thread_pool;
  if (pool)
  if (pool)
    {
    {
      if (pool->threads_used > 0)
      if (pool->threads_used > 0)
        {
        {
          int i;
          int i;
          for (i = 1; i < pool->threads_used; i++)
          for (i = 1; i < pool->threads_used; i++)
            {
            {
              struct gomp_thread *nthr = pool->threads[i];
              struct gomp_thread *nthr = pool->threads[i];
              nthr->fn = gomp_free_pool_helper;
              nthr->fn = gomp_free_pool_helper;
              nthr->data = pool;
              nthr->data = pool;
            }
            }
          /* This barrier undocks threads docked on pool->threads_dock.  */
          /* This barrier undocks threads docked on pool->threads_dock.  */
          gomp_barrier_wait (&pool->threads_dock);
          gomp_barrier_wait (&pool->threads_dock);
          /* And this waits till all threads have called gomp_barrier_wait_last
          /* And this waits till all threads have called gomp_barrier_wait_last
             in gomp_free_pool_helper.  */
             in gomp_free_pool_helper.  */
          gomp_barrier_wait (&pool->threads_dock);
          gomp_barrier_wait (&pool->threads_dock);
          /* Now it is safe to destroy the barrier and free the pool.  */
          /* Now it is safe to destroy the barrier and free the pool.  */
          gomp_barrier_destroy (&pool->threads_dock);
          gomp_barrier_destroy (&pool->threads_dock);
        }
        }
      free (pool->threads);
      free (pool->threads);
      if (pool->last_team)
      if (pool->last_team)
        free_team (pool->last_team);
        free_team (pool->last_team);
      free (pool);
      free (pool);
      thr->thread_pool = NULL;
      thr->thread_pool = NULL;
    }
    }
  if (thr->task != NULL)
  if (thr->task != NULL)
    {
    {
      struct gomp_task *task = thr->task;
      struct gomp_task *task = thr->task;
      gomp_end_task ();
      gomp_end_task ();
      free (task);
      free (task);
    }
    }
}
}
 
 
/* Launch a team.  */
/* Launch a team.  */
 
 
void
void
gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
                 struct gomp_team *team)
                 struct gomp_team *team)
{
{
  struct gomp_thread_start_data *start_data;
  struct gomp_thread_start_data *start_data;
  struct gomp_thread *thr, *nthr;
  struct gomp_thread *thr, *nthr;
  struct gomp_task *task;
  struct gomp_task *task;
  struct gomp_task_icv *icv;
  struct gomp_task_icv *icv;
  bool nested;
  bool nested;
  struct gomp_thread_pool *pool;
  struct gomp_thread_pool *pool;
  unsigned i, n, old_threads_used = 0;
  unsigned i, n, old_threads_used = 0;
  pthread_attr_t thread_attr, *attr;
  pthread_attr_t thread_attr, *attr;
 
 
  thr = gomp_thread ();
  thr = gomp_thread ();
  nested = thr->ts.team != NULL;
  nested = thr->ts.team != NULL;
  if (__builtin_expect (thr->thread_pool == NULL, 0))
  if (__builtin_expect (thr->thread_pool == NULL, 0))
    {
    {
      thr->thread_pool = gomp_new_thread_pool ();
      thr->thread_pool = gomp_new_thread_pool ();
      pthread_setspecific (gomp_thread_destructor, thr);
      pthread_setspecific (gomp_thread_destructor, thr);
    }
    }
  pool = thr->thread_pool;
  pool = thr->thread_pool;
  task = thr->task;
  task = thr->task;
  icv = task ? &task->icv : &gomp_global_icv;
  icv = task ? &task->icv : &gomp_global_icv;
 
 
  /* Always save the previous state, even if this isn't a nested team.
  /* Always save the previous state, even if this isn't a nested team.
     In particular, we should save any work share state from an outer
     In particular, we should save any work share state from an outer
     orphaned work share construct.  */
     orphaned work share construct.  */
  team->prev_ts = thr->ts;
  team->prev_ts = thr->ts;
 
 
  thr->ts.team = team;
  thr->ts.team = team;
  thr->ts.team_id = 0;
  thr->ts.team_id = 0;
  ++thr->ts.level;
  ++thr->ts.level;
  if (nthreads > 1)
  if (nthreads > 1)
    ++thr->ts.active_level;
    ++thr->ts.active_level;
  thr->ts.work_share = &team->work_shares[0];
  thr->ts.work_share = &team->work_shares[0];
  thr->ts.last_work_share = NULL;
  thr->ts.last_work_share = NULL;
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
  thr->ts.single_count = 0;
  thr->ts.single_count = 0;
#endif
#endif
  thr->ts.static_trip = 0;
  thr->ts.static_trip = 0;
  thr->task = &team->implicit_task[0];
  thr->task = &team->implicit_task[0];
  gomp_init_task (thr->task, task, icv);
  gomp_init_task (thr->task, task, icv);
 
 
  if (nthreads == 1)
  if (nthreads == 1)
    return;
    return;
 
 
  i = 1;
  i = 1;
 
 
  /* We only allow the reuse of idle threads for non-nested PARALLEL
  /* We only allow the reuse of idle threads for non-nested PARALLEL
     regions.  This appears to be implied by the semantics of
     regions.  This appears to be implied by the semantics of
     threadprivate variables, but perhaps that's reading too much into
     threadprivate variables, but perhaps that's reading too much into
     things.  Certainly it does prevent any locking problems, since
     things.  Certainly it does prevent any locking problems, since
     only the initial program thread will modify gomp_threads.  */
     only the initial program thread will modify gomp_threads.  */
  if (!nested)
  if (!nested)
    {
    {
      old_threads_used = pool->threads_used;
      old_threads_used = pool->threads_used;
 
 
      if (nthreads <= old_threads_used)
      if (nthreads <= old_threads_used)
        n = nthreads;
        n = nthreads;
      else if (old_threads_used == 0)
      else if (old_threads_used == 0)
        {
        {
          n = 0;
          n = 0;
          gomp_barrier_init (&pool->threads_dock, nthreads);
          gomp_barrier_init (&pool->threads_dock, nthreads);
        }
        }
      else
      else
        {
        {
          n = old_threads_used;
          n = old_threads_used;
 
 
          /* Increase the barrier threshold to make sure all new
          /* Increase the barrier threshold to make sure all new
             threads arrive before the team is released.  */
             threads arrive before the team is released.  */
          gomp_barrier_reinit (&pool->threads_dock, nthreads);
          gomp_barrier_reinit (&pool->threads_dock, nthreads);
        }
        }
 
 
      /* Not true yet, but soon will be.  We're going to release all
      /* Not true yet, but soon will be.  We're going to release all
         threads from the dock, and those that aren't part of the
         threads from the dock, and those that aren't part of the
         team will exit.  */
         team will exit.  */
      pool->threads_used = nthreads;
      pool->threads_used = nthreads;
 
 
      /* Release existing idle threads.  */
      /* Release existing idle threads.  */
      for (; i < n; ++i)
      for (; i < n; ++i)
        {
        {
          nthr = pool->threads[i];
          nthr = pool->threads[i];
          nthr->ts.team = team;
          nthr->ts.team = team;
          nthr->ts.work_share = &team->work_shares[0];
          nthr->ts.work_share = &team->work_shares[0];
          nthr->ts.last_work_share = NULL;
          nthr->ts.last_work_share = NULL;
          nthr->ts.team_id = i;
          nthr->ts.team_id = i;
          nthr->ts.level = team->prev_ts.level + 1;
          nthr->ts.level = team->prev_ts.level + 1;
          nthr->ts.active_level = thr->ts.active_level;
          nthr->ts.active_level = thr->ts.active_level;
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
          nthr->ts.single_count = 0;
          nthr->ts.single_count = 0;
#endif
#endif
          nthr->ts.static_trip = 0;
          nthr->ts.static_trip = 0;
          nthr->task = &team->implicit_task[i];
          nthr->task = &team->implicit_task[i];
          gomp_init_task (nthr->task, task, icv);
          gomp_init_task (nthr->task, task, icv);
          nthr->fn = fn;
          nthr->fn = fn;
          nthr->data = data;
          nthr->data = data;
          team->ordered_release[i] = &nthr->release;
          team->ordered_release[i] = &nthr->release;
        }
        }
 
 
      if (i == nthreads)
      if (i == nthreads)
        goto do_release;
        goto do_release;
 
 
      /* If necessary, expand the size of the gomp_threads array.  It is
      /* If necessary, expand the size of the gomp_threads array.  It is
         expected that changes in the number of threads are rare, thus we
         expected that changes in the number of threads are rare, thus we
         make no effort to expand gomp_threads_size geometrically.  */
         make no effort to expand gomp_threads_size geometrically.  */
      if (nthreads >= pool->threads_size)
      if (nthreads >= pool->threads_size)
        {
        {
          pool->threads_size = nthreads + 1;
          pool->threads_size = nthreads + 1;
          pool->threads
          pool->threads
            = gomp_realloc (pool->threads,
            = gomp_realloc (pool->threads,
                            pool->threads_size
                            pool->threads_size
                            * sizeof (struct gomp_thread_data *));
                            * sizeof (struct gomp_thread_data *));
        }
        }
    }
    }
 
 
  if (__builtin_expect (nthreads > old_threads_used, 0))
  if (__builtin_expect (nthreads > old_threads_used, 0))
    {
    {
      long diff = (long) nthreads - (long) old_threads_used;
      long diff = (long) nthreads - (long) old_threads_used;
 
 
      if (old_threads_used == 0)
      if (old_threads_used == 0)
        --diff;
        --diff;
 
 
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
      __sync_fetch_and_add (&gomp_managed_threads, diff);
      __sync_fetch_and_add (&gomp_managed_threads, diff);
#else
#else
      gomp_mutex_lock (&gomp_remaining_threads_lock);
      gomp_mutex_lock (&gomp_remaining_threads_lock);
      gomp_managed_threads += diff;
      gomp_managed_threads += diff;
      gomp_mutex_unlock (&gomp_remaining_threads_lock);
      gomp_mutex_unlock (&gomp_remaining_threads_lock);
#endif
#endif
    }
    }
 
 
  attr = &gomp_thread_attr;
  attr = &gomp_thread_attr;
  if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
  if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
    {
    {
      size_t stacksize;
      size_t stacksize;
      pthread_attr_init (&thread_attr);
      pthread_attr_init (&thread_attr);
      pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
      pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
      if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
      if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
        pthread_attr_setstacksize (&thread_attr, stacksize);
        pthread_attr_setstacksize (&thread_attr, stacksize);
      attr = &thread_attr;
      attr = &thread_attr;
    }
    }
 
 
  start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
  start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
                            * (nthreads-i));
                            * (nthreads-i));
 
 
  /* Launch new threads.  */
  /* Launch new threads.  */
  for (; i < nthreads; ++i, ++start_data)
  for (; i < nthreads; ++i, ++start_data)
    {
    {
      pthread_t pt;
      pthread_t pt;
      int err;
      int err;
 
 
      start_data->fn = fn;
      start_data->fn = fn;
      start_data->fn_data = data;
      start_data->fn_data = data;
      start_data->ts.team = team;
      start_data->ts.team = team;
      start_data->ts.work_share = &team->work_shares[0];
      start_data->ts.work_share = &team->work_shares[0];
      start_data->ts.last_work_share = NULL;
      start_data->ts.last_work_share = NULL;
      start_data->ts.team_id = i;
      start_data->ts.team_id = i;
      start_data->ts.level = team->prev_ts.level + 1;
      start_data->ts.level = team->prev_ts.level + 1;
      start_data->ts.active_level = thr->ts.active_level;
      start_data->ts.active_level = thr->ts.active_level;
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
      start_data->ts.single_count = 0;
      start_data->ts.single_count = 0;
#endif
#endif
      start_data->ts.static_trip = 0;
      start_data->ts.static_trip = 0;
      start_data->task = &team->implicit_task[i];
      start_data->task = &team->implicit_task[i];
      gomp_init_task (start_data->task, task, icv);
      gomp_init_task (start_data->task, task, icv);
      start_data->thread_pool = pool;
      start_data->thread_pool = pool;
      start_data->nested = nested;
      start_data->nested = nested;
 
 
      if (gomp_cpu_affinity != NULL)
      if (gomp_cpu_affinity != NULL)
        gomp_init_thread_affinity (attr);
        gomp_init_thread_affinity (attr);
 
 
      err = pthread_create (&pt, attr, gomp_thread_start, start_data);
      err = pthread_create (&pt, attr, gomp_thread_start, start_data);
      if (err != 0)
      if (err != 0)
        gomp_fatal ("Thread creation failed: %s", strerror (err));
        gomp_fatal ("Thread creation failed: %s", strerror (err));
    }
    }
 
 
  if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
  if (__builtin_expect (gomp_cpu_affinity != NULL, 0))
    pthread_attr_destroy (&thread_attr);
    pthread_attr_destroy (&thread_attr);
 
 
 do_release:
 do_release:
  gomp_barrier_wait (nested ? &team->barrier : &pool->threads_dock);
  gomp_barrier_wait (nested ? &team->barrier : &pool->threads_dock);
 
 
  /* Decrease the barrier threshold to match the number of threads
  /* Decrease the barrier threshold to match the number of threads
     that should arrive back at the end of this team.  The extra
     that should arrive back at the end of this team.  The extra
     threads should be exiting.  Note that we arrange for this test
     threads should be exiting.  Note that we arrange for this test
     to never be true for nested teams.  */
     to never be true for nested teams.  */
  if (__builtin_expect (nthreads < old_threads_used, 0))
  if (__builtin_expect (nthreads < old_threads_used, 0))
    {
    {
      long diff = (long) nthreads - (long) old_threads_used;
      long diff = (long) nthreads - (long) old_threads_used;
 
 
      gomp_barrier_reinit (&pool->threads_dock, nthreads);
      gomp_barrier_reinit (&pool->threads_dock, nthreads);
 
 
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
      __sync_fetch_and_add (&gomp_managed_threads, diff);
      __sync_fetch_and_add (&gomp_managed_threads, diff);
#else
#else
      gomp_mutex_lock (&gomp_remaining_threads_lock);
      gomp_mutex_lock (&gomp_remaining_threads_lock);
      gomp_managed_threads += diff;
      gomp_managed_threads += diff;
      gomp_mutex_unlock (&gomp_remaining_threads_lock);
      gomp_mutex_unlock (&gomp_remaining_threads_lock);
#endif
#endif
    }
    }
}
}
 
 
 
 
/* Terminate the current team.  This is only to be called by the master
/* Terminate the current team.  This is only to be called by the master
   thread.  We assume that we must wait for the other threads.  */
   thread.  We assume that we must wait for the other threads.  */
 
 
void
void
gomp_team_end (void)
gomp_team_end (void)
{
{
  struct gomp_thread *thr = gomp_thread ();
  struct gomp_thread *thr = gomp_thread ();
  struct gomp_team *team = thr->ts.team;
  struct gomp_team *team = thr->ts.team;
 
 
  /* This barrier handles all pending explicit threads.  */
  /* This barrier handles all pending explicit threads.  */
  gomp_team_barrier_wait (&team->barrier);
  gomp_team_barrier_wait (&team->barrier);
  gomp_fini_work_share (thr->ts.work_share);
  gomp_fini_work_share (thr->ts.work_share);
 
 
  gomp_end_task ();
  gomp_end_task ();
  thr->ts = team->prev_ts;
  thr->ts = team->prev_ts;
 
 
  if (__builtin_expect (thr->ts.team != NULL, 0))
  if (__builtin_expect (thr->ts.team != NULL, 0))
    {
    {
#ifdef HAVE_SYNC_BUILTINS
#ifdef HAVE_SYNC_BUILTINS
      __sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
      __sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
#else
#else
      gomp_mutex_lock (&gomp_remaining_threads_lock);
      gomp_mutex_lock (&gomp_remaining_threads_lock);
      gomp_managed_threads -= team->nthreads - 1L;
      gomp_managed_threads -= team->nthreads - 1L;
      gomp_mutex_unlock (&gomp_remaining_threads_lock);
      gomp_mutex_unlock (&gomp_remaining_threads_lock);
#endif
#endif
      /* This barrier has gomp_barrier_wait_last counterparts
      /* This barrier has gomp_barrier_wait_last counterparts
         and ensures the team can be safely destroyed.  */
         and ensures the team can be safely destroyed.  */
      gomp_barrier_wait (&team->barrier);
      gomp_barrier_wait (&team->barrier);
    }
    }
 
 
  if (__builtin_expect (team->work_shares[0].next_alloc != NULL, 0))
  if (__builtin_expect (team->work_shares[0].next_alloc != NULL, 0))
    {
    {
      struct gomp_work_share *ws = team->work_shares[0].next_alloc;
      struct gomp_work_share *ws = team->work_shares[0].next_alloc;
      do
      do
        {
        {
          struct gomp_work_share *next_ws = ws->next_alloc;
          struct gomp_work_share *next_ws = ws->next_alloc;
          free (ws);
          free (ws);
          ws = next_ws;
          ws = next_ws;
        }
        }
      while (ws != NULL);
      while (ws != NULL);
    }
    }
  gomp_sem_destroy (&team->master_release);
  gomp_sem_destroy (&team->master_release);
#ifndef HAVE_SYNC_BUILTINS
#ifndef HAVE_SYNC_BUILTINS
  gomp_mutex_destroy (&team->work_share_list_free_lock);
  gomp_mutex_destroy (&team->work_share_list_free_lock);
#endif
#endif
 
 
  if (__builtin_expect (thr->ts.team != NULL, 0)
  if (__builtin_expect (thr->ts.team != NULL, 0)
      || __builtin_expect (team->nthreads == 1, 0))
      || __builtin_expect (team->nthreads == 1, 0))
    free_team (team);
    free_team (team);
  else
  else
    {
    {
      struct gomp_thread_pool *pool = thr->thread_pool;
      struct gomp_thread_pool *pool = thr->thread_pool;
      if (pool->last_team)
      if (pool->last_team)
        free_team (pool->last_team);
        free_team (pool->last_team);
      pool->last_team = team;
      pool->last_team = team;
    }
    }
}
}
 
 
 
 
/* Constructors for this file.  */
/* Constructors for this file.  */
 
 
static void __attribute__((constructor))
static void __attribute__((constructor))
initialize_team (void)
initialize_team (void)
{
{
  struct gomp_thread *thr;
  struct gomp_thread *thr;
 
 
#ifndef HAVE_TLS
#ifndef HAVE_TLS
  static struct gomp_thread initial_thread_tls_data;
  static struct gomp_thread initial_thread_tls_data;
 
 
  pthread_key_create (&gomp_tls_key, NULL);
  pthread_key_create (&gomp_tls_key, NULL);
  pthread_setspecific (gomp_tls_key, &initial_thread_tls_data);
  pthread_setspecific (gomp_tls_key, &initial_thread_tls_data);
#endif
#endif
 
 
  if (pthread_key_create (&gomp_thread_destructor, gomp_free_thread) != 0)
  if (pthread_key_create (&gomp_thread_destructor, gomp_free_thread) != 0)
    gomp_fatal ("could not create thread pool destructor.");
    gomp_fatal ("could not create thread pool destructor.");
 
 
#ifdef HAVE_TLS
#ifdef HAVE_TLS
  thr = &gomp_tls_data;
  thr = &gomp_tls_data;
#else
#else
  thr = &initial_thread_tls_data;
  thr = &initial_thread_tls_data;
#endif
#endif
  gomp_sem_init (&thr->release, 0);
  gomp_sem_init (&thr->release, 0);
}
}
 
 
static void __attribute__((destructor))
static void __attribute__((destructor))
team_destructor (void)
team_destructor (void)
{
{
  /* Without this dlclose on libgomp could lead to subsequent
  /* Without this dlclose on libgomp could lead to subsequent
     crashes.  */
     crashes.  */
  pthread_key_delete (gomp_thread_destructor);
  pthread_key_delete (gomp_thread_destructor);
}
}
 
 
struct gomp_task_icv *
struct gomp_task_icv *
gomp_new_icv (void)
gomp_new_icv (void)
{
{
  struct gomp_thread *thr = gomp_thread ();
  struct gomp_thread *thr = gomp_thread ();
  struct gomp_task *task = gomp_malloc (sizeof (struct gomp_task));
  struct gomp_task *task = gomp_malloc (sizeof (struct gomp_task));
  gomp_init_task (task, NULL, &gomp_global_icv);
  gomp_init_task (task, NULL, &gomp_global_icv);
  thr->task = task;
  thr->task = task;
  pthread_setspecific (gomp_thread_destructor, thr);
  pthread_setspecific (gomp_thread_destructor, thr);
  return &task->icv;
  return &task->icv;
}
}
 
 

powered by: WebSVN 2.1.0

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