c++: Respect current_constraint_diagnosis_depth in diagnose_compound_requirement
[gcc.git] / libgomp / team.c
index de5b915f78b81798b37a4a631c3f54eeb1e1815b..82f26a05687e7bf36ac11db17452573bfd2ef481 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2016 Free Software Foundation, Inc.
+/* Copyright (C) 2005-2020 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU Offloading and Multi Processing Library
@@ -23,7 +23,7 @@
    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
-/* This file handles the maintainence of threads in response to team
+/* This file handles the maintenance of threads in response to team
    creation and termination.  */
 
 #include "libgomp.h"
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-/* This attribute contains PTHREAD_CREATE_DETACHED.  */
+#ifdef LIBGOMP_USE_PTHREADS
 pthread_attr_t gomp_thread_attr;
 
 /* This key is for the thread destructor.  */
@@ -57,6 +57,7 @@ struct gomp_thread_start_data
   struct gomp_thread_pool *thread_pool;
   unsigned int place;
   bool nested;
+  pthread_t handle;
 };
 
 
@@ -88,6 +89,9 @@ gomp_thread_start (void *xdata)
   thr->ts = data->ts;
   thr->task = data->task;
   thr->place = data->place;
+#ifdef GOMP_NEEDS_THREAD_HANDLE
+  thr->handle = data->handle;
+#endif
 
   thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
 
@@ -110,7 +114,7 @@ gomp_thread_start (void *xdata)
     {
       pool->threads[thr->ts.team_id] = thr;
 
-      gomp_barrier_wait (&pool->threads_dock);
+      gomp_simple_barrier_wait (&pool->threads_dock);
       do
        {
          struct gomp_team *team = thr->ts.team;
@@ -120,7 +124,7 @@ gomp_thread_start (void *xdata)
          gomp_team_barrier_wait_final (&team->barrier);
          gomp_finish_task (task);
 
-         gomp_barrier_wait (&pool->threads_dock);
+         gomp_simple_barrier_wait (&pool->threads_dock);
 
          local_fn = thr->fn;
          local_data = thr->data;
@@ -130,10 +134,12 @@ gomp_thread_start (void *xdata)
     }
 
   gomp_sem_destroy (&thr->release);
+  pthread_detach (pthread_self ());
   thr->thread_pool = NULL;
   thr->task = NULL;
   return NULL;
 }
+#endif
 
 static inline struct gomp_team *
 get_last_team (unsigned nthreads)
@@ -165,7 +171,7 @@ gomp_new_team (unsigned nthreads)
     {
       size_t extra = sizeof (team->ordered_release[0])
                     + sizeof (team->implicit_task[0]);
-      team = gomp_malloc (sizeof (*team) + nthreads * extra);
+      team = team_malloc (sizeof (*team) + nthreads * extra);
 
 #ifndef HAVE_SYNC_BUILTINS
       gomp_mutex_init (&team->work_share_list_free_lock);
@@ -181,7 +187,7 @@ gomp_new_team (unsigned nthreads)
   team->single_count = 0;
 #endif
   team->work_shares_to_free = &team->work_shares[0];
-  gomp_init_work_share (&team->work_shares[0], false, nthreads);
+  gomp_init_work_share (&team->work_shares[0], 0, nthreads);
   team->work_shares[0].next_alloc = NULL;
   team->work_share_list_free = NULL;
   team->work_share_list_alloc = &team->work_shares[1];
@@ -215,7 +221,7 @@ free_team (struct gomp_team *team)
   gomp_barrier_destroy (&team->barrier);
   gomp_mutex_destroy (&team->task_lock);
   priority_queue_free (&team->task_queue);
-  free (team);
+  team_free (team);
 }
 
 static void
@@ -224,11 +230,21 @@ gomp_free_pool_helper (void *thread_pool)
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_thread_pool *pool
     = (struct gomp_thread_pool *) thread_pool;
-  gomp_barrier_wait_last (&pool->threads_dock);
+  gomp_simple_barrier_wait_last (&pool->threads_dock);
   gomp_sem_destroy (&thr->release);
   thr->thread_pool = NULL;
   thr->task = NULL;
+#ifdef LIBGOMP_USE_PTHREADS
+  pthread_detach (pthread_self ());
   pthread_exit (NULL);
+#elif defined(__nvptx__)
+  asm ("exit;");
+#elif defined(__AMDGCN__)
+  asm ("s_dcache_wb\n\t"
+       "s_endpgm");
+#else
+#error gomp_free_pool_helper must terminate the thread
+#endif
 }
 
 /* Free a thread pool and release its threads. */
@@ -250,12 +266,12 @@ gomp_free_thread (void *arg __attribute__((unused)))
              nthr->data = pool;
            }
          /* This barrier undocks threads docked on pool->threads_dock.  */
-         gomp_barrier_wait (&pool->threads_dock);
+         gomp_simple_barrier_wait (&pool->threads_dock);
          /* And this waits till all threads have called gomp_barrier_wait_last
             in gomp_free_pool_helper.  */
-         gomp_barrier_wait (&pool->threads_dock);
+         gomp_simple_barrier_wait (&pool->threads_dock);
          /* Now it is safe to destroy the barrier and free the pool.  */
-         gomp_barrier_destroy (&pool->threads_dock);
+         gomp_simple_barrier_destroy (&pool->threads_dock);
 
 #ifdef HAVE_SYNC_BUILTINS
          __sync_fetch_and_add (&gomp_managed_threads,
@@ -266,10 +282,12 @@ gomp_free_thread (void *arg __attribute__((unused)))
          gomp_mutex_unlock (&gomp_managed_threads_lock);
 #endif
        }
-      free (pool->threads);
       if (pool->last_team)
        free_team (pool->last_team);
-      free (pool);
+#ifndef __nvptx__
+      team_free (pool->threads);
+      team_free (pool);
+#endif
       thr->thread_pool = NULL;
     }
   if (thr->ts.level == 0 && __builtin_expect (thr->ts.team != NULL, 0))
@@ -284,9 +302,11 @@ gomp_free_thread (void *arg __attribute__((unused)))
 
 /* Launch a team.  */
 
+#ifdef LIBGOMP_USE_PTHREADS
 void
 gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
-                unsigned flags, struct gomp_team *team)
+                unsigned flags, struct gomp_team *team,
+                struct gomp_taskgroup *taskgroup)
 {
   struct gomp_thread_start_data *start_data;
   struct gomp_thread *thr, *nthr;
@@ -301,6 +321,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
   unsigned int s = 0, rest = 0, p = 0, k = 0;
   unsigned int affinity_count = 0;
   struct gomp_thread **affinity_thr = NULL;
+  bool force_display = false;
 
   thr = gomp_thread ();
   nested = thr->ts.level;
@@ -308,7 +329,12 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
   task = thr->task;
   icv = task ? &task->icv : &gomp_global_icv;
   if (__builtin_expect (gomp_places_list != NULL, 0) && thr->place == 0)
-    gomp_init_affinity ();
+    {
+      gomp_init_affinity ();
+      if (__builtin_expect (gomp_display_affinity_var, 0) && nthreads == 1)
+       gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
+                                     thr->place);
+    }
 
   /* 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
@@ -327,6 +353,9 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
 #endif
   thr->ts.static_trip = 0;
   thr->task = &team->implicit_task[0];
+#ifdef GOMP_NEEDS_THREAD_HANDLE
+  thr->handle = pthread_self ();
+#endif
   nthreads_var = icv->nthreads_var;
   if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
       && thr->ts.level < gomp_nthreads_var_list_len)
@@ -339,6 +368,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       && thr->ts.level < gomp_bind_var_list_len)
     bind_var = gomp_bind_var_list[thr->ts.level];
   gomp_init_task (thr->task, task, icv);
+  thr->task->taskgroup = taskgroup;
   team->implicit_task[0].icv.nthreads_var = nthreads_var;
   team->implicit_task[0].icv.bind_var = bind_var;
 
@@ -429,7 +459,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       else if (old_threads_used == 0)
        {
          n = 0;
-         gomp_barrier_init (&pool->threads_dock, nthreads);
+         gomp_simple_barrier_init (&pool->threads_dock, nthreads);
        }
       else
        {
@@ -437,7 +467,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
 
          /* Increase the barrier threshold to make sure all new
             threads arrive before the team is released.  */
-         gomp_barrier_reinit (&pool->threads_dock, nthreads);
+         gomp_simple_barrier_reinit (&pool->threads_dock, nthreads);
        }
 
       /* Not true yet, but soon will be.  We're going to release all
@@ -454,7 +484,9 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
          pool->threads
            = gomp_realloc (pool->threads,
                            pool->threads_size
-                           * sizeof (struct gomp_thread_data *));
+                           * sizeof (struct gomp_thread *));
+         /* Add current (master) thread to threads[].  */
+         pool->threads[0] = thr;
        }
 
       /* Release existing idle threads.  */
@@ -529,6 +561,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
                                                + place_partition_len))
                {
                  unsigned int l;
+                 force_display = true;
                  if (affinity_thr == NULL)
                    {
                      unsigned int j;
@@ -612,6 +645,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
          gomp_init_task (nthr->task, task, icv);
          team->implicit_task[i].icv.nthreads_var = nthreads_var;
          team->implicit_task[i].icv.bind_var = bind_var;
+         nthr->task->taskgroup = taskgroup;
          nthr->fn = fn;
          nthr->data = data;
          team->ordered_release[i] = &nthr->release;
@@ -670,8 +704,8 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
                 threads and all the threads we're going to let die
                 arrive before the team is released.  */
              if (affinity_count)
-               gomp_barrier_reinit (&pool->threads_dock,
-                                    nthreads + affinity_count);
+               gomp_simple_barrier_reinit (&pool->threads_dock,
+                                           nthreads + affinity_count);
            }
        }
 
@@ -701,19 +735,17 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
     {
       size_t stacksize;
       pthread_attr_init (&thread_attr);
-      pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
       if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
        pthread_attr_setstacksize (&thread_attr, stacksize);
       attr = &thread_attr;
     }
 
   start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
-                           * (nthreads-i));
+                           * (nthreads - i));
 
   /* Launch new threads.  */
   for (; i < nthreads; ++i)
     {
-      pthread_t pt;
       int err;
 
       start_data->ts.place_partition_off = thr->ts.place_partition_off;
@@ -799,11 +831,14 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       gomp_init_task (start_data->task, task, icv);
       team->implicit_task[i].icv.nthreads_var = nthreads_var;
       team->implicit_task[i].icv.bind_var = bind_var;
+      start_data->task->taskgroup = taskgroup;
       start_data->thread_pool = pool;
       start_data->nested = nested;
 
       attr = gomp_adjust_thread_attr (attr, &thread_attr);
-      err = pthread_create (&pt, attr, gomp_thread_start, start_data++);
+      err = pthread_create (&start_data->handle, attr, gomp_thread_start,
+                           start_data);
+      start_data++;
       if (err != 0)
        gomp_fatal ("Thread creation failed: %s", strerror (err));
     }
@@ -812,7 +847,10 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
     pthread_attr_destroy (&thread_attr);
 
  do_release:
-  gomp_barrier_wait (nested ? &team->barrier : &pool->threads_dock);
+  if (nested)
+    gomp_barrier_wait (&team->barrier);
+  else
+    gomp_simple_barrier_wait (&pool->threads_dock);
 
   /* Decrease the barrier threshold to match the number of threads
      that should arrive back at the end of this team.  The extra
@@ -830,7 +868,7 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       if (affinity_count)
        diff = -affinity_count;
 
-      gomp_barrier_reinit (&pool->threads_dock, nthreads);
+      gomp_simple_barrier_reinit (&pool->threads_dock, nthreads);
 
 #ifdef HAVE_SYNC_BUILTINS
       __sync_fetch_and_add (&gomp_managed_threads, diff);
@@ -840,10 +878,47 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
       gomp_mutex_unlock (&gomp_managed_threads_lock);
 #endif
     }
+  if (__builtin_expect (gomp_display_affinity_var, 0))
+    {
+      if (nested
+         || nthreads != old_threads_used
+         || force_display)
+       {
+         gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
+                                       thr->place);
+         if (nested)
+           {
+             start_data -= nthreads - 1;
+             for (i = 1; i < nthreads; ++i)
+               {
+                 gomp_display_affinity_thread (
+#ifdef LIBGOMP_USE_PTHREADS
+                                               start_data->handle,
+#else
+                                               gomp_thread_self (),
+#endif
+                                               &start_data->ts,
+                                               start_data->place);
+                 start_data++;
+               }
+           }
+         else
+           {
+             for (i = 1; i < nthreads; ++i)
+               {
+                 gomp_thread_handle handle
+                   = gomp_thread_to_pthread_t (pool->threads[i]);
+                 gomp_display_affinity_thread (handle, &pool->threads[i]->ts,
+                                               pool->threads[i]->place);
+               }
+           }
+       }
+    }
   if (__builtin_expect (affinity_thr != NULL, 0)
       && team->prev_ts.place_partition_len > 64)
     free (affinity_thr);
 }
+#endif
 
 
 /* Terminate the current team.  This is only to be called by the master
@@ -879,7 +954,7 @@ gomp_team_end (void)
   gomp_end_task ();
   thr->ts = team->prev_ts;
 
-  if (__builtin_expect (thr->ts.team != NULL, 0))
+  if (__builtin_expect (thr->ts.level != 0, 0))
     {
 #ifdef HAVE_SYNC_BUILTINS
       __sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
@@ -919,6 +994,7 @@ gomp_team_end (void)
     }
 }
 
+#ifdef LIBGOMP_USE_PTHREADS
 
 /* Constructors for this file.  */
 
@@ -944,6 +1020,77 @@ team_destructor (void)
   pthread_key_delete (gomp_thread_destructor);
 }
 
+/* Similar to gomp_free_pool_helper, but don't detach itself,
+   gomp_pause_host will pthread_join those threads.  */
+
+static void
+gomp_pause_pool_helper (void *thread_pool)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_thread_pool *pool
+    = (struct gomp_thread_pool *) thread_pool;
+  gomp_simple_barrier_wait_last (&pool->threads_dock);
+  gomp_sem_destroy (&thr->release);
+  thr->thread_pool = NULL;
+  thr->task = NULL;
+  pthread_exit (NULL);
+}
+
+/* Free a thread pool and release its threads.  Return non-zero on
+   failure.  */
+
+int
+gomp_pause_host (void)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_thread_pool *pool = thr->thread_pool;
+  if (thr->ts.level)
+    return -1;
+  if (pool)
+    {
+      if (pool->threads_used > 0)
+       {
+         int i;
+         pthread_t *thrs
+           = gomp_alloca (sizeof (pthread_t) * pool->threads_used);
+         for (i = 1; i < pool->threads_used; i++)
+           {
+             struct gomp_thread *nthr = pool->threads[i];
+             nthr->fn = gomp_pause_pool_helper;
+             nthr->data = pool;
+             thrs[i] = gomp_thread_to_pthread_t (nthr);
+           }
+         /* This barrier undocks threads docked on pool->threads_dock.  */
+         gomp_simple_barrier_wait (&pool->threads_dock);
+         /* And this waits till all threads have called gomp_barrier_wait_last
+            in gomp_pause_pool_helper.  */
+         gomp_simple_barrier_wait (&pool->threads_dock);
+         /* Now it is safe to destroy the barrier and free the pool.  */
+         gomp_simple_barrier_destroy (&pool->threads_dock);
+
+#ifdef HAVE_SYNC_BUILTINS
+         __sync_fetch_and_add (&gomp_managed_threads,
+                               1L - pool->threads_used);
+#else
+         gomp_mutex_lock (&gomp_managed_threads_lock);
+         gomp_managed_threads -= pool->threads_used - 1L;
+         gomp_mutex_unlock (&gomp_managed_threads_lock);
+#endif
+         for (i = 1; i < pool->threads_used; i++)
+           pthread_join (thrs[i], NULL);
+       }
+      if (pool->last_team)
+       free_team (pool->last_team);
+#ifndef __nvptx__
+      team_free (pool->threads);
+      team_free (pool);
+#endif
+      thr->thread_pool = NULL;
+    }
+  return 0;
+}
+#endif
+
 struct gomp_task_icv *
 gomp_new_icv (void)
 {
@@ -951,6 +1098,8 @@ gomp_new_icv (void)
   struct gomp_task *task = gomp_malloc (sizeof (struct gomp_task));
   gomp_init_task (task, NULL, &gomp_global_icv);
   thr->task = task;
+#ifdef LIBGOMP_USE_PTHREADS
   pthread_setspecific (gomp_thread_destructor, thr);
+#endif
   return &task->icv;
 }