197403Sobrien/* Copyright (C) 2015-2020 Free Software Foundation, Inc.
297403Sobrien   Contributed by Sebastian Huber <sebastian.huber@embedded-brains.de>.
3117397Skan
497403Sobrien   This file is part of the GNU Offloading and Multi Processing Library
5103447Skan   (libgomp).
6103447Skan
7103447Skan   Libgomp is free software; you can redistribute it and/or modify it
8103447Skan   under the terms of the GNU General Public License as published by
997403Sobrien   the Free Software Foundation; either version 3, or (at your option)
10103447Skan   any later version.
11103447Skan
1297403Sobrien   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
1397403Sobrien   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1497403Sobrien   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1597403Sobrien   more details.
16103447Skan
17103447Skan   Under Section 7 of GPL version 3, you are granted additional
18169691Skan   permissions described in the GCC Runtime Library Exception, version
19103447Skan   3.1, as published by the Free Software Foundation.
20103447Skan
2197403Sobrien   You should have received a copy of the GNU General Public License and
2297403Sobrien   a copy of the GCC Runtime Library Exception along with this program;
2397403Sobrien   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2497403Sobrien   <http://www.gnu.org/licenses/>.  */
2597403Sobrien
2697403Sobrien/* This is the RTEMS implementation of the thread pool management
2797403Sobrien   for libgomp.  This type is private to the library.  */
2897403Sobrien
2997403Sobrien#ifndef GOMP_POOL_H
3097403Sobrien#define GOMP_POOL_H 1
3197403Sobrien
3297403Sobrien#include "libgomp.h"
3397403Sobrien#include <sys/lock.h>
3497403Sobrien#include <string.h>
3597403Sobrien
3697403Sobrien/* For each scheduler instance there may be a thread pool reservoir
3797403Sobrien   to limit the number of thread pools used by the OpenMP master threads of this
3897403Sobrien   scheduler instance.  The reservoirs are configured via the
39132720Skan   GOMP_RTEMS_THREAD_POOLS environment variable.  */
4097403Sobrienstruct gomp_thread_pool_reservoir {
4197403Sobrien  gomp_sem_t available;
42117397Skan  pthread_spinlock_t lock;
4397403Sobrien  size_t index;
4497403Sobrien  int priority;
4597403Sobrien  struct gomp_thread_pool *pools[];
4697403Sobrien};
47169691Skan
48169691Skanstruct gomp_tls_rtems_data {
4997403Sobrien  struct gomp_thread_pool_reservoir *thread_pool_reservoir;
5097403Sobrien};
5197403Sobrien
5297403Sobrienextern struct gomp_thread_pool_reservoir **gomp_thread_pool_reservoirs;
5397403Sobrien
5497403Sobrienextern __thread struct gomp_tls_rtems_data gomp_tls_rtems_data;
5597403Sobrien
5697403Sobrienstatic inline struct gomp_thread_pool_reservoir *
57132720Skangomp_get_thread_pool_reservoir (void)
5897403Sobrien{
5997403Sobrien  struct gomp_thread_pool_reservoir *res =
6097403Sobrien    gomp_tls_rtems_data.thread_pool_reservoir;
6197403Sobrien
6297403Sobrien  if (res == NULL && gomp_thread_pool_reservoirs != NULL)
6397403Sobrien    {
6497403Sobrien      struct gomp_thread *thr = gomp_thread ();
6597403Sobrien      thr->thread_pool = gomp_malloc_cleared (sizeof (*thr->thread_pool));
6697403Sobrien      res = gomp_thread_pool_reservoirs[_Sched_Index ()];
6797403Sobrien      gomp_tls_rtems_data.thread_pool_reservoir = res;
6897403Sobrien    }
6997403Sobrien
7097403Sobrien  return res;
7197403Sobrien}
7297403Sobrien
7397403Sobrienstatic inline struct gomp_thread_pool *
7497403Sobriengomp_get_own_thread_pool (struct gomp_thread *thr, unsigned nthreads)
7597403Sobrien{
7697403Sobrien  struct gomp_thread_pool *pool = thr->thread_pool;
7797403Sobrien  if (__builtin_expect (pool == NULL, 0))
78132720Skan    {
7997403Sobrien      pool = gomp_malloc_cleared (sizeof (*pool));
8097403Sobrien      pool->threads_busy = nthreads;
8197403Sobrien      thr->thread_pool = pool;
8297403Sobrien    }
8397403Sobrien  return pool;
8497403Sobrien}
8597403Sobrien
8697403Sobrienstatic inline struct gomp_thread_pool *
8797403Sobriengomp_get_thread_pool (struct gomp_thread *thr, unsigned nthreads)
8897403Sobrien{
8997403Sobrien  struct gomp_thread_pool *pool;
9097403Sobrien  struct gomp_thread_pool_reservoir *res;
9197403Sobrien
9297403Sobrien  if (__builtin_expect (thr->thread_pool == NULL, 0))
93132720Skan    pthread_setspecific (gomp_thread_destructor, thr);
9497403Sobrien
9597403Sobrien  res = gomp_get_thread_pool_reservoir ();
9697403Sobrien  if (res != NULL)
9797403Sobrien    {
9897403Sobrien      gomp_sem_wait (&res->available);
9997403Sobrien      pthread_spin_lock (&res->lock);
10097403Sobrien      pool = res->pools[--res->index];
10197403Sobrien      pthread_spin_unlock (&res->lock);
10297403Sobrien      pool->threads_busy = nthreads;
10397403Sobrien      thr->thread_pool = pool;
10497403Sobrien    }
10597403Sobrien  else
10697403Sobrien    pool = gomp_get_own_thread_pool (thr, nthreads);
10797403Sobrien
10897403Sobrien  return pool;
109169691Skan}
110169691Skan
11197403Sobrienstatic inline void
11297403Sobriengomp_release_thread_pool (struct gomp_thread_pool *pool)
11397403Sobrien{
114  struct gomp_thread_pool_reservoir *res =
115    gomp_tls_rtems_data.thread_pool_reservoir;
116  if (res != NULL)
117    {
118      pthread_spin_lock (&res->lock);
119      res->pools[res->index++] = pool;
120      pthread_spin_unlock (&res->lock);
121      gomp_sem_post (&res->available);
122    }
123}
124
125static inline pthread_attr_t *
126gomp_adjust_thread_attr (pthread_attr_t *attr, pthread_attr_t *mutable_attr)
127{
128  struct gomp_thread_pool_reservoir *res = gomp_get_thread_pool_reservoir ();
129  if (res != NULL && res->priority > 0)
130    {
131      struct sched_param param;
132      int err;
133      if (attr != mutable_attr)
134	{
135	  attr = mutable_attr;
136	  pthread_attr_init (attr);
137	}
138      memset (&param, 0, sizeof (param));
139      param.sched_priority = res->priority;
140      err = pthread_attr_setschedparam (attr, &param);
141      if (err != 0)
142	gomp_fatal ("Thread attribute set scheduler parameters failed: %s", strerror (err));
143      err = pthread_attr_setschedpolicy (attr, SCHED_FIFO);
144      if (err != 0)
145	gomp_fatal ("Thread attribute set scheduler policy failed: %s", strerror (err));
146      err = pthread_attr_setinheritsched (attr, PTHREAD_EXPLICIT_SCHED);
147      if (err != 0)
148	gomp_fatal ("Thread attribute set explicit scheduler failed: %s", strerror (err));
149    }
150  return attr;
151}
152
153#endif /* GOMP_POOL_H */
154