Home | History | Annotate | Line # | Download | only in libgomp
      1  1.1.1.2  mrg /* Copyright (C) 2020-2024 Free Software Foundation, Inc.
      2      1.1  mrg    Contributed by Jakub Jelinek <jakub (at) redhat.com>.
      3      1.1  mrg 
      4      1.1  mrg    This file is part of the GNU Offloading and Multi Processing Library
      5      1.1  mrg    (libgomp).
      6      1.1  mrg 
      7      1.1  mrg    Libgomp is free software; you can redistribute it and/or modify it
      8      1.1  mrg    under the terms of the GNU General Public License as published by
      9      1.1  mrg    the Free Software Foundation; either version 3, or (at your option)
     10      1.1  mrg    any later version.
     11      1.1  mrg 
     12      1.1  mrg    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
     13      1.1  mrg    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     14      1.1  mrg    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     15      1.1  mrg    more details.
     16      1.1  mrg 
     17      1.1  mrg    Under Section 7 of GPL version 3, you are granted additional
     18      1.1  mrg    permissions described in the GCC Runtime Library Exception, version
     19      1.1  mrg    3.1, as published by the Free Software Foundation.
     20      1.1  mrg 
     21      1.1  mrg    You should have received a copy of the GNU General Public License and
     22      1.1  mrg    a copy of the GCC Runtime Library Exception along with this program;
     23      1.1  mrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24      1.1  mrg    <http://www.gnu.org/licenses/>.  */
     25      1.1  mrg 
     26      1.1  mrg /* This file contains wrappers for the system allocation routines.  Most
     27      1.1  mrg    places in the OpenMP API do not make any provision for failure, so in
     28      1.1  mrg    general we cannot allow memory allocation to fail.  */
     29      1.1  mrg 
     30      1.1  mrg #define _GNU_SOURCE
     31      1.1  mrg #include "libgomp.h"
     32      1.1  mrg #include <stdlib.h>
     33      1.1  mrg #include <string.h>
     34  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
     35  1.1.1.2  mrg #include <dlfcn.h>
     36  1.1.1.2  mrg #endif
     37  1.1.1.2  mrg 
     38  1.1.1.2  mrg /* Keeping track whether a Fortran scalar allocatable/pointer has been
     39  1.1.1.2  mrg    allocated via 'omp allocators'/'omp allocate'.  */
     40  1.1.1.2  mrg 
     41  1.1.1.2  mrg struct fort_alloc_splay_tree_key_s {
     42  1.1.1.2  mrg   void *ptr;
     43  1.1.1.2  mrg };
     44  1.1.1.2  mrg 
     45  1.1.1.2  mrg typedef struct fort_alloc_splay_tree_node_s *fort_alloc_splay_tree_node;
     46  1.1.1.2  mrg typedef struct fort_alloc_splay_tree_s *fort_alloc_splay_tree;
     47  1.1.1.2  mrg typedef struct fort_alloc_splay_tree_key_s *fort_alloc_splay_tree_key;
     48  1.1.1.2  mrg 
     49  1.1.1.2  mrg static inline int
     50  1.1.1.2  mrg fort_alloc_splay_compare (fort_alloc_splay_tree_key x, fort_alloc_splay_tree_key y)
     51  1.1.1.2  mrg {
     52  1.1.1.2  mrg   if (x->ptr < y->ptr)
     53  1.1.1.2  mrg     return -1;
     54  1.1.1.2  mrg   if (x->ptr > y->ptr)
     55  1.1.1.2  mrg     return 1;
     56  1.1.1.2  mrg   return 0;
     57  1.1.1.2  mrg }
     58  1.1.1.2  mrg #define splay_tree_prefix fort_alloc
     59  1.1.1.2  mrg #define splay_tree_static
     60  1.1.1.2  mrg #include "splay-tree.h"
     61  1.1.1.2  mrg 
     62  1.1.1.2  mrg #define splay_tree_prefix fort_alloc
     63  1.1.1.2  mrg #define splay_tree_static
     64  1.1.1.2  mrg #define splay_tree_c
     65  1.1.1.2  mrg #include "splay-tree.h"
     66  1.1.1.2  mrg 
     67  1.1.1.2  mrg static struct fort_alloc_splay_tree_s fort_alloc_scalars;
     68  1.1.1.2  mrg 
     69  1.1.1.2  mrg /* Add pointer as being alloced by GOMP_alloc.  */
     70  1.1.1.2  mrg void
     71  1.1.1.2  mrg GOMP_add_alloc (void *ptr)
     72  1.1.1.2  mrg {
     73  1.1.1.2  mrg   if (ptr == NULL)
     74  1.1.1.2  mrg     return;
     75  1.1.1.2  mrg   fort_alloc_splay_tree_node item;
     76  1.1.1.2  mrg   item = gomp_malloc (sizeof (struct splay_tree_node_s));
     77  1.1.1.2  mrg   item->key.ptr = ptr;
     78  1.1.1.2  mrg   item->left = NULL;
     79  1.1.1.2  mrg   item->right = NULL;
     80  1.1.1.2  mrg   fort_alloc_splay_tree_insert (&fort_alloc_scalars, item);
     81  1.1.1.2  mrg }
     82  1.1.1.2  mrg 
     83  1.1.1.2  mrg /* Remove pointer, either called by FREE or by REALLOC,
     84  1.1.1.2  mrg    either of them can change the allocation status.  */
     85  1.1.1.2  mrg bool
     86  1.1.1.2  mrg GOMP_is_alloc (void *ptr)
     87  1.1.1.2  mrg {
     88  1.1.1.2  mrg   struct fort_alloc_splay_tree_key_s needle;
     89  1.1.1.2  mrg   fort_alloc_splay_tree_node n;
     90  1.1.1.2  mrg   needle.ptr = ptr;
     91  1.1.1.2  mrg   n = fort_alloc_splay_tree_lookup_node (&fort_alloc_scalars, &needle);
     92  1.1.1.2  mrg   if (n)
     93  1.1.1.2  mrg     {
     94  1.1.1.2  mrg       fort_alloc_splay_tree_remove (&fort_alloc_scalars, &n->key);
     95  1.1.1.2  mrg       free (n);
     96  1.1.1.2  mrg     }
     97  1.1.1.2  mrg   return n != NULL;
     98  1.1.1.2  mrg }
     99  1.1.1.2  mrg 
    100      1.1  mrg 
    101      1.1  mrg #define omp_max_predefined_alloc omp_thread_mem_alloc
    102      1.1  mrg 
    103  1.1.1.2  mrg /* These macros may be overridden in config/<target>/allocator.c.
    104  1.1.1.2  mrg    The defaults (no override) are to return NULL for pinned memory requests
    105  1.1.1.2  mrg    and pass through to the regular OS calls otherwise.
    106  1.1.1.2  mrg    The following definitions (ab)use comma operators to avoid unused
    107  1.1.1.2  mrg    variable errors.  */
    108  1.1.1.2  mrg #ifndef MEMSPACE_ALLOC
    109  1.1.1.2  mrg #define MEMSPACE_ALLOC(MEMSPACE, SIZE, PIN) \
    110  1.1.1.2  mrg   (PIN ? NULL : malloc (((void)(MEMSPACE), (SIZE))))
    111  1.1.1.2  mrg #endif
    112  1.1.1.2  mrg #ifndef MEMSPACE_CALLOC
    113  1.1.1.2  mrg #define MEMSPACE_CALLOC(MEMSPACE, SIZE, PIN) \
    114  1.1.1.2  mrg   (PIN ? NULL : calloc (1, (((void)(MEMSPACE), (SIZE)))))
    115  1.1.1.2  mrg #endif
    116  1.1.1.2  mrg #ifndef MEMSPACE_REALLOC
    117  1.1.1.2  mrg #define MEMSPACE_REALLOC(MEMSPACE, ADDR, OLDSIZE, SIZE, OLDPIN, PIN) \
    118  1.1.1.2  mrg    ((PIN) || (OLDPIN) ? NULL \
    119  1.1.1.2  mrg    : realloc (ADDR, (((void)(MEMSPACE), (void)(OLDSIZE), (SIZE)))))
    120  1.1.1.2  mrg #endif
    121  1.1.1.2  mrg #ifndef MEMSPACE_FREE
    122  1.1.1.2  mrg #define MEMSPACE_FREE(MEMSPACE, ADDR, SIZE, PIN) \
    123  1.1.1.2  mrg   if (PIN) free (((void)(MEMSPACE), (void)(SIZE), (ADDR)))
    124  1.1.1.2  mrg #endif
    125  1.1.1.2  mrg #ifndef MEMSPACE_VALIDATE
    126  1.1.1.2  mrg #define MEMSPACE_VALIDATE(MEMSPACE, ACCESS, PIN) \
    127  1.1.1.2  mrg   (PIN ? 0 : ((void)(MEMSPACE), (void)(ACCESS), 1))
    128  1.1.1.2  mrg #endif
    129  1.1.1.2  mrg 
    130  1.1.1.2  mrg /* Map the predefined allocators to the correct memory space.
    131  1.1.1.2  mrg    The index to this table is the omp_allocator_handle_t enum value.
    132  1.1.1.2  mrg    When the user calls omp_alloc with a predefined allocator this
    133  1.1.1.2  mrg    table determines what memory they get.  */
    134  1.1.1.2  mrg static const omp_memspace_handle_t predefined_alloc_mapping[] = {
    135  1.1.1.2  mrg   omp_default_mem_space,   /* omp_null_allocator doesn't actually use this. */
    136  1.1.1.2  mrg   omp_default_mem_space,   /* omp_default_mem_alloc. */
    137  1.1.1.2  mrg   omp_large_cap_mem_space, /* omp_large_cap_mem_alloc. */
    138  1.1.1.2  mrg   omp_const_mem_space,     /* omp_const_mem_alloc. */
    139  1.1.1.2  mrg   omp_high_bw_mem_space,   /* omp_high_bw_mem_alloc. */
    140  1.1.1.2  mrg   omp_low_lat_mem_space,   /* omp_low_lat_mem_alloc. */
    141  1.1.1.2  mrg   omp_low_lat_mem_space,   /* omp_cgroup_mem_alloc (implementation defined). */
    142  1.1.1.2  mrg   omp_low_lat_mem_space,   /* omp_pteam_mem_alloc (implementation defined). */
    143  1.1.1.2  mrg   omp_low_lat_mem_space,   /* omp_thread_mem_alloc (implementation defined). */
    144  1.1.1.2  mrg };
    145  1.1.1.2  mrg 
    146  1.1.1.2  mrg #define ARRAY_SIZE(A) (sizeof (A) / sizeof ((A)[0]))
    147  1.1.1.2  mrg _Static_assert (ARRAY_SIZE (predefined_alloc_mapping)
    148  1.1.1.2  mrg 		== omp_max_predefined_alloc + 1,
    149  1.1.1.2  mrg 		"predefined_alloc_mapping must match omp_memspace_handle_t");
    150  1.1.1.2  mrg 
    151  1.1.1.2  mrg enum gomp_numa_memkind_kind
    152  1.1.1.2  mrg {
    153  1.1.1.2  mrg   GOMP_MEMKIND_NONE = 0,
    154  1.1.1.2  mrg #define GOMP_MEMKIND_KINDS \
    155  1.1.1.2  mrg   GOMP_MEMKIND_KIND (HBW_INTERLEAVE),		\
    156  1.1.1.2  mrg   GOMP_MEMKIND_KIND (HBW_PREFERRED),		\
    157  1.1.1.2  mrg   GOMP_MEMKIND_KIND (DAX_KMEM_ALL),		\
    158  1.1.1.2  mrg   GOMP_MEMKIND_KIND (DAX_KMEM),			\
    159  1.1.1.2  mrg   GOMP_MEMKIND_KIND (INTERLEAVE),		\
    160  1.1.1.2  mrg   GOMP_MEMKIND_KIND (DEFAULT)
    161  1.1.1.2  mrg #define GOMP_MEMKIND_KIND(kind) GOMP_MEMKIND_##kind
    162  1.1.1.2  mrg   GOMP_MEMKIND_KINDS,
    163  1.1.1.2  mrg #undef GOMP_MEMKIND_KIND
    164  1.1.1.2  mrg   GOMP_MEMKIND_COUNT,
    165  1.1.1.2  mrg   GOMP_MEMKIND_LIBNUMA = GOMP_MEMKIND_COUNT
    166  1.1.1.2  mrg };
    167  1.1.1.2  mrg 
    168      1.1  mrg struct omp_allocator_data
    169      1.1  mrg {
    170      1.1  mrg   omp_memspace_handle_t memspace;
    171      1.1  mrg   omp_uintptr_t alignment;
    172      1.1  mrg   omp_uintptr_t pool_size;
    173      1.1  mrg   omp_uintptr_t used_pool_size;
    174      1.1  mrg   omp_allocator_handle_t fb_data;
    175      1.1  mrg   unsigned int sync_hint : 8;
    176      1.1  mrg   unsigned int access : 8;
    177      1.1  mrg   unsigned int fallback : 8;
    178      1.1  mrg   unsigned int pinned : 1;
    179      1.1  mrg   unsigned int partition : 7;
    180  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    181  1.1.1.2  mrg   unsigned int memkind : 8;
    182  1.1.1.2  mrg #endif
    183      1.1  mrg #ifndef HAVE_SYNC_BUILTINS
    184      1.1  mrg   gomp_mutex_t lock;
    185      1.1  mrg #endif
    186      1.1  mrg };
    187      1.1  mrg 
    188      1.1  mrg struct omp_mem_header
    189      1.1  mrg {
    190      1.1  mrg   void *ptr;
    191      1.1  mrg   size_t size;
    192      1.1  mrg   omp_allocator_handle_t allocator;
    193      1.1  mrg   void *pad;
    194      1.1  mrg };
    195      1.1  mrg 
    196  1.1.1.2  mrg struct gomp_libnuma_data
    197  1.1.1.2  mrg {
    198  1.1.1.2  mrg   void *numa_handle;
    199  1.1.1.2  mrg   void *(*numa_alloc_local) (size_t);
    200  1.1.1.2  mrg   void *(*numa_realloc) (void *, size_t, size_t);
    201  1.1.1.2  mrg   void (*numa_free) (void *, size_t);
    202  1.1.1.2  mrg };
    203  1.1.1.2  mrg 
    204  1.1.1.2  mrg struct gomp_memkind_data
    205  1.1.1.2  mrg {
    206  1.1.1.2  mrg   void *memkind_handle;
    207  1.1.1.2  mrg   void *(*memkind_malloc) (void *, size_t);
    208  1.1.1.2  mrg   void *(*memkind_calloc) (void *, size_t, size_t);
    209  1.1.1.2  mrg   void *(*memkind_realloc) (void *, void *, size_t);
    210  1.1.1.2  mrg   void (*memkind_free) (void *, void *);
    211  1.1.1.2  mrg   int (*memkind_check_available) (void *);
    212  1.1.1.2  mrg   void **kinds[GOMP_MEMKIND_COUNT];
    213  1.1.1.2  mrg };
    214  1.1.1.2  mrg 
    215  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    216  1.1.1.2  mrg static struct gomp_libnuma_data *libnuma_data;
    217  1.1.1.2  mrg static pthread_once_t libnuma_data_once = PTHREAD_ONCE_INIT;
    218  1.1.1.2  mrg 
    219  1.1.1.2  mrg static void
    220  1.1.1.2  mrg gomp_init_libnuma (void)
    221  1.1.1.2  mrg {
    222  1.1.1.2  mrg   void *handle = dlopen ("libnuma.so.1", RTLD_LAZY);
    223  1.1.1.2  mrg   struct gomp_libnuma_data *data;
    224  1.1.1.2  mrg 
    225  1.1.1.2  mrg   data = calloc (1, sizeof (struct gomp_libnuma_data));
    226  1.1.1.2  mrg   if (data == NULL)
    227  1.1.1.2  mrg     {
    228  1.1.1.2  mrg       if (handle)
    229  1.1.1.2  mrg 	dlclose (handle);
    230  1.1.1.2  mrg       return;
    231  1.1.1.2  mrg     }
    232  1.1.1.2  mrg   if (handle)
    233  1.1.1.2  mrg     {
    234  1.1.1.2  mrg       int (*numa_available) (void);
    235  1.1.1.2  mrg       numa_available
    236  1.1.1.2  mrg 	= (__typeof (numa_available)) dlsym (handle, "numa_available");
    237  1.1.1.2  mrg       if (!numa_available || numa_available () != 0)
    238  1.1.1.2  mrg 	{
    239  1.1.1.2  mrg 	  dlclose (handle);
    240  1.1.1.2  mrg 	  handle = NULL;
    241  1.1.1.2  mrg 	}
    242  1.1.1.2  mrg     }
    243  1.1.1.2  mrg   if (!handle)
    244  1.1.1.2  mrg     {
    245  1.1.1.2  mrg       __atomic_store_n (&libnuma_data, data, MEMMODEL_RELEASE);
    246  1.1.1.2  mrg       return;
    247  1.1.1.2  mrg     }
    248  1.1.1.2  mrg   data->numa_handle = handle;
    249  1.1.1.2  mrg   data->numa_alloc_local
    250  1.1.1.2  mrg     = (__typeof (data->numa_alloc_local)) dlsym (handle, "numa_alloc_local");
    251  1.1.1.2  mrg   data->numa_realloc
    252  1.1.1.2  mrg     = (__typeof (data->numa_realloc)) dlsym (handle, "numa_realloc");
    253  1.1.1.2  mrg   data->numa_free
    254  1.1.1.2  mrg     = (__typeof (data->numa_free)) dlsym (handle, "numa_free");
    255  1.1.1.2  mrg   __atomic_store_n (&libnuma_data, data, MEMMODEL_RELEASE);
    256  1.1.1.2  mrg }
    257  1.1.1.2  mrg 
    258  1.1.1.2  mrg static struct gomp_libnuma_data *
    259  1.1.1.2  mrg gomp_get_libnuma (void)
    260  1.1.1.2  mrg {
    261  1.1.1.2  mrg   struct gomp_libnuma_data *data
    262  1.1.1.2  mrg     = __atomic_load_n (&libnuma_data, MEMMODEL_ACQUIRE);
    263  1.1.1.2  mrg   if (data)
    264  1.1.1.2  mrg     return data;
    265  1.1.1.2  mrg   pthread_once (&libnuma_data_once, gomp_init_libnuma);
    266  1.1.1.2  mrg   return __atomic_load_n (&libnuma_data, MEMMODEL_ACQUIRE);
    267  1.1.1.2  mrg }
    268  1.1.1.2  mrg #endif
    269  1.1.1.2  mrg 
    270  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    271  1.1.1.2  mrg static struct gomp_memkind_data *memkind_data;
    272  1.1.1.2  mrg static pthread_once_t memkind_data_once = PTHREAD_ONCE_INIT;
    273  1.1.1.2  mrg 
    274  1.1.1.2  mrg static void
    275  1.1.1.2  mrg gomp_init_memkind (void)
    276  1.1.1.2  mrg {
    277  1.1.1.2  mrg   void *handle = dlopen ("libmemkind.so.0", RTLD_LAZY);
    278  1.1.1.2  mrg   struct gomp_memkind_data *data;
    279  1.1.1.2  mrg   int i;
    280  1.1.1.2  mrg   static const char *kinds[] = {
    281  1.1.1.2  mrg     NULL,
    282  1.1.1.2  mrg #define GOMP_MEMKIND_KIND(kind) "MEMKIND_" #kind
    283  1.1.1.2  mrg     GOMP_MEMKIND_KINDS
    284  1.1.1.2  mrg #undef GOMP_MEMKIND_KIND
    285  1.1.1.2  mrg   };
    286  1.1.1.2  mrg 
    287  1.1.1.2  mrg   data = calloc (1, sizeof (struct gomp_memkind_data));
    288  1.1.1.2  mrg   if (data == NULL)
    289  1.1.1.2  mrg     {
    290  1.1.1.2  mrg       if (handle)
    291  1.1.1.2  mrg 	dlclose (handle);
    292  1.1.1.2  mrg       return;
    293  1.1.1.2  mrg     }
    294  1.1.1.2  mrg   if (!handle)
    295  1.1.1.2  mrg     {
    296  1.1.1.2  mrg       __atomic_store_n (&memkind_data, data, MEMMODEL_RELEASE);
    297  1.1.1.2  mrg       return;
    298  1.1.1.2  mrg     }
    299  1.1.1.2  mrg   data->memkind_handle = handle;
    300  1.1.1.2  mrg   data->memkind_malloc
    301  1.1.1.2  mrg     = (__typeof (data->memkind_malloc)) dlsym (handle, "memkind_malloc");
    302  1.1.1.2  mrg   data->memkind_calloc
    303  1.1.1.2  mrg     = (__typeof (data->memkind_calloc)) dlsym (handle, "memkind_calloc");
    304  1.1.1.2  mrg   data->memkind_realloc
    305  1.1.1.2  mrg     = (__typeof (data->memkind_realloc)) dlsym (handle, "memkind_realloc");
    306  1.1.1.2  mrg   data->memkind_free
    307  1.1.1.2  mrg     = (__typeof (data->memkind_free)) dlsym (handle, "memkind_free");
    308  1.1.1.2  mrg   data->memkind_check_available
    309  1.1.1.2  mrg     = (__typeof (data->memkind_check_available))
    310  1.1.1.2  mrg       dlsym (handle, "memkind_check_available");
    311  1.1.1.2  mrg   if (data->memkind_malloc
    312  1.1.1.2  mrg       && data->memkind_calloc
    313  1.1.1.2  mrg       && data->memkind_realloc
    314  1.1.1.2  mrg       && data->memkind_free
    315  1.1.1.2  mrg       && data->memkind_check_available)
    316  1.1.1.2  mrg     for (i = 1; i < GOMP_MEMKIND_COUNT; ++i)
    317  1.1.1.2  mrg       {
    318  1.1.1.2  mrg 	data->kinds[i] = (void **) dlsym (handle, kinds[i]);
    319  1.1.1.2  mrg 	if (data->kinds[i] && data->memkind_check_available (*data->kinds[i]))
    320  1.1.1.2  mrg 	  data->kinds[i] = NULL;
    321  1.1.1.2  mrg       }
    322  1.1.1.2  mrg   __atomic_store_n (&memkind_data, data, MEMMODEL_RELEASE);
    323  1.1.1.2  mrg }
    324  1.1.1.2  mrg 
    325  1.1.1.2  mrg static struct gomp_memkind_data *
    326  1.1.1.2  mrg gomp_get_memkind (void)
    327  1.1.1.2  mrg {
    328  1.1.1.2  mrg   struct gomp_memkind_data *data
    329  1.1.1.2  mrg     = __atomic_load_n (&memkind_data, MEMMODEL_ACQUIRE);
    330  1.1.1.2  mrg   if (data)
    331  1.1.1.2  mrg     return data;
    332  1.1.1.2  mrg   pthread_once (&memkind_data_once, gomp_init_memkind);
    333  1.1.1.2  mrg   return __atomic_load_n (&memkind_data, MEMMODEL_ACQUIRE);
    334  1.1.1.2  mrg }
    335  1.1.1.2  mrg #endif
    336  1.1.1.2  mrg 
    337      1.1  mrg omp_allocator_handle_t
    338      1.1  mrg omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,
    339      1.1  mrg 		    const omp_alloctrait_t traits[])
    340      1.1  mrg {
    341      1.1  mrg   struct omp_allocator_data data
    342      1.1  mrg     = { memspace, 1, ~(uintptr_t) 0, 0, 0, omp_atv_contended, omp_atv_all,
    343  1.1.1.2  mrg 	omp_atv_default_mem_fb, omp_atv_false, omp_atv_environment,
    344  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    345  1.1.1.2  mrg 	GOMP_MEMKIND_NONE
    346  1.1.1.2  mrg #endif
    347  1.1.1.2  mrg       };
    348      1.1  mrg   struct omp_allocator_data *ret;
    349      1.1  mrg   int i;
    350      1.1  mrg 
    351      1.1  mrg   if (memspace > omp_low_lat_mem_space)
    352      1.1  mrg     return omp_null_allocator;
    353      1.1  mrg   for (i = 0; i < ntraits; i++)
    354      1.1  mrg     switch (traits[i].key)
    355      1.1  mrg       {
    356      1.1  mrg       case omp_atk_sync_hint:
    357      1.1  mrg 	switch (traits[i].value)
    358      1.1  mrg 	  {
    359      1.1  mrg 	  case omp_atv_default:
    360      1.1  mrg 	    data.sync_hint = omp_atv_contended;
    361      1.1  mrg 	    break;
    362      1.1  mrg 	  case omp_atv_contended:
    363      1.1  mrg 	  case omp_atv_uncontended:
    364      1.1  mrg 	  case omp_atv_serialized:
    365      1.1  mrg 	  case omp_atv_private:
    366      1.1  mrg 	    data.sync_hint = traits[i].value;
    367      1.1  mrg 	    break;
    368      1.1  mrg 	  default:
    369      1.1  mrg 	    return omp_null_allocator;
    370      1.1  mrg 	  }
    371      1.1  mrg 	break;
    372      1.1  mrg       case omp_atk_alignment:
    373      1.1  mrg         if (traits[i].value == omp_atv_default)
    374      1.1  mrg 	  {
    375      1.1  mrg 	    data.alignment = 1;
    376      1.1  mrg 	    break;
    377      1.1  mrg 	  }
    378      1.1  mrg 	if ((traits[i].value & (traits[i].value - 1)) != 0
    379      1.1  mrg 	    || !traits[i].value)
    380      1.1  mrg 	  return omp_null_allocator;
    381      1.1  mrg 	data.alignment = traits[i].value;
    382      1.1  mrg 	break;
    383      1.1  mrg       case omp_atk_access:
    384      1.1  mrg 	switch (traits[i].value)
    385      1.1  mrg 	  {
    386      1.1  mrg 	  case omp_atv_default:
    387      1.1  mrg 	    data.access = omp_atv_all;
    388      1.1  mrg 	    break;
    389      1.1  mrg 	  case omp_atv_all:
    390      1.1  mrg 	  case omp_atv_cgroup:
    391      1.1  mrg 	  case omp_atv_pteam:
    392      1.1  mrg 	  case omp_atv_thread:
    393      1.1  mrg 	    data.access = traits[i].value;
    394      1.1  mrg 	    break;
    395      1.1  mrg 	  default:
    396      1.1  mrg 	    return omp_null_allocator;
    397      1.1  mrg 	  }
    398      1.1  mrg 	break;
    399      1.1  mrg       case omp_atk_pool_size:
    400      1.1  mrg 	if (traits[i].value == omp_atv_default)
    401      1.1  mrg 	  data.pool_size = ~(uintptr_t) 0;
    402      1.1  mrg 	else
    403      1.1  mrg 	  data.pool_size = traits[i].value;
    404      1.1  mrg 	break;
    405      1.1  mrg       case omp_atk_fallback:
    406      1.1  mrg 	switch (traits[i].value)
    407      1.1  mrg 	  {
    408      1.1  mrg 	  case omp_atv_default:
    409      1.1  mrg 	    data.fallback = omp_atv_default_mem_fb;
    410      1.1  mrg 	    break;
    411      1.1  mrg 	  case omp_atv_default_mem_fb:
    412      1.1  mrg 	  case omp_atv_null_fb:
    413      1.1  mrg 	  case omp_atv_abort_fb:
    414      1.1  mrg 	  case omp_atv_allocator_fb:
    415      1.1  mrg 	    data.fallback = traits[i].value;
    416      1.1  mrg 	    break;
    417      1.1  mrg 	  default:
    418      1.1  mrg 	    return omp_null_allocator;
    419      1.1  mrg 	  }
    420      1.1  mrg 	break;
    421      1.1  mrg       case omp_atk_fb_data:
    422      1.1  mrg 	data.fb_data = traits[i].value;
    423      1.1  mrg 	break;
    424      1.1  mrg       case omp_atk_pinned:
    425      1.1  mrg 	switch (traits[i].value)
    426      1.1  mrg 	  {
    427      1.1  mrg 	  case omp_atv_default:
    428      1.1  mrg 	  case omp_atv_false:
    429      1.1  mrg 	    data.pinned = omp_atv_false;
    430      1.1  mrg 	    break;
    431      1.1  mrg 	  case omp_atv_true:
    432      1.1  mrg 	    data.pinned = omp_atv_true;
    433      1.1  mrg 	    break;
    434      1.1  mrg 	  default:
    435      1.1  mrg 	    return omp_null_allocator;
    436      1.1  mrg 	  }
    437      1.1  mrg 	break;
    438      1.1  mrg       case omp_atk_partition:
    439      1.1  mrg 	switch (traits[i].value)
    440      1.1  mrg 	  {
    441      1.1  mrg 	  case omp_atv_default:
    442      1.1  mrg 	    data.partition = omp_atv_environment;
    443      1.1  mrg 	    break;
    444      1.1  mrg 	  case omp_atv_environment:
    445      1.1  mrg 	  case omp_atv_nearest:
    446      1.1  mrg 	  case omp_atv_blocked:
    447      1.1  mrg 	  case omp_atv_interleaved:
    448      1.1  mrg 	    data.partition = traits[i].value;
    449      1.1  mrg 	    break;
    450      1.1  mrg 	  default:
    451      1.1  mrg 	    return omp_null_allocator;
    452      1.1  mrg 	  }
    453      1.1  mrg 	break;
    454      1.1  mrg       default:
    455      1.1  mrg 	return omp_null_allocator;
    456      1.1  mrg       }
    457      1.1  mrg 
    458      1.1  mrg   if (data.alignment < sizeof (void *))
    459      1.1  mrg     data.alignment = sizeof (void *);
    460      1.1  mrg 
    461  1.1.1.2  mrg   switch (memspace)
    462  1.1.1.2  mrg     {
    463  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    464  1.1.1.2  mrg     case omp_high_bw_mem_space:
    465  1.1.1.2  mrg       struct gomp_memkind_data *memkind_data;
    466  1.1.1.2  mrg       memkind_data = gomp_get_memkind ();
    467  1.1.1.2  mrg       if (data.partition == omp_atv_interleaved
    468  1.1.1.2  mrg 	  && memkind_data->kinds[GOMP_MEMKIND_HBW_INTERLEAVE])
    469  1.1.1.2  mrg 	{
    470  1.1.1.2  mrg 	  data.memkind = GOMP_MEMKIND_HBW_INTERLEAVE;
    471  1.1.1.2  mrg 	  break;
    472  1.1.1.2  mrg 	}
    473  1.1.1.2  mrg       else if (memkind_data->kinds[GOMP_MEMKIND_HBW_PREFERRED])
    474  1.1.1.2  mrg 	{
    475  1.1.1.2  mrg 	  data.memkind = GOMP_MEMKIND_HBW_PREFERRED;
    476  1.1.1.2  mrg 	  break;
    477  1.1.1.2  mrg 	}
    478  1.1.1.2  mrg       break;
    479  1.1.1.2  mrg     case omp_large_cap_mem_space:
    480  1.1.1.2  mrg       memkind_data = gomp_get_memkind ();
    481  1.1.1.2  mrg       if (memkind_data->kinds[GOMP_MEMKIND_DAX_KMEM_ALL])
    482  1.1.1.2  mrg 	data.memkind = GOMP_MEMKIND_DAX_KMEM_ALL;
    483  1.1.1.2  mrg       else if (memkind_data->kinds[GOMP_MEMKIND_DAX_KMEM])
    484  1.1.1.2  mrg 	data.memkind = GOMP_MEMKIND_DAX_KMEM;
    485  1.1.1.2  mrg       break;
    486  1.1.1.2  mrg #endif
    487  1.1.1.2  mrg     default:
    488  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    489  1.1.1.2  mrg       if (data.partition == omp_atv_interleaved)
    490  1.1.1.2  mrg 	{
    491  1.1.1.2  mrg 	  memkind_data = gomp_get_memkind ();
    492  1.1.1.2  mrg 	  if (memkind_data->kinds[GOMP_MEMKIND_INTERLEAVE])
    493  1.1.1.2  mrg 	    data.memkind = GOMP_MEMKIND_INTERLEAVE;
    494  1.1.1.2  mrg 	}
    495  1.1.1.2  mrg #endif
    496  1.1.1.2  mrg       break;
    497  1.1.1.2  mrg     }
    498  1.1.1.2  mrg 
    499  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    500  1.1.1.2  mrg   if (data.memkind == GOMP_MEMKIND_NONE && data.partition == omp_atv_nearest)
    501  1.1.1.2  mrg     {
    502  1.1.1.2  mrg       libnuma_data = gomp_get_libnuma ();
    503  1.1.1.2  mrg       if (libnuma_data->numa_alloc_local != NULL)
    504  1.1.1.2  mrg 	data.memkind = GOMP_MEMKIND_LIBNUMA;
    505  1.1.1.2  mrg     }
    506  1.1.1.2  mrg #endif
    507  1.1.1.2  mrg 
    508  1.1.1.2  mrg   /* Reject unsupported memory spaces.  */
    509  1.1.1.2  mrg   if (!MEMSPACE_VALIDATE (data.memspace, data.access, data.pinned))
    510      1.1  mrg     return omp_null_allocator;
    511      1.1  mrg 
    512      1.1  mrg   ret = gomp_malloc (sizeof (struct omp_allocator_data));
    513      1.1  mrg   *ret = data;
    514      1.1  mrg #ifndef HAVE_SYNC_BUILTINS
    515      1.1  mrg   gomp_mutex_init (&ret->lock);
    516      1.1  mrg #endif
    517      1.1  mrg   return (omp_allocator_handle_t) ret;
    518      1.1  mrg }
    519      1.1  mrg 
    520      1.1  mrg void
    521      1.1  mrg omp_destroy_allocator (omp_allocator_handle_t allocator)
    522      1.1  mrg {
    523      1.1  mrg   if (allocator != omp_null_allocator)
    524      1.1  mrg     {
    525      1.1  mrg #ifndef HAVE_SYNC_BUILTINS
    526      1.1  mrg       gomp_mutex_destroy (&((struct omp_allocator_data *) allocator)->lock);
    527      1.1  mrg #endif
    528      1.1  mrg       free ((void *) allocator);
    529      1.1  mrg     }
    530      1.1  mrg }
    531      1.1  mrg 
    532      1.1  mrg ialias (omp_init_allocator)
    533      1.1  mrg ialias (omp_destroy_allocator)
    534      1.1  mrg 
    535      1.1  mrg void *
    536      1.1  mrg omp_aligned_alloc (size_t alignment, size_t size,
    537      1.1  mrg 		   omp_allocator_handle_t allocator)
    538      1.1  mrg {
    539      1.1  mrg   struct omp_allocator_data *allocator_data;
    540      1.1  mrg   size_t new_size, new_alignment;
    541      1.1  mrg   void *ptr, *ret;
    542  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    543  1.1.1.2  mrg   enum gomp_numa_memkind_kind memkind;
    544  1.1.1.2  mrg #endif
    545      1.1  mrg 
    546      1.1  mrg   if (__builtin_expect (size == 0, 0))
    547      1.1  mrg     return NULL;
    548      1.1  mrg 
    549      1.1  mrg retry:
    550      1.1  mrg   new_alignment = alignment;
    551      1.1  mrg   if (allocator == omp_null_allocator)
    552      1.1  mrg     {
    553      1.1  mrg       struct gomp_thread *thr = gomp_thread ();
    554      1.1  mrg       if (thr->ts.def_allocator == omp_null_allocator)
    555      1.1  mrg 	thr->ts.def_allocator = gomp_def_allocator;
    556      1.1  mrg       allocator = (omp_allocator_handle_t) thr->ts.def_allocator;
    557      1.1  mrg     }
    558      1.1  mrg 
    559      1.1  mrg   if (allocator > omp_max_predefined_alloc)
    560      1.1  mrg     {
    561      1.1  mrg       allocator_data = (struct omp_allocator_data *) allocator;
    562      1.1  mrg       if (new_alignment < allocator_data->alignment)
    563      1.1  mrg 	new_alignment = allocator_data->alignment;
    564  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    565  1.1.1.2  mrg       memkind = allocator_data->memkind;
    566  1.1.1.2  mrg #endif
    567      1.1  mrg     }
    568      1.1  mrg   else
    569      1.1  mrg     {
    570      1.1  mrg       allocator_data = NULL;
    571      1.1  mrg       if (new_alignment < sizeof (void *))
    572      1.1  mrg 	new_alignment = sizeof (void *);
    573  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    574  1.1.1.2  mrg       memkind = GOMP_MEMKIND_NONE;
    575  1.1.1.2  mrg #endif
    576  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    577  1.1.1.2  mrg       if (allocator == omp_high_bw_mem_alloc)
    578  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_HBW_PREFERRED;
    579  1.1.1.2  mrg       else if (allocator == omp_large_cap_mem_alloc)
    580  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_DAX_KMEM_ALL;
    581  1.1.1.2  mrg       if (memkind)
    582  1.1.1.2  mrg 	{
    583  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    584  1.1.1.2  mrg 	  if (!memkind_data->kinds[memkind])
    585  1.1.1.2  mrg 	    memkind = GOMP_MEMKIND_NONE;
    586  1.1.1.2  mrg 	}
    587  1.1.1.2  mrg #endif
    588      1.1  mrg     }
    589      1.1  mrg 
    590      1.1  mrg   new_size = sizeof (struct omp_mem_header);
    591      1.1  mrg   if (new_alignment > sizeof (void *))
    592      1.1  mrg     new_size += new_alignment - sizeof (void *);
    593      1.1  mrg   if (__builtin_add_overflow (size, new_size, &new_size))
    594      1.1  mrg     goto fail;
    595  1.1.1.2  mrg #ifdef OMP_LOW_LAT_MEM_ALLOC_INVALID
    596  1.1.1.2  mrg   if (allocator == omp_low_lat_mem_alloc)
    597  1.1.1.2  mrg     goto fail;
    598  1.1.1.2  mrg #endif
    599      1.1  mrg 
    600      1.1  mrg   if (__builtin_expect (allocator_data
    601      1.1  mrg 			&& allocator_data->pool_size < ~(uintptr_t) 0, 0))
    602      1.1  mrg     {
    603      1.1  mrg       uintptr_t used_pool_size;
    604      1.1  mrg       if (new_size > allocator_data->pool_size)
    605      1.1  mrg 	goto fail;
    606      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
    607      1.1  mrg       used_pool_size = __atomic_load_n (&allocator_data->used_pool_size,
    608      1.1  mrg 					MEMMODEL_RELAXED);
    609      1.1  mrg       do
    610      1.1  mrg 	{
    611      1.1  mrg 	  uintptr_t new_pool_size;
    612      1.1  mrg 	  if (__builtin_add_overflow (used_pool_size, new_size,
    613      1.1  mrg 				      &new_pool_size)
    614      1.1  mrg 	      || new_pool_size > allocator_data->pool_size)
    615      1.1  mrg 	    goto fail;
    616      1.1  mrg 	  if (__atomic_compare_exchange_n (&allocator_data->used_pool_size,
    617      1.1  mrg 					   &used_pool_size, new_pool_size,
    618      1.1  mrg 					   true, MEMMODEL_RELAXED,
    619      1.1  mrg 					   MEMMODEL_RELAXED))
    620      1.1  mrg 	    break;
    621      1.1  mrg 	}
    622      1.1  mrg       while (1);
    623      1.1  mrg #else
    624      1.1  mrg       gomp_mutex_lock (&allocator_data->lock);
    625      1.1  mrg       if (__builtin_add_overflow (allocator_data->used_pool_size, new_size,
    626      1.1  mrg 				  &used_pool_size)
    627      1.1  mrg 	  || used_pool_size > allocator_data->pool_size)
    628      1.1  mrg 	{
    629      1.1  mrg 	  gomp_mutex_unlock (&allocator_data->lock);
    630      1.1  mrg 	  goto fail;
    631      1.1  mrg 	}
    632      1.1  mrg       allocator_data->used_pool_size = used_pool_size;
    633      1.1  mrg       gomp_mutex_unlock (&allocator_data->lock);
    634      1.1  mrg #endif
    635  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    636  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
    637  1.1.1.2  mrg 	ptr = libnuma_data->numa_alloc_local (new_size);
    638  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
    639  1.1.1.2  mrg       else
    640  1.1.1.2  mrg # endif
    641  1.1.1.2  mrg #endif
    642  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    643  1.1.1.2  mrg       if (memkind)
    644  1.1.1.2  mrg 	{
    645  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    646  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
    647  1.1.1.2  mrg 	  ptr = memkind_data->memkind_malloc (kind, new_size);
    648  1.1.1.2  mrg 	}
    649  1.1.1.2  mrg       else
    650  1.1.1.2  mrg #endif
    651  1.1.1.2  mrg 	ptr = MEMSPACE_ALLOC (allocator_data->memspace, new_size,
    652  1.1.1.2  mrg 			      allocator_data->pinned);
    653      1.1  mrg       if (ptr == NULL)
    654      1.1  mrg 	{
    655      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
    656      1.1  mrg 	  __atomic_add_fetch (&allocator_data->used_pool_size, -new_size,
    657      1.1  mrg 			      MEMMODEL_RELAXED);
    658      1.1  mrg #else
    659      1.1  mrg 	  gomp_mutex_lock (&allocator_data->lock);
    660      1.1  mrg 	  allocator_data->used_pool_size -= new_size;
    661      1.1  mrg 	  gomp_mutex_unlock (&allocator_data->lock);
    662      1.1  mrg #endif
    663      1.1  mrg 	  goto fail;
    664      1.1  mrg 	}
    665      1.1  mrg     }
    666      1.1  mrg   else
    667      1.1  mrg     {
    668  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    669  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
    670  1.1.1.2  mrg 	ptr = libnuma_data->numa_alloc_local (new_size);
    671  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
    672  1.1.1.2  mrg       else
    673  1.1.1.2  mrg # endif
    674  1.1.1.2  mrg #endif
    675  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    676  1.1.1.2  mrg       if (memkind)
    677  1.1.1.2  mrg 	{
    678  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    679  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
    680  1.1.1.2  mrg 	  ptr = memkind_data->memkind_malloc (kind, new_size);
    681  1.1.1.2  mrg 	}
    682  1.1.1.2  mrg       else
    683  1.1.1.2  mrg #endif
    684  1.1.1.2  mrg 	{
    685  1.1.1.2  mrg 	  omp_memspace_handle_t memspace;
    686  1.1.1.2  mrg 	  memspace = (allocator_data
    687  1.1.1.2  mrg 		      ? allocator_data->memspace
    688  1.1.1.2  mrg 		      : predefined_alloc_mapping[allocator]);
    689  1.1.1.2  mrg 	  ptr = MEMSPACE_ALLOC (memspace, new_size,
    690  1.1.1.2  mrg 				allocator_data && allocator_data->pinned);
    691  1.1.1.2  mrg 	}
    692      1.1  mrg       if (ptr == NULL)
    693      1.1  mrg 	goto fail;
    694      1.1  mrg     }
    695      1.1  mrg 
    696      1.1  mrg   if (new_alignment > sizeof (void *))
    697      1.1  mrg     ret = (void *) (((uintptr_t) ptr
    698      1.1  mrg 		     + sizeof (struct omp_mem_header)
    699      1.1  mrg 		     + new_alignment - sizeof (void *))
    700      1.1  mrg 		    & ~(new_alignment - 1));
    701      1.1  mrg   else
    702      1.1  mrg     ret = (char *) ptr + sizeof (struct omp_mem_header);
    703      1.1  mrg   ((struct omp_mem_header *) ret)[-1].ptr = ptr;
    704      1.1  mrg   ((struct omp_mem_header *) ret)[-1].size = new_size;
    705      1.1  mrg   ((struct omp_mem_header *) ret)[-1].allocator = allocator;
    706      1.1  mrg   return ret;
    707      1.1  mrg 
    708  1.1.1.2  mrg fail:;
    709  1.1.1.2  mrg   int fallback = (allocator_data
    710  1.1.1.2  mrg 		  ? allocator_data->fallback
    711  1.1.1.2  mrg 		  : allocator == omp_default_mem_alloc
    712  1.1.1.2  mrg 		  ? omp_atv_null_fb
    713  1.1.1.2  mrg 		  : omp_atv_default_mem_fb);
    714  1.1.1.2  mrg   switch (fallback)
    715  1.1.1.2  mrg     {
    716  1.1.1.2  mrg     case omp_atv_default_mem_fb:
    717  1.1.1.2  mrg       allocator = omp_default_mem_alloc;
    718  1.1.1.2  mrg       goto retry;
    719  1.1.1.2  mrg     case omp_atv_null_fb:
    720  1.1.1.2  mrg       break;
    721  1.1.1.2  mrg     default:
    722  1.1.1.2  mrg     case omp_atv_abort_fb:
    723  1.1.1.2  mrg       gomp_fatal ("Out of memory allocating %lu bytes",
    724  1.1.1.2  mrg 		  (unsigned long) size);
    725  1.1.1.2  mrg     case omp_atv_allocator_fb:
    726  1.1.1.2  mrg       allocator = allocator_data->fb_data;
    727  1.1.1.2  mrg       goto retry;
    728      1.1  mrg     }
    729      1.1  mrg   return NULL;
    730      1.1  mrg }
    731      1.1  mrg 
    732      1.1  mrg ialias (omp_aligned_alloc)
    733      1.1  mrg 
    734      1.1  mrg void *
    735      1.1  mrg omp_alloc (size_t size, omp_allocator_handle_t allocator)
    736      1.1  mrg {
    737      1.1  mrg   return ialias_call (omp_aligned_alloc) (1, size, allocator);
    738      1.1  mrg }
    739      1.1  mrg 
    740      1.1  mrg /* Like omp_aligned_alloc, but apply on top of that:
    741      1.1  mrg    "For allocations that arise from this ... the null_fb value of the
    742      1.1  mrg    fallback allocator trait behaves as if the abort_fb had been specified."  */
    743      1.1  mrg 
    744      1.1  mrg void *
    745      1.1  mrg GOMP_alloc (size_t alignment, size_t size, uintptr_t allocator)
    746      1.1  mrg {
    747      1.1  mrg   void *ret
    748      1.1  mrg     = ialias_call (omp_aligned_alloc) (alignment, size,
    749      1.1  mrg 				       (omp_allocator_handle_t) allocator);
    750      1.1  mrg   if (__builtin_expect (ret == NULL, 0) && size)
    751      1.1  mrg     gomp_fatal ("Out of memory allocating %lu bytes",
    752      1.1  mrg 		(unsigned long) size);
    753      1.1  mrg   return ret;
    754      1.1  mrg }
    755      1.1  mrg 
    756      1.1  mrg void
    757      1.1  mrg omp_free (void *ptr, omp_allocator_handle_t allocator)
    758      1.1  mrg {
    759      1.1  mrg   struct omp_mem_header *data;
    760  1.1.1.2  mrg   omp_memspace_handle_t memspace = omp_default_mem_space;
    761  1.1.1.2  mrg   int pinned = false;
    762      1.1  mrg 
    763      1.1  mrg   if (ptr == NULL)
    764      1.1  mrg     return;
    765      1.1  mrg   (void) allocator;
    766      1.1  mrg   data = &((struct omp_mem_header *) ptr)[-1];
    767      1.1  mrg   if (data->allocator > omp_max_predefined_alloc)
    768      1.1  mrg     {
    769      1.1  mrg       struct omp_allocator_data *allocator_data
    770      1.1  mrg 	= (struct omp_allocator_data *) (data->allocator);
    771      1.1  mrg       if (allocator_data->pool_size < ~(uintptr_t) 0)
    772      1.1  mrg 	{
    773      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
    774      1.1  mrg 	  __atomic_add_fetch (&allocator_data->used_pool_size, -data->size,
    775      1.1  mrg 			      MEMMODEL_RELAXED);
    776      1.1  mrg #else
    777      1.1  mrg 	  gomp_mutex_lock (&allocator_data->lock);
    778      1.1  mrg 	  allocator_data->used_pool_size -= data->size;
    779      1.1  mrg 	  gomp_mutex_unlock (&allocator_data->lock);
    780      1.1  mrg #endif
    781      1.1  mrg 	}
    782  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    783  1.1.1.2  mrg       if (allocator_data->memkind == GOMP_MEMKIND_LIBNUMA)
    784  1.1.1.2  mrg 	{
    785  1.1.1.2  mrg 	  libnuma_data->numa_free (data->ptr, data->size);
    786  1.1.1.2  mrg 	  return;
    787  1.1.1.2  mrg 	}
    788  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
    789  1.1.1.2  mrg       else
    790  1.1.1.2  mrg # endif
    791  1.1.1.2  mrg #endif
    792  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    793  1.1.1.2  mrg       if (allocator_data->memkind)
    794  1.1.1.2  mrg 	{
    795  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    796  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[allocator_data->memkind];
    797  1.1.1.2  mrg 	  memkind_data->memkind_free (kind, data->ptr);
    798  1.1.1.2  mrg 	  return;
    799  1.1.1.2  mrg 	}
    800  1.1.1.2  mrg #endif
    801  1.1.1.2  mrg 
    802  1.1.1.2  mrg       memspace = allocator_data->memspace;
    803  1.1.1.2  mrg       pinned = allocator_data->pinned;
    804  1.1.1.2  mrg     }
    805  1.1.1.2  mrg   else
    806  1.1.1.2  mrg     {
    807  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    808  1.1.1.2  mrg       enum gomp_numa_memkind_kind memkind = GOMP_MEMKIND_NONE;
    809  1.1.1.2  mrg       if (data->allocator == omp_high_bw_mem_alloc)
    810  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_HBW_PREFERRED;
    811  1.1.1.2  mrg       else if (data->allocator == omp_large_cap_mem_alloc)
    812  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_DAX_KMEM_ALL;
    813  1.1.1.2  mrg       if (memkind)
    814  1.1.1.2  mrg 	{
    815  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    816  1.1.1.2  mrg 	  if (memkind_data->kinds[memkind])
    817  1.1.1.2  mrg 	    {
    818  1.1.1.2  mrg 	      void *kind = *memkind_data->kinds[memkind];
    819  1.1.1.2  mrg 	      memkind_data->memkind_free (kind, data->ptr);
    820  1.1.1.2  mrg 	      return;
    821  1.1.1.2  mrg 	    }
    822  1.1.1.2  mrg 	}
    823  1.1.1.2  mrg #endif
    824  1.1.1.2  mrg 
    825  1.1.1.2  mrg       memspace = predefined_alloc_mapping[data->allocator];
    826      1.1  mrg     }
    827  1.1.1.2  mrg 
    828  1.1.1.2  mrg   MEMSPACE_FREE (memspace, data->ptr, data->size, pinned);
    829      1.1  mrg }
    830      1.1  mrg 
    831      1.1  mrg ialias (omp_free)
    832      1.1  mrg 
    833      1.1  mrg void
    834      1.1  mrg GOMP_free (void *ptr, uintptr_t allocator)
    835      1.1  mrg {
    836      1.1  mrg   return ialias_call (omp_free) (ptr, (omp_allocator_handle_t) allocator);
    837      1.1  mrg }
    838      1.1  mrg 
    839      1.1  mrg void *
    840      1.1  mrg omp_aligned_calloc (size_t alignment, size_t nmemb, size_t size,
    841      1.1  mrg 		    omp_allocator_handle_t allocator)
    842      1.1  mrg {
    843      1.1  mrg   struct omp_allocator_data *allocator_data;
    844      1.1  mrg   size_t new_size, size_temp, new_alignment;
    845      1.1  mrg   void *ptr, *ret;
    846  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    847  1.1.1.2  mrg   enum gomp_numa_memkind_kind memkind;
    848  1.1.1.2  mrg #endif
    849      1.1  mrg 
    850      1.1  mrg   if (__builtin_expect (size == 0 || nmemb == 0, 0))
    851      1.1  mrg     return NULL;
    852      1.1  mrg 
    853      1.1  mrg retry:
    854      1.1  mrg   new_alignment = alignment;
    855      1.1  mrg   if (allocator == omp_null_allocator)
    856      1.1  mrg     {
    857      1.1  mrg       struct gomp_thread *thr = gomp_thread ();
    858      1.1  mrg       if (thr->ts.def_allocator == omp_null_allocator)
    859      1.1  mrg 	thr->ts.def_allocator = gomp_def_allocator;
    860      1.1  mrg       allocator = (omp_allocator_handle_t) thr->ts.def_allocator;
    861      1.1  mrg     }
    862      1.1  mrg 
    863      1.1  mrg   if (allocator > omp_max_predefined_alloc)
    864      1.1  mrg     {
    865      1.1  mrg       allocator_data = (struct omp_allocator_data *) allocator;
    866      1.1  mrg       if (new_alignment < allocator_data->alignment)
    867      1.1  mrg 	new_alignment = allocator_data->alignment;
    868  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    869  1.1.1.2  mrg       memkind = allocator_data->memkind;
    870  1.1.1.2  mrg #endif
    871      1.1  mrg     }
    872      1.1  mrg   else
    873      1.1  mrg     {
    874      1.1  mrg       allocator_data = NULL;
    875      1.1  mrg       if (new_alignment < sizeof (void *))
    876      1.1  mrg 	new_alignment = sizeof (void *);
    877  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
    878  1.1.1.2  mrg       memkind = GOMP_MEMKIND_NONE;
    879  1.1.1.2  mrg #endif
    880  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    881  1.1.1.2  mrg       if (allocator == omp_high_bw_mem_alloc)
    882  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_HBW_PREFERRED;
    883  1.1.1.2  mrg       else if (allocator == omp_large_cap_mem_alloc)
    884  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_DAX_KMEM_ALL;
    885  1.1.1.2  mrg       if (memkind)
    886  1.1.1.2  mrg 	{
    887  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    888  1.1.1.2  mrg 	  if (!memkind_data->kinds[memkind])
    889  1.1.1.2  mrg 	    memkind = GOMP_MEMKIND_NONE;
    890  1.1.1.2  mrg 	}
    891  1.1.1.2  mrg #endif
    892      1.1  mrg     }
    893      1.1  mrg 
    894      1.1  mrg   new_size = sizeof (struct omp_mem_header);
    895      1.1  mrg   if (new_alignment > sizeof (void *))
    896      1.1  mrg     new_size += new_alignment - sizeof (void *);
    897      1.1  mrg   if (__builtin_mul_overflow (size, nmemb, &size_temp))
    898      1.1  mrg     goto fail;
    899      1.1  mrg   if (__builtin_add_overflow (size_temp, new_size, &new_size))
    900      1.1  mrg     goto fail;
    901  1.1.1.2  mrg #ifdef OMP_LOW_LAT_MEM_ALLOC_INVALID
    902  1.1.1.2  mrg   if (allocator == omp_low_lat_mem_alloc)
    903  1.1.1.2  mrg     goto fail;
    904  1.1.1.2  mrg #endif
    905      1.1  mrg 
    906      1.1  mrg   if (__builtin_expect (allocator_data
    907      1.1  mrg 			&& allocator_data->pool_size < ~(uintptr_t) 0, 0))
    908      1.1  mrg     {
    909      1.1  mrg       uintptr_t used_pool_size;
    910      1.1  mrg       if (new_size > allocator_data->pool_size)
    911      1.1  mrg 	goto fail;
    912      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
    913      1.1  mrg       used_pool_size = __atomic_load_n (&allocator_data->used_pool_size,
    914      1.1  mrg 					MEMMODEL_RELAXED);
    915      1.1  mrg       do
    916      1.1  mrg 	{
    917      1.1  mrg 	  uintptr_t new_pool_size;
    918      1.1  mrg 	  if (__builtin_add_overflow (used_pool_size, new_size,
    919      1.1  mrg 				      &new_pool_size)
    920      1.1  mrg 	      || new_pool_size > allocator_data->pool_size)
    921      1.1  mrg 	    goto fail;
    922      1.1  mrg 	  if (__atomic_compare_exchange_n (&allocator_data->used_pool_size,
    923      1.1  mrg 					   &used_pool_size, new_pool_size,
    924      1.1  mrg 					   true, MEMMODEL_RELAXED,
    925      1.1  mrg 					   MEMMODEL_RELAXED))
    926      1.1  mrg 	    break;
    927      1.1  mrg 	}
    928      1.1  mrg       while (1);
    929      1.1  mrg #else
    930      1.1  mrg       gomp_mutex_lock (&allocator_data->lock);
    931      1.1  mrg       if (__builtin_add_overflow (allocator_data->used_pool_size, new_size,
    932      1.1  mrg 				  &used_pool_size)
    933      1.1  mrg 	  || used_pool_size > allocator_data->pool_size)
    934      1.1  mrg 	{
    935      1.1  mrg 	  gomp_mutex_unlock (&allocator_data->lock);
    936      1.1  mrg 	  goto fail;
    937      1.1  mrg 	}
    938      1.1  mrg       allocator_data->used_pool_size = used_pool_size;
    939      1.1  mrg       gomp_mutex_unlock (&allocator_data->lock);
    940      1.1  mrg #endif
    941  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    942  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
    943  1.1.1.2  mrg 	/* numa_alloc_local uses mmap with MAP_ANONYMOUS, returning
    944  1.1.1.2  mrg 	   memory that is initialized to zero.  */
    945  1.1.1.2  mrg 	ptr = libnuma_data->numa_alloc_local (new_size);
    946  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
    947  1.1.1.2  mrg       else
    948  1.1.1.2  mrg # endif
    949  1.1.1.2  mrg #endif
    950  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    951  1.1.1.2  mrg       if (memkind)
    952  1.1.1.2  mrg 	{
    953  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    954  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
    955  1.1.1.2  mrg 	  ptr = memkind_data->memkind_calloc (kind, 1, new_size);
    956  1.1.1.2  mrg 	}
    957  1.1.1.2  mrg       else
    958  1.1.1.2  mrg #endif
    959  1.1.1.2  mrg 	ptr = MEMSPACE_CALLOC (allocator_data->memspace, new_size,
    960  1.1.1.2  mrg 			       allocator_data->pinned);
    961      1.1  mrg       if (ptr == NULL)
    962      1.1  mrg 	{
    963      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
    964      1.1  mrg 	  __atomic_add_fetch (&allocator_data->used_pool_size, -new_size,
    965      1.1  mrg 			      MEMMODEL_RELAXED);
    966      1.1  mrg #else
    967      1.1  mrg 	  gomp_mutex_lock (&allocator_data->lock);
    968      1.1  mrg 	  allocator_data->used_pool_size -= new_size;
    969      1.1  mrg 	  gomp_mutex_unlock (&allocator_data->lock);
    970      1.1  mrg #endif
    971      1.1  mrg 	  goto fail;
    972      1.1  mrg 	}
    973      1.1  mrg     }
    974      1.1  mrg   else
    975      1.1  mrg     {
    976  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
    977  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
    978  1.1.1.2  mrg 	/* numa_alloc_local uses mmap with MAP_ANONYMOUS, returning
    979  1.1.1.2  mrg 	   memory that is initialized to zero.  */
    980  1.1.1.2  mrg 	ptr = libnuma_data->numa_alloc_local (new_size);
    981  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
    982  1.1.1.2  mrg       else
    983  1.1.1.2  mrg # endif
    984  1.1.1.2  mrg #endif
    985  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
    986  1.1.1.2  mrg       if (memkind)
    987  1.1.1.2  mrg 	{
    988  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
    989  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
    990  1.1.1.2  mrg 	  ptr = memkind_data->memkind_calloc (kind, 1, new_size);
    991  1.1.1.2  mrg 	}
    992  1.1.1.2  mrg       else
    993  1.1.1.2  mrg #endif
    994  1.1.1.2  mrg 	{
    995  1.1.1.2  mrg 	  omp_memspace_handle_t memspace;
    996  1.1.1.2  mrg 	  memspace = (allocator_data
    997  1.1.1.2  mrg 		      ? allocator_data->memspace
    998  1.1.1.2  mrg 		      : predefined_alloc_mapping[allocator]);
    999  1.1.1.2  mrg 	  ptr = MEMSPACE_CALLOC (memspace, new_size,
   1000  1.1.1.2  mrg 				 allocator_data && allocator_data->pinned);
   1001  1.1.1.2  mrg 	}
   1002      1.1  mrg       if (ptr == NULL)
   1003      1.1  mrg 	goto fail;
   1004      1.1  mrg     }
   1005      1.1  mrg 
   1006      1.1  mrg   if (new_alignment > sizeof (void *))
   1007      1.1  mrg     ret = (void *) (((uintptr_t) ptr
   1008      1.1  mrg 		     + sizeof (struct omp_mem_header)
   1009      1.1  mrg 		     + new_alignment - sizeof (void *))
   1010      1.1  mrg 		    & ~(new_alignment - 1));
   1011      1.1  mrg   else
   1012      1.1  mrg     ret = (char *) ptr + sizeof (struct omp_mem_header);
   1013      1.1  mrg   ((struct omp_mem_header *) ret)[-1].ptr = ptr;
   1014      1.1  mrg   ((struct omp_mem_header *) ret)[-1].size = new_size;
   1015      1.1  mrg   ((struct omp_mem_header *) ret)[-1].allocator = allocator;
   1016      1.1  mrg   return ret;
   1017      1.1  mrg 
   1018  1.1.1.2  mrg fail:;
   1019  1.1.1.2  mrg   int fallback = (allocator_data
   1020  1.1.1.2  mrg 		  ? allocator_data->fallback
   1021  1.1.1.2  mrg 		  : allocator == omp_default_mem_alloc
   1022  1.1.1.2  mrg 		  ? omp_atv_null_fb
   1023  1.1.1.2  mrg 		  : omp_atv_default_mem_fb);
   1024  1.1.1.2  mrg   switch (fallback)
   1025  1.1.1.2  mrg     {
   1026  1.1.1.2  mrg     case omp_atv_default_mem_fb:
   1027  1.1.1.2  mrg       allocator = omp_default_mem_alloc;
   1028  1.1.1.2  mrg       goto retry;
   1029  1.1.1.2  mrg     case omp_atv_null_fb:
   1030  1.1.1.2  mrg       break;
   1031  1.1.1.2  mrg     default:
   1032  1.1.1.2  mrg     case omp_atv_abort_fb:
   1033  1.1.1.2  mrg       gomp_fatal ("Out of memory allocating %lu bytes",
   1034  1.1.1.2  mrg 		  (unsigned long) (size * nmemb));
   1035  1.1.1.2  mrg     case omp_atv_allocator_fb:
   1036  1.1.1.2  mrg       allocator = allocator_data->fb_data;
   1037  1.1.1.2  mrg       goto retry;
   1038      1.1  mrg     }
   1039      1.1  mrg   return NULL;
   1040      1.1  mrg }
   1041      1.1  mrg 
   1042      1.1  mrg ialias (omp_aligned_calloc)
   1043      1.1  mrg 
   1044      1.1  mrg void *
   1045      1.1  mrg omp_calloc (size_t nmemb, size_t size, omp_allocator_handle_t allocator)
   1046      1.1  mrg {
   1047      1.1  mrg   return ialias_call (omp_aligned_calloc) (1, nmemb, size, allocator);
   1048      1.1  mrg }
   1049      1.1  mrg 
   1050      1.1  mrg void *
   1051      1.1  mrg omp_realloc (void *ptr, size_t size, omp_allocator_handle_t allocator,
   1052      1.1  mrg 	     omp_allocator_handle_t free_allocator)
   1053      1.1  mrg {
   1054      1.1  mrg   struct omp_allocator_data *allocator_data, *free_allocator_data;
   1055      1.1  mrg   size_t new_size, old_size, new_alignment, old_alignment;
   1056      1.1  mrg   void *new_ptr, *ret;
   1057      1.1  mrg   struct omp_mem_header *data;
   1058  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
   1059  1.1.1.2  mrg   enum gomp_numa_memkind_kind memkind, free_memkind;
   1060  1.1.1.2  mrg #endif
   1061      1.1  mrg 
   1062      1.1  mrg   if (__builtin_expect (ptr == NULL, 0))
   1063      1.1  mrg     return ialias_call (omp_aligned_alloc) (1, size, allocator);
   1064      1.1  mrg 
   1065      1.1  mrg   if (__builtin_expect (size == 0, 0))
   1066      1.1  mrg     {
   1067      1.1  mrg       ialias_call (omp_free) (ptr, free_allocator);
   1068      1.1  mrg       return NULL;
   1069      1.1  mrg     }
   1070      1.1  mrg 
   1071      1.1  mrg   data = &((struct omp_mem_header *) ptr)[-1];
   1072      1.1  mrg   free_allocator = data->allocator;
   1073      1.1  mrg 
   1074      1.1  mrg retry:
   1075      1.1  mrg   new_alignment = sizeof (void *);
   1076      1.1  mrg   if (allocator == omp_null_allocator)
   1077      1.1  mrg     allocator = free_allocator;
   1078      1.1  mrg 
   1079      1.1  mrg   if (allocator > omp_max_predefined_alloc)
   1080      1.1  mrg     {
   1081      1.1  mrg       allocator_data = (struct omp_allocator_data *) allocator;
   1082      1.1  mrg       if (new_alignment < allocator_data->alignment)
   1083      1.1  mrg 	new_alignment = allocator_data->alignment;
   1084  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
   1085  1.1.1.2  mrg       memkind = allocator_data->memkind;
   1086  1.1.1.2  mrg #endif
   1087      1.1  mrg     }
   1088      1.1  mrg   else
   1089  1.1.1.2  mrg     {
   1090  1.1.1.2  mrg       allocator_data = NULL;
   1091  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
   1092  1.1.1.2  mrg       memkind = GOMP_MEMKIND_NONE;
   1093  1.1.1.2  mrg #endif
   1094  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
   1095  1.1.1.2  mrg       if (allocator == omp_high_bw_mem_alloc)
   1096  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_HBW_PREFERRED;
   1097  1.1.1.2  mrg       else if (allocator == omp_large_cap_mem_alloc)
   1098  1.1.1.2  mrg 	memkind = GOMP_MEMKIND_DAX_KMEM_ALL;
   1099  1.1.1.2  mrg       if (memkind)
   1100  1.1.1.2  mrg 	{
   1101  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
   1102  1.1.1.2  mrg 	  if (!memkind_data->kinds[memkind])
   1103  1.1.1.2  mrg 	    memkind = GOMP_MEMKIND_NONE;
   1104  1.1.1.2  mrg 	}
   1105  1.1.1.2  mrg #endif
   1106  1.1.1.2  mrg     }
   1107      1.1  mrg   if (free_allocator > omp_max_predefined_alloc)
   1108  1.1.1.2  mrg     {
   1109  1.1.1.2  mrg       free_allocator_data = (struct omp_allocator_data *) free_allocator;
   1110  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
   1111  1.1.1.2  mrg       free_memkind = free_allocator_data->memkind;
   1112  1.1.1.2  mrg #endif
   1113  1.1.1.2  mrg     }
   1114      1.1  mrg   else
   1115  1.1.1.2  mrg     {
   1116  1.1.1.2  mrg       free_allocator_data = NULL;
   1117  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
   1118  1.1.1.2  mrg       free_memkind = GOMP_MEMKIND_NONE;
   1119  1.1.1.2  mrg #endif
   1120  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
   1121  1.1.1.2  mrg       if (free_allocator == omp_high_bw_mem_alloc)
   1122  1.1.1.2  mrg 	free_memkind = GOMP_MEMKIND_HBW_PREFERRED;
   1123  1.1.1.2  mrg       else if (free_allocator == omp_large_cap_mem_alloc)
   1124  1.1.1.2  mrg 	free_memkind = GOMP_MEMKIND_DAX_KMEM_ALL;
   1125  1.1.1.2  mrg       if (free_memkind)
   1126  1.1.1.2  mrg 	{
   1127  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
   1128  1.1.1.2  mrg 	  if (!memkind_data->kinds[free_memkind])
   1129  1.1.1.2  mrg 	    free_memkind = GOMP_MEMKIND_NONE;
   1130  1.1.1.2  mrg 	}
   1131  1.1.1.2  mrg #endif
   1132  1.1.1.2  mrg     }
   1133      1.1  mrg   old_alignment = (uintptr_t) ptr - (uintptr_t) (data->ptr);
   1134      1.1  mrg 
   1135      1.1  mrg   new_size = sizeof (struct omp_mem_header);
   1136      1.1  mrg   if (new_alignment > sizeof (void *))
   1137      1.1  mrg     new_size += new_alignment - sizeof (void *);
   1138      1.1  mrg   if (__builtin_add_overflow (size, new_size, &new_size))
   1139      1.1  mrg     goto fail;
   1140      1.1  mrg   old_size = data->size;
   1141  1.1.1.2  mrg #ifdef OMP_LOW_LAT_MEM_ALLOC_INVALID
   1142  1.1.1.2  mrg   if (allocator == omp_low_lat_mem_alloc)
   1143  1.1.1.2  mrg     goto fail;
   1144  1.1.1.2  mrg #endif
   1145      1.1  mrg 
   1146      1.1  mrg   if (__builtin_expect (allocator_data
   1147      1.1  mrg 			&& allocator_data->pool_size < ~(uintptr_t) 0, 0))
   1148      1.1  mrg     {
   1149      1.1  mrg       uintptr_t used_pool_size;
   1150      1.1  mrg       size_t prev_size = 0;
   1151      1.1  mrg       /* Check if we can use realloc.  Don't use it if extra alignment
   1152      1.1  mrg 	 was used previously or newly, because realloc might return a pointer
   1153      1.1  mrg 	 with different alignment and then we'd need to memmove the data
   1154      1.1  mrg 	 again.  */
   1155      1.1  mrg       if (free_allocator_data
   1156      1.1  mrg 	  && free_allocator_data == allocator_data
   1157      1.1  mrg 	  && new_alignment == sizeof (void *)
   1158      1.1  mrg 	  && old_alignment == sizeof (struct omp_mem_header))
   1159      1.1  mrg 	prev_size = old_size;
   1160      1.1  mrg       if (new_size > prev_size
   1161      1.1  mrg 	  && new_size - prev_size > allocator_data->pool_size)
   1162      1.1  mrg 	goto fail;
   1163      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
   1164      1.1  mrg       used_pool_size = __atomic_load_n (&allocator_data->used_pool_size,
   1165      1.1  mrg 					MEMMODEL_RELAXED);
   1166      1.1  mrg       do
   1167      1.1  mrg 	{
   1168      1.1  mrg 	  uintptr_t new_pool_size;
   1169      1.1  mrg 	  if (new_size > prev_size)
   1170      1.1  mrg 	    {
   1171      1.1  mrg 	      if (__builtin_add_overflow (used_pool_size, new_size - prev_size,
   1172      1.1  mrg 					  &new_pool_size)
   1173      1.1  mrg 		  || new_pool_size > allocator_data->pool_size)
   1174      1.1  mrg 		goto fail;
   1175      1.1  mrg 	    }
   1176      1.1  mrg 	  else
   1177      1.1  mrg 	    new_pool_size = used_pool_size + new_size - prev_size;
   1178      1.1  mrg 	  if (__atomic_compare_exchange_n (&allocator_data->used_pool_size,
   1179      1.1  mrg 					   &used_pool_size, new_pool_size,
   1180      1.1  mrg 					   true, MEMMODEL_RELAXED,
   1181      1.1  mrg 					   MEMMODEL_RELAXED))
   1182      1.1  mrg 	    break;
   1183      1.1  mrg 	}
   1184      1.1  mrg       while (1);
   1185      1.1  mrg #else
   1186      1.1  mrg       gomp_mutex_lock (&allocator_data->lock);
   1187      1.1  mrg       if (new_size > prev_size)
   1188      1.1  mrg 	{
   1189      1.1  mrg 	  if (__builtin_add_overflow (allocator_data->used_pool_size,
   1190      1.1  mrg 				      new_size - prev_size,
   1191      1.1  mrg 				      &used_pool_size)
   1192      1.1  mrg 	      || used_pool_size > allocator_data->pool_size)
   1193      1.1  mrg 	    {
   1194      1.1  mrg 	      gomp_mutex_unlock (&allocator_data->lock);
   1195      1.1  mrg 	      goto fail;
   1196      1.1  mrg 	    }
   1197      1.1  mrg 	}
   1198      1.1  mrg       else
   1199      1.1  mrg 	used_pool_size = (allocator_data->used_pool_size
   1200      1.1  mrg 			  + new_size - prev_size);
   1201      1.1  mrg       allocator_data->used_pool_size = used_pool_size;
   1202      1.1  mrg       gomp_mutex_unlock (&allocator_data->lock);
   1203      1.1  mrg #endif
   1204  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
   1205  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
   1206  1.1.1.2  mrg 	{
   1207  1.1.1.2  mrg 	  if (prev_size)
   1208  1.1.1.2  mrg 	    new_ptr = libnuma_data->numa_realloc (data->ptr, data->size,
   1209  1.1.1.2  mrg 						  new_size);
   1210  1.1.1.2  mrg 	  else
   1211  1.1.1.2  mrg 	    new_ptr = libnuma_data->numa_alloc_local (new_size);
   1212  1.1.1.2  mrg 	}
   1213  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
   1214  1.1.1.2  mrg       else
   1215  1.1.1.2  mrg # endif
   1216  1.1.1.2  mrg #endif
   1217  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
   1218  1.1.1.2  mrg       if (memkind)
   1219  1.1.1.2  mrg 	{
   1220  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
   1221  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
   1222  1.1.1.2  mrg 	  if (prev_size)
   1223  1.1.1.2  mrg 	    new_ptr = memkind_data->memkind_realloc (kind, data->ptr,
   1224  1.1.1.2  mrg 						     new_size);
   1225  1.1.1.2  mrg 	  else
   1226  1.1.1.2  mrg 	    new_ptr = memkind_data->memkind_malloc (kind, new_size);
   1227  1.1.1.2  mrg 	}
   1228  1.1.1.2  mrg       else
   1229  1.1.1.2  mrg #endif
   1230      1.1  mrg       if (prev_size)
   1231  1.1.1.2  mrg 	new_ptr = MEMSPACE_REALLOC (allocator_data->memspace, data->ptr,
   1232  1.1.1.2  mrg 				    data->size, new_size,
   1233  1.1.1.2  mrg 				    (free_allocator_data
   1234  1.1.1.2  mrg 				     && free_allocator_data->pinned),
   1235  1.1.1.2  mrg 				    allocator_data->pinned);
   1236      1.1  mrg       else
   1237  1.1.1.2  mrg 	new_ptr = MEMSPACE_ALLOC (allocator_data->memspace, new_size,
   1238  1.1.1.2  mrg 				  allocator_data->pinned);
   1239      1.1  mrg       if (new_ptr == NULL)
   1240      1.1  mrg 	{
   1241      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
   1242      1.1  mrg 	  __atomic_add_fetch (&allocator_data->used_pool_size,
   1243      1.1  mrg 			      prev_size - new_size,
   1244      1.1  mrg 			      MEMMODEL_RELAXED);
   1245      1.1  mrg #else
   1246      1.1  mrg 	  gomp_mutex_lock (&allocator_data->lock);
   1247      1.1  mrg 	  allocator_data->used_pool_size -= new_size - prev_size;
   1248      1.1  mrg 	  gomp_mutex_unlock (&allocator_data->lock);
   1249      1.1  mrg #endif
   1250      1.1  mrg 	  goto fail;
   1251      1.1  mrg 	}
   1252      1.1  mrg       else if (prev_size)
   1253      1.1  mrg 	{
   1254      1.1  mrg 	  ret = (char *) new_ptr + sizeof (struct omp_mem_header);
   1255      1.1  mrg 	  ((struct omp_mem_header *) ret)[-1].ptr = new_ptr;
   1256      1.1  mrg 	  ((struct omp_mem_header *) ret)[-1].size = new_size;
   1257      1.1  mrg 	  ((struct omp_mem_header *) ret)[-1].allocator = allocator;
   1258      1.1  mrg 	  return ret;
   1259      1.1  mrg 	}
   1260      1.1  mrg     }
   1261      1.1  mrg   else if (new_alignment == sizeof (void *)
   1262      1.1  mrg 	   && old_alignment == sizeof (struct omp_mem_header)
   1263  1.1.1.2  mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
   1264  1.1.1.2  mrg 	   && memkind == free_memkind
   1265  1.1.1.2  mrg #endif
   1266      1.1  mrg 	   && (free_allocator_data == NULL
   1267      1.1  mrg 	       || free_allocator_data->pool_size == ~(uintptr_t) 0))
   1268      1.1  mrg     {
   1269  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
   1270  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
   1271  1.1.1.2  mrg 	new_ptr = libnuma_data->numa_realloc (data->ptr, data->size, new_size);
   1272  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
   1273  1.1.1.2  mrg       else
   1274  1.1.1.2  mrg # endif
   1275  1.1.1.2  mrg #endif
   1276  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
   1277  1.1.1.2  mrg       if (memkind)
   1278  1.1.1.2  mrg 	{
   1279  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
   1280  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
   1281  1.1.1.2  mrg 	  new_ptr = memkind_data->memkind_realloc (kind, data->ptr,
   1282  1.1.1.2  mrg 						   new_size);
   1283  1.1.1.2  mrg 	}
   1284  1.1.1.2  mrg       else
   1285  1.1.1.2  mrg #endif
   1286  1.1.1.2  mrg 	{
   1287  1.1.1.2  mrg 	  omp_memspace_handle_t memspace;
   1288  1.1.1.2  mrg 	  memspace = (allocator_data
   1289  1.1.1.2  mrg 		      ? allocator_data->memspace
   1290  1.1.1.2  mrg 		      : predefined_alloc_mapping[allocator]);
   1291  1.1.1.2  mrg 	  new_ptr = MEMSPACE_REALLOC (memspace, data->ptr, data->size, new_size,
   1292  1.1.1.2  mrg 				      (free_allocator_data
   1293  1.1.1.2  mrg 				       && free_allocator_data->pinned),
   1294  1.1.1.2  mrg 				      allocator_data && allocator_data->pinned);
   1295  1.1.1.2  mrg 	}
   1296      1.1  mrg       if (new_ptr == NULL)
   1297      1.1  mrg 	goto fail;
   1298  1.1.1.2  mrg 
   1299      1.1  mrg       ret = (char *) new_ptr + sizeof (struct omp_mem_header);
   1300      1.1  mrg       ((struct omp_mem_header *) ret)[-1].ptr = new_ptr;
   1301      1.1  mrg       ((struct omp_mem_header *) ret)[-1].size = new_size;
   1302      1.1  mrg       ((struct omp_mem_header *) ret)[-1].allocator = allocator;
   1303      1.1  mrg       return ret;
   1304      1.1  mrg     }
   1305      1.1  mrg   else
   1306      1.1  mrg     {
   1307  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
   1308  1.1.1.2  mrg       if (memkind == GOMP_MEMKIND_LIBNUMA)
   1309  1.1.1.2  mrg 	new_ptr = libnuma_data->numa_alloc_local (new_size);
   1310  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
   1311  1.1.1.2  mrg       else
   1312  1.1.1.2  mrg # endif
   1313  1.1.1.2  mrg #endif
   1314  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
   1315  1.1.1.2  mrg       if (memkind)
   1316  1.1.1.2  mrg 	{
   1317  1.1.1.2  mrg 	  struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
   1318  1.1.1.2  mrg 	  void *kind = *memkind_data->kinds[memkind];
   1319  1.1.1.2  mrg 	  new_ptr = memkind_data->memkind_malloc (kind, new_size);
   1320  1.1.1.2  mrg 	}
   1321  1.1.1.2  mrg       else
   1322  1.1.1.2  mrg #endif
   1323  1.1.1.2  mrg 	{
   1324  1.1.1.2  mrg 	  omp_memspace_handle_t memspace;
   1325  1.1.1.2  mrg 	  memspace = (allocator_data
   1326  1.1.1.2  mrg 		      ? allocator_data->memspace
   1327  1.1.1.2  mrg 		      : predefined_alloc_mapping[allocator]);
   1328  1.1.1.2  mrg 	  new_ptr = MEMSPACE_ALLOC (memspace, new_size,
   1329  1.1.1.2  mrg 				    allocator_data && allocator_data->pinned);
   1330  1.1.1.2  mrg 	}
   1331      1.1  mrg       if (new_ptr == NULL)
   1332      1.1  mrg 	goto fail;
   1333      1.1  mrg     }
   1334      1.1  mrg 
   1335      1.1  mrg   if (new_alignment > sizeof (void *))
   1336      1.1  mrg     ret = (void *) (((uintptr_t) new_ptr
   1337      1.1  mrg 		     + sizeof (struct omp_mem_header)
   1338      1.1  mrg 		     + new_alignment - sizeof (void *))
   1339      1.1  mrg 		    & ~(new_alignment - 1));
   1340      1.1  mrg   else
   1341      1.1  mrg     ret = (char *) new_ptr + sizeof (struct omp_mem_header);
   1342      1.1  mrg   ((struct omp_mem_header *) ret)[-1].ptr = new_ptr;
   1343      1.1  mrg   ((struct omp_mem_header *) ret)[-1].size = new_size;
   1344      1.1  mrg   ((struct omp_mem_header *) ret)[-1].allocator = allocator;
   1345      1.1  mrg   if (old_size - old_alignment < size)
   1346      1.1  mrg     size = old_size - old_alignment;
   1347      1.1  mrg   memcpy (ret, ptr, size);
   1348      1.1  mrg   if (__builtin_expect (free_allocator_data
   1349      1.1  mrg 			&& free_allocator_data->pool_size < ~(uintptr_t) 0, 0))
   1350      1.1  mrg     {
   1351      1.1  mrg #ifdef HAVE_SYNC_BUILTINS
   1352      1.1  mrg       __atomic_add_fetch (&free_allocator_data->used_pool_size, -data->size,
   1353      1.1  mrg 			  MEMMODEL_RELAXED);
   1354      1.1  mrg #else
   1355      1.1  mrg       gomp_mutex_lock (&free_allocator_data->lock);
   1356      1.1  mrg       free_allocator_data->used_pool_size -= data->size;
   1357      1.1  mrg       gomp_mutex_unlock (&free_allocator_data->lock);
   1358      1.1  mrg #endif
   1359      1.1  mrg     }
   1360  1.1.1.2  mrg #ifdef LIBGOMP_USE_LIBNUMA
   1361  1.1.1.2  mrg   if (free_memkind == GOMP_MEMKIND_LIBNUMA)
   1362  1.1.1.2  mrg     {
   1363  1.1.1.2  mrg       libnuma_data->numa_free (data->ptr, data->size);
   1364  1.1.1.2  mrg       return ret;
   1365  1.1.1.2  mrg     }
   1366  1.1.1.2  mrg # ifdef LIBGOMP_USE_MEMKIND
   1367  1.1.1.2  mrg   else
   1368  1.1.1.2  mrg # endif
   1369  1.1.1.2  mrg #endif
   1370  1.1.1.2  mrg #ifdef LIBGOMP_USE_MEMKIND
   1371  1.1.1.2  mrg   if (free_memkind)
   1372  1.1.1.2  mrg     {
   1373  1.1.1.2  mrg       struct gomp_memkind_data *memkind_data = gomp_get_memkind ();
   1374  1.1.1.2  mrg       void *kind = *memkind_data->kinds[free_memkind];
   1375  1.1.1.2  mrg       memkind_data->memkind_free (kind, data->ptr);
   1376  1.1.1.2  mrg       return ret;
   1377  1.1.1.2  mrg     }
   1378  1.1.1.2  mrg #endif
   1379  1.1.1.2  mrg   {
   1380  1.1.1.2  mrg     omp_memspace_handle_t was_memspace;
   1381  1.1.1.2  mrg     was_memspace = (free_allocator_data
   1382  1.1.1.2  mrg 		    ? free_allocator_data->memspace
   1383  1.1.1.2  mrg 		    : predefined_alloc_mapping[free_allocator]);
   1384  1.1.1.2  mrg     int was_pinned = (free_allocator_data && free_allocator_data->pinned);
   1385  1.1.1.2  mrg     MEMSPACE_FREE (was_memspace, data->ptr, data->size, was_pinned);
   1386  1.1.1.2  mrg   }
   1387      1.1  mrg   return ret;
   1388      1.1  mrg 
   1389  1.1.1.2  mrg fail:;
   1390  1.1.1.2  mrg   int fallback = (allocator_data
   1391  1.1.1.2  mrg 		  ? allocator_data->fallback
   1392  1.1.1.2  mrg 		  : allocator == omp_default_mem_alloc
   1393  1.1.1.2  mrg 		  ? omp_atv_null_fb
   1394  1.1.1.2  mrg 		  : omp_atv_default_mem_fb);
   1395  1.1.1.2  mrg   switch (fallback)
   1396  1.1.1.2  mrg     {
   1397  1.1.1.2  mrg     case omp_atv_default_mem_fb:
   1398  1.1.1.2  mrg       allocator = omp_default_mem_alloc;
   1399  1.1.1.2  mrg       goto retry;
   1400  1.1.1.2  mrg     case omp_atv_null_fb:
   1401  1.1.1.2  mrg       break;
   1402  1.1.1.2  mrg     default:
   1403  1.1.1.2  mrg     case omp_atv_abort_fb:
   1404  1.1.1.2  mrg       gomp_fatal ("Out of memory allocating %lu bytes",
   1405  1.1.1.2  mrg 		  (unsigned long) size);
   1406  1.1.1.2  mrg     case omp_atv_allocator_fb:
   1407  1.1.1.2  mrg       allocator = allocator_data->fb_data;
   1408  1.1.1.2  mrg       goto retry;
   1409      1.1  mrg     }
   1410      1.1  mrg   return NULL;
   1411      1.1  mrg }
   1412