@@ -174,6 +174,10 @@ OMP_5.0 {
omp_get_affinity_format_;
omp_set_affinity_format;
omp_set_affinity_format_;
+ omp_pause_resource;
+ omp_pause_resource_;
+ omp_pause_resource_all;
+ omp_pause_resource_all_;
} OMP_4.5;
GOMP_1.0 {
@@ -83,6 +83,12 @@ typedef struct __attribute__((__aligned_
char __omp_depend_t__[2 * sizeof (void *)];
} omp_depend_t;
+typedef enum omp_pause_resource_t
+{
+ omp_pause_soft = 1,
+ omp_pause_hard = 2
+} omp_pause_resource_t;
+
#ifdef __cplusplus
extern "C" {
# define __GOMP_NOTHROW throw ()
@@ -178,6 +184,9 @@ extern void omp_display_affinity (const
extern __SIZE_TYPE__ omp_capture_affinity (char *, __SIZE_TYPE__, const char *)
__GOMP_NOTHROW;
+extern int omp_pause_resource (omp_pause_resource_t, int) __GOMP_NOTHROW;
+extern int omp_pause_resource_all (omp_pause_resource_t) __GOMP_NOTHROW;
+
#ifdef __cplusplus
}
#endif
@@ -30,6 +30,7 @@
integer, parameter :: omp_sched_kind = 4
integer, parameter :: omp_proc_bind_kind = 4
integer, parameter :: omp_lock_hint_kind = 4
+ integer, parameter :: omp_pause_resource_kind = 4
integer (omp_sched_kind), parameter :: omp_sched_static = 1
integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2
integer (omp_sched_kind), parameter :: omp_sched_guided = 3
@@ -54,6 +55,10 @@
parameter :: omp_lock_hint_nonspeculative = 4
integer (omp_lock_hint_kind), &
parameter :: omp_lock_hint_speculative = 8
+ integer (kind=omp_pause_resource_kind), &
+ parameter :: omp_pause_soft = 1
+ integer (kind=omp_pause_resource_kind), &
+ parameter :: omp_pause_hard = 2
end module
module omp_lib
@@ -460,4 +465,23 @@
end function omp_capture_affinity
end interface
+ interface
+ function omp_pause_resource (kind, device_num)
+ use omp_lib_kinds
+ integer (4) :: omp_pause_resource
+ integer (kind=omp_pause_resource_kind), &
+ intent(in) :: kind
+ integer (4) :: device_num
+ end function
+ end interface
+
+ interface
+ function omp_pause_resource_all (kind)
+ use omp_lib_kinds
+ integer (4) :: omp_pause_resource_all
+ integer (kind=omp_pause_resource_kind), &
+ intent(in) :: kind
+ end function
+ end interface
+
end module omp_lib
@@ -59,6 +59,12 @@
parameter (omp_lock_hint_nonspeculative = 4)
parameter (omp_lock_hint_speculative = 8)
parameter (openmp_version = 201511)
+ integer omp_pause_resource_kind
+ parameter (omp_pause_resource_kind = 4)
+ integer (omp_pause_resource_kind) omp_pause_soft
+ integer (omp_pause_resource_kind) omp_pause_hard
+ parameter (omp_pause_soft = 1)
+ parameter (omp_pause_hard = 2)
external omp_init_lock, omp_init_nest_lock
external omp_init_lock_with_hint
@@ -131,3 +137,7 @@
external omp_display_affinity, omp_capture_affinity
integer(4) omp_get_affinity_format
integer(4) omp_capture_affinity
+
+ external omp_pause_resource, omp_pause_resource_all
+ integer(4) omp_pause_resource
+ integer(4) omp_pause_resource_all
@@ -821,6 +821,7 @@ extern void gomp_team_start (void (*) (v
unsigned, struct gomp_team *);
extern void gomp_team_end (void);
extern void gomp_free_thread (void *);
+extern int gomp_pause_host (void);
/* target.c */
@@ -32,7 +32,6 @@
#include <string.h>
#ifdef LIBGOMP_USE_PTHREADS
-/* This attribute contains PTHREAD_CREATE_DETACHED. */
pthread_attr_t gomp_thread_attr;
/* This key is for the thread destructor. */
@@ -135,6 +134,7 @@ gomp_thread_start (void *xdata)
}
gomp_sem_destroy (&thr->release);
+ pthread_detach (pthread_self ());
thr->thread_pool = NULL;
thr->task = NULL;
return NULL;
@@ -235,6 +235,7 @@ gomp_free_pool_helper (void *thread_pool
thr->thread_pool = NULL;
thr->task = NULL;
#ifdef LIBGOMP_USE_PTHREADS
+ pthread_detach (pthread_self ());
pthread_exit (NULL);
#elif defined(__nvptx__)
asm ("exit;");
@@ -726,7 +727,6 @@ gomp_team_start (void (*fn) (void *), vo
{
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;
@@ -1010,6 +1010,76 @@ team_destructor (void)
crashes. */
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__
+ free (pool->threads);
+ free (pool);
+#endif
+ thr->thread_pool = NULL;
+ }
+ return 0;
+}
#endif
struct gomp_task_icv *
@@ -2503,6 +2503,31 @@ omp_target_disassociate_ptr (const void
return ret;
}
+int
+omp_pause_resource (omp_pause_resource_t kind, int device_num)
+{
+ (void) kind;
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
+ return gomp_pause_host ();
+ if (device_num < 0 || device_num >= gomp_get_num_devices ())
+ return -1;
+ /* Do nothing for target devices for now. */
+ return 0;
+}
+
+int
+omp_pause_resource_all (omp_pause_resource_t kind)
+{
+ (void) kind;
+ if (gomp_pause_host ())
+ return -1;
+ /* Do nothing for target devices for now. */
+ return 0;
+}
+
+ialias (omp_pause_resource)
+ialias (omp_pause_resource_all)
+
#ifdef PLUGIN_SUPPORT
/* This function tries to load a plugin for DEVICE. Name of plugin is passed
@@ -1348,7 +1348,6 @@ initialize_env (void)
/* Not strictly environment related, but ordering constructors is tricky. */
pthread_attr_init (&gomp_thread_attr);
- pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
|| parse_stacksize ("GOMP_STACKSIZE", &stacksize)
@@ -84,6 +84,8 @@ ialias_redirect (omp_get_team_num)
ialias_redirect (omp_is_initial_device)
ialias_redirect (omp_get_initial_device)
ialias_redirect (omp_get_max_task_priority)
+ialias_redirect (omp_pause_resource)
+ialias_redirect (omp_pause_resource_all)
#endif
#ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
@@ -659,3 +661,15 @@ omp_capture_affinity_ (char *buffer, con
memset (buffer + ret, ' ', buffer_len - ret);
return ret;
}
+
+int32_t
+omp_pause_resource_ (const int32_t *kind, const int32_t *device_num)
+{
+ return omp_pause_resource (*kind, *device_num);
+}
+
+int32_t
+omp_pause_resource_all_ (const int32_t *kind)
+{
+ return omp_pause_resource_all (*kind);
+}
@@ -174,5 +174,11 @@ gomp_team_start (void (*fn) (void *), vo
gomp_simple_barrier_wait (&pool->threads_dock);
}
+int
+gomp_pause_host (void)
+{
+ return -1;
+}
+
#include "../../team.c"
#endif
@@ -47,3 +47,21 @@ GOMP_teams (unsigned int num_teams, unsi
}
gomp_num_teams_var = num_teams - 1;
}
+
+int
+omp_pause_resource (omp_pause_resource_t kind, int device_num)
+{
+ (void) kind;
+ (void) device_num;
+ return -1;
+}
+
+int
+omp_pause_resource_all (omp_pause_resource_t kind)
+{
+ (void) kind;
+ return -1;
+}
+
+ialias (omp_pause_resource)
+ialias (omp_pause_resource_all)
@@ -0,0 +1,23 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int a[64];
+
+int
+main ()
+{
+ int i;
+ #pragma omp parallel for
+ for (i = 0; i < 64; i++)
+ a[i] = i;
+ omp_pause_resource (omp_pause_soft, omp_get_initial_device ());
+ #pragma omp parallel for
+ for (i = 0; i < 64; i++)
+ a[i] += i;
+ omp_pause_resource_all (omp_pause_hard);
+ #pragma omp parallel for
+ for (i = 0; i < 64; i++)
+ if (a[i] != 2 * i)
+ abort ();
+ return 0;
+}
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-require-effective-target tls_runtime } */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int t = 128;
+#pragma omp threadprivate (t)
+
+int
+main ()
+{
+ #pragma omp parallel
+ t = omp_get_thread_num () + 256;
+ #pragma omp parallel
+ if (t != omp_get_thread_num () + 256)
+ abort ();
+ omp_pause_resource (omp_pause_soft, omp_get_initial_device ());
+ /* This goes beyond what is required by the standard, we actually
+ check if the threads other than the initial one have been destroyed. */
+ #pragma omp parallel
+ {
+ if (omp_get_thread_num () != 0 && t != 128)
+ abort ();
+ t = omp_get_thread_num () + 384;
+ }
+ #pragma omp parallel
+ if (t != omp_get_thread_num () + 384)
+ abort ();
+ omp_pause_resource_all (omp_pause_hard);
+ #pragma omp parallel
+ {
+ if (omp_get_thread_num () != 0 && t != 128)
+ abort ();
+ t = omp_get_thread_num () + 512;
+ }
+ #pragma omp parallel
+ if (t != omp_get_thread_num () + 512)
+ abort ();
+ return 0;
+}