xref: /llvm-project/openmp/runtime/src/kmp_alloc.cpp (revision ae46cd72aa07f804ca6280a9bab04474a07c59f1)
17cc577a4SJonathan Peyton /*
2de4749b7SJonathan Peyton  * kmp_alloc.cpp -- private/shared dynamic memory allocation and management
37cc577a4SJonathan Peyton  */
47cc577a4SJonathan Peyton 
57cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
67cc577a4SJonathan Peyton //
757b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
857b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
957b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
107cc577a4SJonathan Peyton //
117cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
127cc577a4SJonathan Peyton 
137cc577a4SJonathan Peyton #include "kmp.h"
147cc577a4SJonathan Peyton #include "kmp_io.h"
153041982dSJonathan Peyton #include "kmp_wrapper_malloc.h"
167cc577a4SJonathan Peyton 
177cc577a4SJonathan Peyton // Disable bget when it is not used
187cc577a4SJonathan Peyton #if KMP_USE_BGET
197cc577a4SJonathan Peyton 
207cc577a4SJonathan Peyton /* Thread private buffer management code */
217cc577a4SJonathan Peyton 
227cc577a4SJonathan Peyton typedef int (*bget_compact_t)(size_t, int);
237cc577a4SJonathan Peyton typedef void *(*bget_acquire_t)(size_t);
247cc577a4SJonathan Peyton typedef void (*bget_release_t)(void *);
257cc577a4SJonathan Peyton 
267cc577a4SJonathan Peyton /* NOTE: bufsize must be a signed datatype */
277cc577a4SJonathan Peyton 
287cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
297cc577a4SJonathan Peyton #if KMP_ARCH_X86 || KMP_ARCH_ARM
307cc577a4SJonathan Peyton typedef kmp_int32 bufsize;
317cc577a4SJonathan Peyton #else
327cc577a4SJonathan Peyton typedef kmp_int64 bufsize;
337cc577a4SJonathan Peyton #endif
347cc577a4SJonathan Peyton #else
357cc577a4SJonathan Peyton typedef ssize_t bufsize;
36e4b4f994SJonathan Peyton #endif // KMP_OS_WINDOWS
377cc577a4SJonathan Peyton 
387cc577a4SJonathan Peyton /* The three modes of operation are, fifo search, lifo search, and best-fit */
397cc577a4SJonathan Peyton 
407cc577a4SJonathan Peyton typedef enum bget_mode {
417cc577a4SJonathan Peyton   bget_mode_fifo = 0,
427cc577a4SJonathan Peyton   bget_mode_lifo = 1,
437cc577a4SJonathan Peyton   bget_mode_best = 2
447cc577a4SJonathan Peyton } bget_mode_t;
457cc577a4SJonathan Peyton 
467cc577a4SJonathan Peyton static void bpool(kmp_info_t *th, void *buffer, bufsize len);
477cc577a4SJonathan Peyton static void *bget(kmp_info_t *th, bufsize size);
487cc577a4SJonathan Peyton static void *bgetz(kmp_info_t *th, bufsize size);
497cc577a4SJonathan Peyton static void *bgetr(kmp_info_t *th, void *buffer, bufsize newsize);
507cc577a4SJonathan Peyton static void brel(kmp_info_t *th, void *buf);
513041982dSJonathan Peyton static void bectl(kmp_info_t *th, bget_compact_t compact,
523041982dSJonathan Peyton                   bget_acquire_t acquire, bget_release_t release,
533041982dSJonathan Peyton                   bufsize pool_incr);
547cc577a4SJonathan Peyton 
557cc577a4SJonathan Peyton /* BGET CONFIGURATION */
563041982dSJonathan Peyton /* Buffer allocation size quantum: all buffers allocated are a
573041982dSJonathan Peyton    multiple of this size.  This MUST be a power of two. */
587cc577a4SJonathan Peyton 
593041982dSJonathan Peyton /* On IA-32 architecture with  Linux* OS, malloc() does not
60ed5fe645SKelvin Li    ensure 16 byte alignment */
617cc577a4SJonathan Peyton 
627cc577a4SJonathan Peyton #if KMP_ARCH_X86 || !KMP_HAVE_QUAD
637cc577a4SJonathan Peyton 
647cc577a4SJonathan Peyton #define SizeQuant 8
657cc577a4SJonathan Peyton #define AlignType double
667cc577a4SJonathan Peyton 
677cc577a4SJonathan Peyton #else
687cc577a4SJonathan Peyton 
697cc577a4SJonathan Peyton #define SizeQuant 16
707cc577a4SJonathan Peyton #define AlignType _Quad
717cc577a4SJonathan Peyton 
727cc577a4SJonathan Peyton #endif
737cc577a4SJonathan Peyton 
743041982dSJonathan Peyton // Define this symbol to enable the bstats() function which calculates the
753041982dSJonathan Peyton // total free space in the buffer pool, the largest available buffer, and the
763041982dSJonathan Peyton // total space currently allocated.
773041982dSJonathan Peyton #define BufStats 1
787cc577a4SJonathan Peyton 
797cc577a4SJonathan Peyton #ifdef KMP_DEBUG
807cc577a4SJonathan Peyton 
813041982dSJonathan Peyton // Define this symbol to enable the bpoold() function which dumps the buffers
823041982dSJonathan Peyton // in a buffer pool.
833041982dSJonathan Peyton #define BufDump 1
847cc577a4SJonathan Peyton 
853041982dSJonathan Peyton // Define this symbol to enable the bpoolv() function for validating a buffer
863041982dSJonathan Peyton // pool.
873041982dSJonathan Peyton #define BufValid 1
887cc577a4SJonathan Peyton 
893041982dSJonathan Peyton // Define this symbol to enable the bufdump() function which allows dumping the
903041982dSJonathan Peyton // contents of an allocated or free buffer.
913041982dSJonathan Peyton #define DumpData 1
923041982dSJonathan Peyton 
937cc577a4SJonathan Peyton #ifdef NOT_USED_NOW
947cc577a4SJonathan Peyton 
953041982dSJonathan Peyton // Wipe free buffers to a guaranteed pattern of garbage to trip up miscreants
963041982dSJonathan Peyton // who attempt to use pointers into released buffers.
973041982dSJonathan Peyton #define FreeWipe 1
987cc577a4SJonathan Peyton 
993041982dSJonathan Peyton // Use a best fit algorithm when searching for space for an allocation request.
1003041982dSJonathan Peyton // This uses memory more efficiently, but allocation will be much slower.
1013041982dSJonathan Peyton #define BestFit 1
1023041982dSJonathan Peyton 
1037cc577a4SJonathan Peyton #endif /* NOT_USED_NOW */
1047cc577a4SJonathan Peyton #endif /* KMP_DEBUG */
1057cc577a4SJonathan Peyton 
1067cc577a4SJonathan Peyton static bufsize bget_bin_size[] = {
1077cc577a4SJonathan Peyton     0,
1087cc577a4SJonathan Peyton     //    1 << 6,    /* .5 Cache line */
1097cc577a4SJonathan Peyton     1 << 7, /* 1 Cache line, new */
1107cc577a4SJonathan Peyton     1 << 8, /* 2 Cache lines */
1117cc577a4SJonathan Peyton     1 << 9, /* 4 Cache lines, new */
1127cc577a4SJonathan Peyton     1 << 10, /* 8 Cache lines */
1137cc577a4SJonathan Peyton     1 << 11, /* 16 Cache lines, new */
1143041982dSJonathan Peyton     1 << 12, 1 << 13, /* new */
1153041982dSJonathan Peyton     1 << 14, 1 << 15, /* new */
1163041982dSJonathan Peyton     1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, /*  1MB */
1177cc577a4SJonathan Peyton     1 << 21, /*  2MB */
1187cc577a4SJonathan Peyton     1 << 22, /*  4MB */
1197cc577a4SJonathan Peyton     1 << 23, /*  8MB */
1207cc577a4SJonathan Peyton     1 << 24, /* 16MB */
1217cc577a4SJonathan Peyton     1 << 25, /* 32MB */
1227cc577a4SJonathan Peyton };
1237cc577a4SJonathan Peyton 
1247cc577a4SJonathan Peyton #define MAX_BGET_BINS (int)(sizeof(bget_bin_size) / sizeof(bufsize))
1257cc577a4SJonathan Peyton 
1267cc577a4SJonathan Peyton struct bfhead;
1277cc577a4SJonathan Peyton 
1283041982dSJonathan Peyton //  Declare the interface, including the requested buffer size type, bufsize.
1297cc577a4SJonathan Peyton 
1307cc577a4SJonathan Peyton /* Queue links */
1317cc577a4SJonathan Peyton typedef struct qlinks {
1327cc577a4SJonathan Peyton   struct bfhead *flink; /* Forward link */
1337cc577a4SJonathan Peyton   struct bfhead *blink; /* Backward link */
1347cc577a4SJonathan Peyton } qlinks_t;
1357cc577a4SJonathan Peyton 
1367cc577a4SJonathan Peyton /* Header in allocated and free buffers */
1377cc577a4SJonathan Peyton typedef struct bhead2 {
1387cc577a4SJonathan Peyton   kmp_info_t *bthr; /* The thread which owns the buffer pool */
1393041982dSJonathan Peyton   bufsize prevfree; /* Relative link back to previous free buffer in memory or
1403041982dSJonathan Peyton                        0 if previous buffer is allocated.  */
1413041982dSJonathan Peyton   bufsize bsize; /* Buffer size: positive if free, negative if allocated. */
1427cc577a4SJonathan Peyton } bhead2_t;
1437cc577a4SJonathan Peyton 
1447cc577a4SJonathan Peyton /* Make sure the bhead structure is a multiple of SizeQuant in size. */
1457cc577a4SJonathan Peyton typedef union bhead {
1467cc577a4SJonathan Peyton   KMP_ALIGN(SizeQuant)
1477cc577a4SJonathan Peyton   AlignType b_align;
1487cc577a4SJonathan Peyton   char b_pad[sizeof(bhead2_t) + (SizeQuant - (sizeof(bhead2_t) % SizeQuant))];
1497cc577a4SJonathan Peyton   bhead2_t bb;
1507cc577a4SJonathan Peyton } bhead_t;
1517cc577a4SJonathan Peyton #define BH(p) ((bhead_t *)(p))
1527cc577a4SJonathan Peyton 
1537cc577a4SJonathan Peyton /*  Header in directly allocated buffers (by acqfcn) */
1543041982dSJonathan Peyton typedef struct bdhead {
1557cc577a4SJonathan Peyton   bufsize tsize; /* Total size, including overhead */
1567cc577a4SJonathan Peyton   bhead_t bh; /* Common header */
1577cc577a4SJonathan Peyton } bdhead_t;
1587cc577a4SJonathan Peyton #define BDH(p) ((bdhead_t *)(p))
1597cc577a4SJonathan Peyton 
1607cc577a4SJonathan Peyton /* Header in free buffers */
1617cc577a4SJonathan Peyton typedef struct bfhead {
1627cc577a4SJonathan Peyton   bhead_t bh; /* Common allocated/free header */
1637cc577a4SJonathan Peyton   qlinks_t ql; /* Links on free list */
1647cc577a4SJonathan Peyton } bfhead_t;
1657cc577a4SJonathan Peyton #define BFH(p) ((bfhead_t *)(p))
1667cc577a4SJonathan Peyton 
1677cc577a4SJonathan Peyton typedef struct thr_data {
1687cc577a4SJonathan Peyton   bfhead_t freelist[MAX_BGET_BINS];
1697cc577a4SJonathan Peyton #if BufStats
1707cc577a4SJonathan Peyton   size_t totalloc; /* Total space currently allocated */
1717cc577a4SJonathan Peyton   long numget, numrel; /* Number of bget() and brel() calls */
1727cc577a4SJonathan Peyton   long numpblk; /* Number of pool blocks */
1737cc577a4SJonathan Peyton   long numpget, numprel; /* Number of block gets and rels */
1747cc577a4SJonathan Peyton   long numdget, numdrel; /* Number of direct gets and rels */
1757cc577a4SJonathan Peyton #endif /* BufStats */
1767cc577a4SJonathan Peyton 
1777cc577a4SJonathan Peyton   /* Automatic expansion block management functions */
1787cc577a4SJonathan Peyton   bget_compact_t compfcn;
1797cc577a4SJonathan Peyton   bget_acquire_t acqfcn;
1807cc577a4SJonathan Peyton   bget_release_t relfcn;
1817cc577a4SJonathan Peyton 
1827cc577a4SJonathan Peyton   bget_mode_t mode; /* what allocation mode to use? */
1837cc577a4SJonathan Peyton 
1847cc577a4SJonathan Peyton   bufsize exp_incr; /* Expansion block size */
1857cc577a4SJonathan Peyton   bufsize pool_len; /* 0: no bpool calls have been made
1863041982dSJonathan Peyton                        -1: not all pool blocks are the same size
1873041982dSJonathan Peyton                        >0: (common) block size for all bpool calls made so far
1887cc577a4SJonathan Peyton                     */
18942016791SKazuaki Ishizaki   bfhead_t *last_pool; /* Last pool owned by this thread (delay deallocation) */
1907cc577a4SJonathan Peyton } thr_data_t;
1917cc577a4SJonathan Peyton 
1927cc577a4SJonathan Peyton /*  Minimum allocation quantum: */
1937cc577a4SJonathan Peyton #define QLSize (sizeof(qlinks_t))
1947cc577a4SJonathan Peyton #define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize)
1953041982dSJonathan Peyton #define MaxSize                                                                \
1963041982dSJonathan Peyton   (bufsize)(                                                                   \
1973041982dSJonathan Peyton       ~(((bufsize)(1) << (sizeof(bufsize) * CHAR_BIT - 1)) | (SizeQuant - 1)))
19842016791SKazuaki Ishizaki // Maximum for the requested size.
1997cc577a4SJonathan Peyton 
2007cc577a4SJonathan Peyton /* End sentinel: value placed in bsize field of dummy block delimiting
2017cc577a4SJonathan Peyton    end of pool block.  The most negative number which will  fit  in  a
2027cc577a4SJonathan Peyton    bufsize, defined in a way that the compiler will accept. */
2037cc577a4SJonathan Peyton 
2043041982dSJonathan Peyton #define ESent                                                                  \
2053041982dSJonathan Peyton   ((bufsize)(-(((((bufsize)1) << ((int)sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2))
2067cc577a4SJonathan Peyton 
2077cc577a4SJonathan Peyton /* Thread Data management routines */
bget_get_bin(bufsize size)2083041982dSJonathan Peyton static int bget_get_bin(bufsize size) {
2097cc577a4SJonathan Peyton   // binary chop bins
2107cc577a4SJonathan Peyton   int lo = 0, hi = MAX_BGET_BINS - 1;
2117cc577a4SJonathan Peyton 
2127cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(size > 0);
2137cc577a4SJonathan Peyton 
2147cc577a4SJonathan Peyton   while ((hi - lo) > 1) {
2157cc577a4SJonathan Peyton     int mid = (lo + hi) >> 1;
2167cc577a4SJonathan Peyton     if (size < bget_bin_size[mid])
2177cc577a4SJonathan Peyton       hi = mid - 1;
2187cc577a4SJonathan Peyton     else
2197cc577a4SJonathan Peyton       lo = mid;
2207cc577a4SJonathan Peyton   }
2217cc577a4SJonathan Peyton 
2227cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((lo >= 0) && (lo < MAX_BGET_BINS));
2237cc577a4SJonathan Peyton 
2247cc577a4SJonathan Peyton   return lo;
2257cc577a4SJonathan Peyton }
2267cc577a4SJonathan Peyton 
set_thr_data(kmp_info_t * th)2273041982dSJonathan Peyton static void set_thr_data(kmp_info_t *th) {
2287cc577a4SJonathan Peyton   int i;
2297cc577a4SJonathan Peyton   thr_data_t *data;
2307cc577a4SJonathan Peyton 
2313041982dSJonathan Peyton   data = (thr_data_t *)((!th->th.th_local.bget_data)
2323041982dSJonathan Peyton                             ? __kmp_allocate(sizeof(*data))
2333041982dSJonathan Peyton                             : th->th.th_local.bget_data);
2347cc577a4SJonathan Peyton 
2357cc577a4SJonathan Peyton   memset(data, '\0', sizeof(*data));
2367cc577a4SJonathan Peyton 
2377cc577a4SJonathan Peyton   for (i = 0; i < MAX_BGET_BINS; ++i) {
2387cc577a4SJonathan Peyton     data->freelist[i].ql.flink = &data->freelist[i];
2397cc577a4SJonathan Peyton     data->freelist[i].ql.blink = &data->freelist[i];
2407cc577a4SJonathan Peyton   }
2417cc577a4SJonathan Peyton 
2427cc577a4SJonathan Peyton   th->th.th_local.bget_data = data;
2437cc577a4SJonathan Peyton   th->th.th_local.bget_list = 0;
2447cc577a4SJonathan Peyton #if !USE_CMP_XCHG_FOR_BGET
2457cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
2467cc577a4SJonathan Peyton   __kmp_init_lock(&th->th.th_local.bget_lock);
2477cc577a4SJonathan Peyton #else
2487cc577a4SJonathan Peyton   __kmp_init_bootstrap_lock(&th->th.th_local.bget_lock);
2497cc577a4SJonathan Peyton #endif /* USE_LOCK_FOR_BGET */
2507cc577a4SJonathan Peyton #endif /* ! USE_CMP_XCHG_FOR_BGET */
2517cc577a4SJonathan Peyton }
2527cc577a4SJonathan Peyton 
get_thr_data(kmp_info_t * th)2533041982dSJonathan Peyton static thr_data_t *get_thr_data(kmp_info_t *th) {
2547cc577a4SJonathan Peyton   thr_data_t *data;
2557cc577a4SJonathan Peyton 
2567cc577a4SJonathan Peyton   data = (thr_data_t *)th->th.th_local.bget_data;
2577cc577a4SJonathan Peyton 
2587cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(data != 0);
2597cc577a4SJonathan Peyton 
2607cc577a4SJonathan Peyton   return data;
2617cc577a4SJonathan Peyton }
2627cc577a4SJonathan Peyton 
2637cc577a4SJonathan Peyton /* Walk the free list and release the enqueued buffers */
__kmp_bget_dequeue(kmp_info_t * th)2643041982dSJonathan Peyton static void __kmp_bget_dequeue(kmp_info_t *th) {
2657cc577a4SJonathan Peyton   void *p = TCR_SYNC_PTR(th->th.th_local.bget_list);
2667cc577a4SJonathan Peyton 
2677cc577a4SJonathan Peyton   if (p != 0) {
2687cc577a4SJonathan Peyton #if USE_CMP_XCHG_FOR_BGET
2697cc577a4SJonathan Peyton     {
2707cc577a4SJonathan Peyton       volatile void *old_value = TCR_SYNC_PTR(th->th.th_local.bget_list);
271c47afcd9SAndrey Churbanov       while (!KMP_COMPARE_AND_STORE_PTR(&th->th.th_local.bget_list,
2725ba90c79SAndrey Churbanov                                         CCAST(void *, old_value), nullptr)) {
2737cc577a4SJonathan Peyton         KMP_CPU_PAUSE();
2747cc577a4SJonathan Peyton         old_value = TCR_SYNC_PTR(th->th.th_local.bget_list);
2757cc577a4SJonathan Peyton       }
276c47afcd9SAndrey Churbanov       p = CCAST(void *, old_value);
2777cc577a4SJonathan Peyton     }
2787cc577a4SJonathan Peyton #else /* ! USE_CMP_XCHG_FOR_BGET */
2797cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
2803041982dSJonathan Peyton     __kmp_acquire_lock(&th->th.th_local.bget_lock, __kmp_gtid_from_thread(th));
2817cc577a4SJonathan Peyton #else
2827cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock(&th->th.th_local.bget_lock);
2837cc577a4SJonathan Peyton #endif /* USE_QUEUING_LOCK_FOR_BGET */
2847cc577a4SJonathan Peyton 
2857cc577a4SJonathan Peyton     p = (void *)th->th.th_local.bget_list;
2867cc577a4SJonathan Peyton     th->th.th_local.bget_list = 0;
2877cc577a4SJonathan Peyton 
2887cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
2893041982dSJonathan Peyton     __kmp_release_lock(&th->th.th_local.bget_lock, __kmp_gtid_from_thread(th));
2907cc577a4SJonathan Peyton #else
2917cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock(&th->th.th_local.bget_lock);
2927cc577a4SJonathan Peyton #endif
2937cc577a4SJonathan Peyton #endif /* USE_CMP_XCHG_FOR_BGET */
2947cc577a4SJonathan Peyton 
2957cc577a4SJonathan Peyton     /* Check again to make sure the list is not empty */
2967cc577a4SJonathan Peyton     while (p != 0) {
2977cc577a4SJonathan Peyton       void *buf = p;
2987cc577a4SJonathan Peyton       bfhead_t *b = BFH(((char *)p) - sizeof(bhead_t));
2997cc577a4SJonathan Peyton 
3007cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(b->bh.bb.bsize != 0);
3017cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(((kmp_uintptr_t)TCR_PTR(b->bh.bb.bthr) & ~1) ==
3027cc577a4SJonathan Peyton                        (kmp_uintptr_t)th); // clear possible mark
3037cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(b->ql.blink == 0);
3047cc577a4SJonathan Peyton 
3057cc577a4SJonathan Peyton       p = (void *)b->ql.flink;
3067cc577a4SJonathan Peyton 
3077cc577a4SJonathan Peyton       brel(th, buf);
3087cc577a4SJonathan Peyton     }
3097cc577a4SJonathan Peyton   }
3107cc577a4SJonathan Peyton }
3117cc577a4SJonathan Peyton 
3127cc577a4SJonathan Peyton /* Chain together the free buffers by using the thread owner field */
__kmp_bget_enqueue(kmp_info_t * th,void * buf,kmp_int32 rel_gtid)3133041982dSJonathan Peyton static void __kmp_bget_enqueue(kmp_info_t *th, void *buf
3147cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
3153041982dSJonathan Peyton                                ,
3163041982dSJonathan Peyton                                kmp_int32 rel_gtid
3177cc577a4SJonathan Peyton #endif
3183041982dSJonathan Peyton ) {
3197cc577a4SJonathan Peyton   bfhead_t *b = BFH(((char *)buf) - sizeof(bhead_t));
3207cc577a4SJonathan Peyton 
3217cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(b->bh.bb.bsize != 0);
3227cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(((kmp_uintptr_t)TCR_PTR(b->bh.bb.bthr) & ~1) ==
3237cc577a4SJonathan Peyton                    (kmp_uintptr_t)th); // clear possible mark
3247cc577a4SJonathan Peyton 
3257cc577a4SJonathan Peyton   b->ql.blink = 0;
3267cc577a4SJonathan Peyton 
3277cc577a4SJonathan Peyton   KC_TRACE(10, ("__kmp_bget_enqueue: moving buffer to T#%d list\n",
3287cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(th)));
3297cc577a4SJonathan Peyton 
3307cc577a4SJonathan Peyton #if USE_CMP_XCHG_FOR_BGET
3317cc577a4SJonathan Peyton   {
3327cc577a4SJonathan Peyton     volatile void *old_value = TCR_PTR(th->th.th_local.bget_list);
3337cc577a4SJonathan Peyton     /* the next pointer must be set before setting bget_list to buf to avoid
3347cc577a4SJonathan Peyton        exposing a broken list to other threads, even for an instant. */
335c47afcd9SAndrey Churbanov     b->ql.flink = BFH(CCAST(void *, old_value));
3367cc577a4SJonathan Peyton 
337c47afcd9SAndrey Churbanov     while (!KMP_COMPARE_AND_STORE_PTR(&th->th.th_local.bget_list,
338c47afcd9SAndrey Churbanov                                       CCAST(void *, old_value), buf)) {
3397cc577a4SJonathan Peyton       KMP_CPU_PAUSE();
3407cc577a4SJonathan Peyton       old_value = TCR_PTR(th->th.th_local.bget_list);
3417cc577a4SJonathan Peyton       /* the next pointer must be set before setting bget_list to buf to avoid
3427cc577a4SJonathan Peyton          exposing a broken list to other threads, even for an instant. */
343c47afcd9SAndrey Churbanov       b->ql.flink = BFH(CCAST(void *, old_value));
3447cc577a4SJonathan Peyton     }
3457cc577a4SJonathan Peyton   }
3467cc577a4SJonathan Peyton #else /* ! USE_CMP_XCHG_FOR_BGET */
3477cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
3487cc577a4SJonathan Peyton   __kmp_acquire_lock(&th->th.th_local.bget_lock, rel_gtid);
3497cc577a4SJonathan Peyton #else
3507cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&th->th.th_local.bget_lock);
3517cc577a4SJonathan Peyton #endif
3527cc577a4SJonathan Peyton 
3537cc577a4SJonathan Peyton   b->ql.flink = BFH(th->th.th_local.bget_list);
3547cc577a4SJonathan Peyton   th->th.th_local.bget_list = (void *)buf;
3557cc577a4SJonathan Peyton 
3567cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
3577cc577a4SJonathan Peyton   __kmp_release_lock(&th->th.th_local.bget_lock, rel_gtid);
3587cc577a4SJonathan Peyton #else
3597cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&th->th.th_local.bget_lock);
3607cc577a4SJonathan Peyton #endif
3617cc577a4SJonathan Peyton #endif /* USE_CMP_XCHG_FOR_BGET */
3627cc577a4SJonathan Peyton }
3637cc577a4SJonathan Peyton 
3647cc577a4SJonathan Peyton /* insert buffer back onto a new freelist */
__kmp_bget_insert_into_freelist(thr_data_t * thr,bfhead_t * b)3653041982dSJonathan Peyton static void __kmp_bget_insert_into_freelist(thr_data_t *thr, bfhead_t *b) {
3667cc577a4SJonathan Peyton   int bin;
3677cc577a4SJonathan Peyton 
3687cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(((size_t)b) % SizeQuant == 0);
3697cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(b->bh.bb.bsize % SizeQuant == 0);
3707cc577a4SJonathan Peyton 
3717cc577a4SJonathan Peyton   bin = bget_get_bin(b->bh.bb.bsize);
3727cc577a4SJonathan Peyton 
3733041982dSJonathan Peyton   KMP_DEBUG_ASSERT(thr->freelist[bin].ql.blink->ql.flink ==
3743041982dSJonathan Peyton                    &thr->freelist[bin]);
3753041982dSJonathan Peyton   KMP_DEBUG_ASSERT(thr->freelist[bin].ql.flink->ql.blink ==
3763041982dSJonathan Peyton                    &thr->freelist[bin]);
3777cc577a4SJonathan Peyton 
3787cc577a4SJonathan Peyton   b->ql.flink = &thr->freelist[bin];
3797cc577a4SJonathan Peyton   b->ql.blink = thr->freelist[bin].ql.blink;
3807cc577a4SJonathan Peyton 
3817cc577a4SJonathan Peyton   thr->freelist[bin].ql.blink = b;
3827cc577a4SJonathan Peyton   b->ql.blink->ql.flink = b;
3837cc577a4SJonathan Peyton }
3847cc577a4SJonathan Peyton 
3857cc577a4SJonathan Peyton /* unlink the buffer from the old freelist */
__kmp_bget_remove_from_freelist(bfhead_t * b)3863041982dSJonathan Peyton static void __kmp_bget_remove_from_freelist(bfhead_t *b) {
3877cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(b->ql.blink->ql.flink == b);
3887cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(b->ql.flink->ql.blink == b);
3897cc577a4SJonathan Peyton 
3907cc577a4SJonathan Peyton   b->ql.blink->ql.flink = b->ql.flink;
3917cc577a4SJonathan Peyton   b->ql.flink->ql.blink = b->ql.blink;
3927cc577a4SJonathan Peyton }
3937cc577a4SJonathan Peyton 
3947cc577a4SJonathan Peyton /*  GET STATS -- check info on free list */
bcheck(kmp_info_t * th,bufsize * max_free,bufsize * total_free)3953041982dSJonathan Peyton static void bcheck(kmp_info_t *th, bufsize *max_free, bufsize *total_free) {
3967cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
3977cc577a4SJonathan Peyton   int bin;
3987cc577a4SJonathan Peyton 
3997cc577a4SJonathan Peyton   *total_free = *max_free = 0;
4007cc577a4SJonathan Peyton 
4017cc577a4SJonathan Peyton   for (bin = 0; bin < MAX_BGET_BINS; ++bin) {
4027cc577a4SJonathan Peyton     bfhead_t *b, *best;
4037cc577a4SJonathan Peyton 
4047cc577a4SJonathan Peyton     best = &thr->freelist[bin];
4057cc577a4SJonathan Peyton     b = best->ql.flink;
4067cc577a4SJonathan Peyton 
4077cc577a4SJonathan Peyton     while (b != &thr->freelist[bin]) {
4087cc577a4SJonathan Peyton       *total_free += (b->bh.bb.bsize - sizeof(bhead_t));
4097cc577a4SJonathan Peyton       if ((best == &thr->freelist[bin]) || (b->bh.bb.bsize < best->bh.bb.bsize))
4107cc577a4SJonathan Peyton         best = b;
4117cc577a4SJonathan Peyton 
4127cc577a4SJonathan Peyton       /* Link to next buffer */
4137cc577a4SJonathan Peyton       b = b->ql.flink;
4147cc577a4SJonathan Peyton     }
4157cc577a4SJonathan Peyton 
4167cc577a4SJonathan Peyton     if (*max_free < best->bh.bb.bsize)
4177cc577a4SJonathan Peyton       *max_free = best->bh.bb.bsize;
4187cc577a4SJonathan Peyton   }
4197cc577a4SJonathan Peyton 
4207cc577a4SJonathan Peyton   if (*max_free > (bufsize)sizeof(bhead_t))
4217cc577a4SJonathan Peyton     *max_free -= sizeof(bhead_t);
4227cc577a4SJonathan Peyton }
4237cc577a4SJonathan Peyton 
4247cc577a4SJonathan Peyton /*  BGET  --  Allocate a buffer.  */
bget(kmp_info_t * th,bufsize requested_size)4253041982dSJonathan Peyton static void *bget(kmp_info_t *th, bufsize requested_size) {
4267cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
4277cc577a4SJonathan Peyton   bufsize size = requested_size;
4287cc577a4SJonathan Peyton   bfhead_t *b;
4297cc577a4SJonathan Peyton   void *buf;
4307cc577a4SJonathan Peyton   int compactseq = 0;
4317cc577a4SJonathan Peyton   int use_blink = 0;
4327cc577a4SJonathan Peyton   /* For BestFit */
4337cc577a4SJonathan Peyton   bfhead_t *best;
4347cc577a4SJonathan Peyton 
4357cc577a4SJonathan Peyton   if (size < 0 || size + sizeof(bhead_t) > MaxSize) {
4367cc577a4SJonathan Peyton     return NULL;
437bd3a7633SJonathan Peyton   }
4387cc577a4SJonathan Peyton 
4397cc577a4SJonathan Peyton   __kmp_bget_dequeue(th); /* Release any queued buffers */
4407cc577a4SJonathan Peyton 
4413041982dSJonathan Peyton   if (size < (bufsize)SizeQ) { // Need at least room for the queue links.
4423041982dSJonathan Peyton     size = SizeQ;
4437cc577a4SJonathan Peyton   }
4447cc577a4SJonathan Peyton #if defined(SizeQuant) && (SizeQuant > 1)
4457cc577a4SJonathan Peyton   size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1));
4467cc577a4SJonathan Peyton #endif
4477cc577a4SJonathan Peyton 
4483041982dSJonathan Peyton   size += sizeof(bhead_t); // Add overhead in allocated buffer to size required.
4497cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(size >= 0);
4507cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(size % SizeQuant == 0);
4517cc577a4SJonathan Peyton 
4527cc577a4SJonathan Peyton   use_blink = (thr->mode == bget_mode_lifo);
4537cc577a4SJonathan Peyton 
4547cc577a4SJonathan Peyton   /* If a compact function was provided in the call to bectl(), wrap
4557cc577a4SJonathan Peyton      a loop around the allocation process  to  allow  compaction  to
4567cc577a4SJonathan Peyton      intervene in case we don't find a suitable buffer in the chain. */
4577cc577a4SJonathan Peyton 
4587cc577a4SJonathan Peyton   for (;;) {
4597cc577a4SJonathan Peyton     int bin;
4607cc577a4SJonathan Peyton 
4617cc577a4SJonathan Peyton     for (bin = bget_get_bin(size); bin < MAX_BGET_BINS; ++bin) {
4627cc577a4SJonathan Peyton       /* Link to next buffer */
4633041982dSJonathan Peyton       b = (use_blink ? thr->freelist[bin].ql.blink
4643041982dSJonathan Peyton                      : thr->freelist[bin].ql.flink);
4657cc577a4SJonathan Peyton 
4667cc577a4SJonathan Peyton       if (thr->mode == bget_mode_best) {
4677cc577a4SJonathan Peyton         best = &thr->freelist[bin];
4687cc577a4SJonathan Peyton 
4697cc577a4SJonathan Peyton         /* Scan the free list searching for the first buffer big enough
4707cc577a4SJonathan Peyton            to hold the requested size buffer. */
4717cc577a4SJonathan Peyton         while (b != &thr->freelist[bin]) {
4727cc577a4SJonathan Peyton           if (b->bh.bb.bsize >= (bufsize)size) {
4733041982dSJonathan Peyton             if ((best == &thr->freelist[bin]) ||
4743041982dSJonathan Peyton                 (b->bh.bb.bsize < best->bh.bb.bsize)) {
4757cc577a4SJonathan Peyton               best = b;
4767cc577a4SJonathan Peyton             }
4777cc577a4SJonathan Peyton           }
4787cc577a4SJonathan Peyton 
4797cc577a4SJonathan Peyton           /* Link to next buffer */
4807cc577a4SJonathan Peyton           b = (use_blink ? b->ql.blink : b->ql.flink);
4817cc577a4SJonathan Peyton         }
4827cc577a4SJonathan Peyton         b = best;
4837cc577a4SJonathan Peyton       }
4847cc577a4SJonathan Peyton 
4857cc577a4SJonathan Peyton       while (b != &thr->freelist[bin]) {
4867cc577a4SJonathan Peyton         if ((bufsize)b->bh.bb.bsize >= (bufsize)size) {
4877cc577a4SJonathan Peyton 
4883041982dSJonathan Peyton           // Buffer is big enough to satisfy the request. Allocate it to the
4893041982dSJonathan Peyton           // caller. We must decide whether the buffer is large enough to split
4903041982dSJonathan Peyton           // into the part given to the caller and a free buffer that remains
4913041982dSJonathan Peyton           // on the free list, or whether the entire buffer should be removed
4923041982dSJonathan Peyton           // from the free list and given to the caller in its entirety. We
4933041982dSJonathan Peyton           // only split the buffer if enough room remains for a header plus the
4943041982dSJonathan Peyton           // minimum quantum of allocation.
4953041982dSJonathan Peyton           if ((b->bh.bb.bsize - (bufsize)size) >
4963041982dSJonathan Peyton               (bufsize)(SizeQ + (sizeof(bhead_t)))) {
4977cc577a4SJonathan Peyton             bhead_t *ba, *bn;
4987cc577a4SJonathan Peyton 
4997cc577a4SJonathan Peyton             ba = BH(((char *)b) + (b->bh.bb.bsize - (bufsize)size));
5007cc577a4SJonathan Peyton             bn = BH(((char *)ba) + size);
5017cc577a4SJonathan Peyton 
5027cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(bn->bb.prevfree == b->bh.bb.bsize);
5037cc577a4SJonathan Peyton 
5047cc577a4SJonathan Peyton             /* Subtract size from length of free block. */
5057cc577a4SJonathan Peyton             b->bh.bb.bsize -= (bufsize)size;
5067cc577a4SJonathan Peyton 
5077cc577a4SJonathan Peyton             /* Link allocated buffer to the previous free buffer. */
5087cc577a4SJonathan Peyton             ba->bb.prevfree = b->bh.bb.bsize;
5097cc577a4SJonathan Peyton 
5107cc577a4SJonathan Peyton             /* Plug negative size into user buffer. */
5117cc577a4SJonathan Peyton             ba->bb.bsize = -size;
5127cc577a4SJonathan Peyton 
5137cc577a4SJonathan Peyton             /* Mark this buffer as owned by this thread. */
5143041982dSJonathan Peyton             TCW_PTR(ba->bb.bthr,
5153041982dSJonathan Peyton                     th); // not an allocated address (do not mark it)
5167cc577a4SJonathan Peyton             /* Mark buffer after this one not preceded by free block. */
5177cc577a4SJonathan Peyton             bn->bb.prevfree = 0;
5187cc577a4SJonathan Peyton 
5193041982dSJonathan Peyton             // unlink buffer from old freelist, and reinsert into new freelist
5207cc577a4SJonathan Peyton             __kmp_bget_remove_from_freelist(b);
5217cc577a4SJonathan Peyton             __kmp_bget_insert_into_freelist(thr, b);
5227cc577a4SJonathan Peyton #if BufStats
5237cc577a4SJonathan Peyton             thr->totalloc += (size_t)size;
5247cc577a4SJonathan Peyton             thr->numget++; /* Increment number of bget() calls */
5257cc577a4SJonathan Peyton #endif
5267cc577a4SJonathan Peyton             buf = (void *)((((char *)ba) + sizeof(bhead_t)));
5277cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0);
5287cc577a4SJonathan Peyton             return buf;
5297cc577a4SJonathan Peyton           } else {
5307cc577a4SJonathan Peyton             bhead_t *ba;
5317cc577a4SJonathan Peyton 
5327cc577a4SJonathan Peyton             ba = BH(((char *)b) + b->bh.bb.bsize);
5337cc577a4SJonathan Peyton 
5347cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(ba->bb.prevfree == b->bh.bb.bsize);
5357cc577a4SJonathan Peyton 
5367cc577a4SJonathan Peyton             /* The buffer isn't big enough to split.  Give  the  whole
5377cc577a4SJonathan Peyton                shebang to the caller and remove it from the free list. */
5387cc577a4SJonathan Peyton 
5397cc577a4SJonathan Peyton             __kmp_bget_remove_from_freelist(b);
5407cc577a4SJonathan Peyton #if BufStats
5417cc577a4SJonathan Peyton             thr->totalloc += (size_t)b->bh.bb.bsize;
5427cc577a4SJonathan Peyton             thr->numget++; /* Increment number of bget() calls */
5437cc577a4SJonathan Peyton #endif
5447cc577a4SJonathan Peyton             /* Negate size to mark buffer allocated. */
5457cc577a4SJonathan Peyton             b->bh.bb.bsize = -(b->bh.bb.bsize);
5467cc577a4SJonathan Peyton 
5477cc577a4SJonathan Peyton             /* Mark this buffer as owned by this thread. */
5483041982dSJonathan Peyton             TCW_PTR(ba->bb.bthr, th); // not an allocated address (do not mark)
5497cc577a4SJonathan Peyton             /* Zero the back pointer in the next buffer in memory
5507cc577a4SJonathan Peyton                to indicate that this buffer is allocated. */
5517cc577a4SJonathan Peyton             ba->bb.prevfree = 0;
5527cc577a4SJonathan Peyton 
5537cc577a4SJonathan Peyton             /* Give user buffer starting at queue links. */
5547cc577a4SJonathan Peyton             buf = (void *)&(b->ql);
5557cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0);
5567cc577a4SJonathan Peyton             return buf;
5577cc577a4SJonathan Peyton           }
5587cc577a4SJonathan Peyton         }
5597cc577a4SJonathan Peyton 
5607cc577a4SJonathan Peyton         /* Link to next buffer */
5617cc577a4SJonathan Peyton         b = (use_blink ? b->ql.blink : b->ql.flink);
5627cc577a4SJonathan Peyton       }
5637cc577a4SJonathan Peyton     }
5647cc577a4SJonathan Peyton 
5653041982dSJonathan Peyton     /* We failed to find a buffer. If there's a compact function defined,
5663041982dSJonathan Peyton        notify it of the size requested. If it returns TRUE, try the allocation
5673041982dSJonathan Peyton        again. */
5687cc577a4SJonathan Peyton 
5697cc577a4SJonathan Peyton     if ((thr->compfcn == 0) || (!(*thr->compfcn)(size, ++compactseq))) {
5707cc577a4SJonathan Peyton       break;
5717cc577a4SJonathan Peyton     }
5727cc577a4SJonathan Peyton   }
5737cc577a4SJonathan Peyton 
5747cc577a4SJonathan Peyton   /* No buffer available with requested size free. */
5757cc577a4SJonathan Peyton 
5767cc577a4SJonathan Peyton   /* Don't give up yet -- look in the reserve supply. */
5777cc577a4SJonathan Peyton   if (thr->acqfcn != 0) {
5787cc577a4SJonathan Peyton     if (size > (bufsize)(thr->exp_incr - sizeof(bhead_t))) {
5793041982dSJonathan Peyton       /* Request is too large to fit in a single expansion block.
58042016791SKazuaki Ishizaki          Try to satisfy it by a direct buffer acquisition. */
5817cc577a4SJonathan Peyton       bdhead_t *bdh;
5827cc577a4SJonathan Peyton 
5837cc577a4SJonathan Peyton       size += sizeof(bdhead_t) - sizeof(bhead_t);
5847cc577a4SJonathan Peyton 
5857cc577a4SJonathan Peyton       KE_TRACE(10, ("%%%%%% MALLOC( %d )\n", (int)size));
5867cc577a4SJonathan Peyton 
5877cc577a4SJonathan Peyton       /* richryan */
5887cc577a4SJonathan Peyton       bdh = BDH((*thr->acqfcn)((bufsize)size));
5897cc577a4SJonathan Peyton       if (bdh != NULL) {
5907cc577a4SJonathan Peyton 
5913041982dSJonathan Peyton         // Mark the buffer special by setting size field of its header to zero.
5927cc577a4SJonathan Peyton         bdh->bh.bb.bsize = 0;
5937cc577a4SJonathan Peyton 
5947cc577a4SJonathan Peyton         /* Mark this buffer as owned by this thread. */
5957cc577a4SJonathan Peyton         TCW_PTR(bdh->bh.bb.bthr, th); // don't mark buffer as allocated,
5967cc577a4SJonathan Peyton         // because direct buffer never goes to free list
5977cc577a4SJonathan Peyton         bdh->bh.bb.prevfree = 0;
5987cc577a4SJonathan Peyton         bdh->tsize = size;
5997cc577a4SJonathan Peyton #if BufStats
6007cc577a4SJonathan Peyton         thr->totalloc += (size_t)size;
6017cc577a4SJonathan Peyton         thr->numget++; /* Increment number of bget() calls */
6027cc577a4SJonathan Peyton         thr->numdget++; /* Direct bget() call count */
6037cc577a4SJonathan Peyton #endif
6047cc577a4SJonathan Peyton         buf = (void *)(bdh + 1);
6057cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0);
6067cc577a4SJonathan Peyton         return buf;
6077cc577a4SJonathan Peyton       }
6087cc577a4SJonathan Peyton 
6097cc577a4SJonathan Peyton     } else {
6107cc577a4SJonathan Peyton 
6117cc577a4SJonathan Peyton       /*  Try to obtain a new expansion block */
6127cc577a4SJonathan Peyton       void *newpool;
6137cc577a4SJonathan Peyton 
6147cc577a4SJonathan Peyton       KE_TRACE(10, ("%%%%%% MALLOCB( %d )\n", (int)thr->exp_incr));
6157cc577a4SJonathan Peyton 
6167cc577a4SJonathan Peyton       /* richryan */
6177cc577a4SJonathan Peyton       newpool = (*thr->acqfcn)((bufsize)thr->exp_incr);
6187cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(((size_t)newpool) % SizeQuant == 0);
6197cc577a4SJonathan Peyton       if (newpool != NULL) {
6207cc577a4SJonathan Peyton         bpool(th, newpool, thr->exp_incr);
6213041982dSJonathan Peyton         buf = bget(
6223041982dSJonathan Peyton             th, requested_size); /* This can't, I say, can't get into a loop. */
6237cc577a4SJonathan Peyton         return buf;
6247cc577a4SJonathan Peyton       }
6257cc577a4SJonathan Peyton     }
6267cc577a4SJonathan Peyton   }
6277cc577a4SJonathan Peyton 
6287cc577a4SJonathan Peyton   /*  Still no buffer available */
6297cc577a4SJonathan Peyton 
6307cc577a4SJonathan Peyton   return NULL;
6317cc577a4SJonathan Peyton }
6327cc577a4SJonathan Peyton 
6337cc577a4SJonathan Peyton /*  BGETZ  --  Allocate a buffer and clear its contents to zero.  We clear
6347cc577a4SJonathan Peyton                the  entire  contents  of  the buffer to zero, not just the
6357cc577a4SJonathan Peyton                region requested by the caller. */
6367cc577a4SJonathan Peyton 
bgetz(kmp_info_t * th,bufsize size)6373041982dSJonathan Peyton static void *bgetz(kmp_info_t *th, bufsize size) {
6387cc577a4SJonathan Peyton   char *buf = (char *)bget(th, size);
6397cc577a4SJonathan Peyton 
6407cc577a4SJonathan Peyton   if (buf != NULL) {
6417cc577a4SJonathan Peyton     bhead_t *b;
6427cc577a4SJonathan Peyton     bufsize rsize;
6437cc577a4SJonathan Peyton 
6447cc577a4SJonathan Peyton     b = BH(buf - sizeof(bhead_t));
6457cc577a4SJonathan Peyton     rsize = -(b->bb.bsize);
6467cc577a4SJonathan Peyton     if (rsize == 0) {
6477cc577a4SJonathan Peyton       bdhead_t *bd;
6487cc577a4SJonathan Peyton 
6497cc577a4SJonathan Peyton       bd = BDH(buf - sizeof(bdhead_t));
6507cc577a4SJonathan Peyton       rsize = bd->tsize - (bufsize)sizeof(bdhead_t);
6517cc577a4SJonathan Peyton     } else {
6527cc577a4SJonathan Peyton       rsize -= sizeof(bhead_t);
6537cc577a4SJonathan Peyton     }
6547cc577a4SJonathan Peyton 
6557cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(rsize >= size);
6567cc577a4SJonathan Peyton 
6577cc577a4SJonathan Peyton     (void)memset(buf, 0, (bufsize)rsize);
6587cc577a4SJonathan Peyton   }
6597cc577a4SJonathan Peyton   return ((void *)buf);
6607cc577a4SJonathan Peyton }
6617cc577a4SJonathan Peyton 
6627cc577a4SJonathan Peyton /*  BGETR  --  Reallocate a buffer.  This is a minimal implementation,
6637cc577a4SJonathan Peyton                simply in terms of brel()  and  bget().   It  could  be
6647cc577a4SJonathan Peyton                enhanced to allow the buffer to grow into adjacent free
6657cc577a4SJonathan Peyton                blocks and to avoid moving data unnecessarily.  */
6667cc577a4SJonathan Peyton 
bgetr(kmp_info_t * th,void * buf,bufsize size)6673041982dSJonathan Peyton static void *bgetr(kmp_info_t *th, void *buf, bufsize size) {
6687cc577a4SJonathan Peyton   void *nbuf;
6697cc577a4SJonathan Peyton   bufsize osize; /* Old size of buffer */
6707cc577a4SJonathan Peyton   bhead_t *b;
6717cc577a4SJonathan Peyton 
6727cc577a4SJonathan Peyton   nbuf = bget(th, size);
6737cc577a4SJonathan Peyton   if (nbuf == NULL) { /* Acquire new buffer */
6747cc577a4SJonathan Peyton     return NULL;
6757cc577a4SJonathan Peyton   }
6767cc577a4SJonathan Peyton   if (buf == NULL) {
6777cc577a4SJonathan Peyton     return nbuf;
6787cc577a4SJonathan Peyton   }
6797cc577a4SJonathan Peyton   b = BH(((char *)buf) - sizeof(bhead_t));
6807cc577a4SJonathan Peyton   osize = -b->bb.bsize;
6817cc577a4SJonathan Peyton   if (osize == 0) {
6827cc577a4SJonathan Peyton     /*  Buffer acquired directly through acqfcn. */
6837cc577a4SJonathan Peyton     bdhead_t *bd;
6847cc577a4SJonathan Peyton 
6857cc577a4SJonathan Peyton     bd = BDH(((char *)buf) - sizeof(bdhead_t));
6867cc577a4SJonathan Peyton     osize = bd->tsize - (bufsize)sizeof(bdhead_t);
6877cc577a4SJonathan Peyton   } else {
6887cc577a4SJonathan Peyton     osize -= sizeof(bhead_t);
689bd3a7633SJonathan Peyton   }
6907cc577a4SJonathan Peyton 
6917cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(osize > 0);
6927cc577a4SJonathan Peyton 
6937cc577a4SJonathan Peyton   (void)KMP_MEMCPY((char *)nbuf, (char *)buf, /* Copy the data */
6947cc577a4SJonathan Peyton                    (size_t)((size < osize) ? size : osize));
6957cc577a4SJonathan Peyton   brel(th, buf);
6967cc577a4SJonathan Peyton 
6977cc577a4SJonathan Peyton   return nbuf;
6987cc577a4SJonathan Peyton }
6997cc577a4SJonathan Peyton 
7007cc577a4SJonathan Peyton /*  BREL  --  Release a buffer.  */
brel(kmp_info_t * th,void * buf)7013041982dSJonathan Peyton static void brel(kmp_info_t *th, void *buf) {
7027cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
7037cc577a4SJonathan Peyton   bfhead_t *b, *bn;
7047cc577a4SJonathan Peyton   kmp_info_t *bth;
7057cc577a4SJonathan Peyton 
7067cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(buf != NULL);
7077cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0);
7087cc577a4SJonathan Peyton 
7097cc577a4SJonathan Peyton   b = BFH(((char *)buf) - sizeof(bhead_t));
7107cc577a4SJonathan Peyton 
7117cc577a4SJonathan Peyton   if (b->bh.bb.bsize == 0) { /* Directly-acquired buffer? */
7127cc577a4SJonathan Peyton     bdhead_t *bdh;
7137cc577a4SJonathan Peyton 
7147cc577a4SJonathan Peyton     bdh = BDH(((char *)buf) - sizeof(bdhead_t));
7157cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(b->bh.bb.prevfree == 0);
7167cc577a4SJonathan Peyton #if BufStats
7177cc577a4SJonathan Peyton     thr->totalloc -= (size_t)bdh->tsize;
7187cc577a4SJonathan Peyton     thr->numdrel++; /* Number of direct releases */
7197cc577a4SJonathan Peyton     thr->numrel++; /* Increment number of brel() calls */
7207cc577a4SJonathan Peyton #endif /* BufStats */
7217cc577a4SJonathan Peyton #ifdef FreeWipe
7223041982dSJonathan Peyton     (void)memset((char *)buf, 0x55, (size_t)(bdh->tsize - sizeof(bdhead_t)));
7237cc577a4SJonathan Peyton #endif /* FreeWipe */
7247cc577a4SJonathan Peyton 
7257cc577a4SJonathan Peyton     KE_TRACE(10, ("%%%%%% FREE( %p )\n", (void *)bdh));
7267cc577a4SJonathan Peyton 
7277cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(thr->relfcn != 0);
7287cc577a4SJonathan Peyton     (*thr->relfcn)((void *)bdh); /* Release it directly. */
7297cc577a4SJonathan Peyton     return;
7307cc577a4SJonathan Peyton   }
7317cc577a4SJonathan Peyton 
7323041982dSJonathan Peyton   bth = (kmp_info_t *)((kmp_uintptr_t)TCR_PTR(b->bh.bb.bthr) &
7333041982dSJonathan Peyton                        ~1); // clear possible mark before comparison
7347cc577a4SJonathan Peyton   if (bth != th) {
7357cc577a4SJonathan Peyton     /* Add this buffer to be released by the owning thread later */
7367cc577a4SJonathan Peyton     __kmp_bget_enqueue(bth, buf
7377cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET
7383041982dSJonathan Peyton                        ,
7393041982dSJonathan Peyton                        __kmp_gtid_from_thread(th)
7407cc577a4SJonathan Peyton #endif
7417cc577a4SJonathan Peyton     );
7427cc577a4SJonathan Peyton     return;
7437cc577a4SJonathan Peyton   }
7447cc577a4SJonathan Peyton 
7453041982dSJonathan Peyton   /* Buffer size must be negative, indicating that the buffer is allocated. */
7467cc577a4SJonathan Peyton   if (b->bh.bb.bsize >= 0) {
7477cc577a4SJonathan Peyton     bn = NULL;
7487cc577a4SJonathan Peyton   }
7497cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(b->bh.bb.bsize < 0);
7507cc577a4SJonathan Peyton 
7513041982dSJonathan Peyton   /*  Back pointer in next buffer must be zero, indicating the same thing: */
7527cc577a4SJonathan Peyton 
7537cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(BH((char *)b - b->bh.bb.bsize)->bb.prevfree == 0);
7547cc577a4SJonathan Peyton 
7557cc577a4SJonathan Peyton #if BufStats
7567cc577a4SJonathan Peyton   thr->numrel++; /* Increment number of brel() calls */
7577cc577a4SJonathan Peyton   thr->totalloc += (size_t)b->bh.bb.bsize;
7587cc577a4SJonathan Peyton #endif
7597cc577a4SJonathan Peyton 
7607cc577a4SJonathan Peyton   /* If the back link is nonzero, the previous buffer is free.  */
7617cc577a4SJonathan Peyton 
7627cc577a4SJonathan Peyton   if (b->bh.bb.prevfree != 0) {
7633041982dSJonathan Peyton     /* The previous buffer is free. Consolidate this buffer with it by adding
7643041982dSJonathan Peyton        the length of this buffer to the previous free buffer. Note that we
7653041982dSJonathan Peyton        subtract the size in the buffer being released, since it's negative to
7663041982dSJonathan Peyton        indicate that the buffer is allocated. */
767414544c9SEd Maste     bufsize size = b->bh.bb.bsize;
7687cc577a4SJonathan Peyton 
7697cc577a4SJonathan Peyton     /* Make the previous buffer the one we're working on. */
7703041982dSJonathan Peyton     KMP_DEBUG_ASSERT(BH((char *)b - b->bh.bb.prevfree)->bb.bsize ==
7713041982dSJonathan Peyton                      b->bh.bb.prevfree);
7727cc577a4SJonathan Peyton     b = BFH(((char *)b) - b->bh.bb.prevfree);
7737cc577a4SJonathan Peyton     b->bh.bb.bsize -= size;
7747cc577a4SJonathan Peyton 
7757cc577a4SJonathan Peyton     /* unlink the buffer from the old freelist */
7767cc577a4SJonathan Peyton     __kmp_bget_remove_from_freelist(b);
7773041982dSJonathan Peyton   } else {
7783041982dSJonathan Peyton     /* The previous buffer isn't allocated. Mark this buffer size as positive
7793041982dSJonathan Peyton        (i.e. free) and fall through to place the buffer on the free list as an
7803041982dSJonathan Peyton        isolated free block. */
7817cc577a4SJonathan Peyton     b->bh.bb.bsize = -b->bh.bb.bsize;
7827cc577a4SJonathan Peyton   }
7837cc577a4SJonathan Peyton 
7847cc577a4SJonathan Peyton   /* insert buffer back onto a new freelist */
7857cc577a4SJonathan Peyton   __kmp_bget_insert_into_freelist(thr, b);
7867cc577a4SJonathan Peyton 
7877cc577a4SJonathan Peyton   /* Now we look at the next buffer in memory, located by advancing from
7887cc577a4SJonathan Peyton      the  start  of  this  buffer  by its size, to see if that buffer is
7897cc577a4SJonathan Peyton      free.  If it is, we combine  this  buffer  with  the  next  one  in
7907cc577a4SJonathan Peyton      memory, dechaining the second buffer from the free list. */
7917cc577a4SJonathan Peyton   bn = BFH(((char *)b) + b->bh.bb.bsize);
7927cc577a4SJonathan Peyton   if (bn->bh.bb.bsize > 0) {
7937cc577a4SJonathan Peyton 
7947cc577a4SJonathan Peyton     /* The buffer is free.  Remove it from the free list and add
7957cc577a4SJonathan Peyton        its size to that of our buffer. */
7963041982dSJonathan Peyton     KMP_DEBUG_ASSERT(BH((char *)bn + bn->bh.bb.bsize)->bb.prevfree ==
7973041982dSJonathan Peyton                      bn->bh.bb.bsize);
7987cc577a4SJonathan Peyton 
7997cc577a4SJonathan Peyton     __kmp_bget_remove_from_freelist(bn);
8007cc577a4SJonathan Peyton 
8017cc577a4SJonathan Peyton     b->bh.bb.bsize += bn->bh.bb.bsize;
8027cc577a4SJonathan Peyton 
8033041982dSJonathan Peyton     /* unlink the buffer from the old freelist, and reinsert it into the new
8043041982dSJonathan Peyton      * freelist */
8057cc577a4SJonathan Peyton     __kmp_bget_remove_from_freelist(b);
8067cc577a4SJonathan Peyton     __kmp_bget_insert_into_freelist(thr, b);
8077cc577a4SJonathan Peyton 
8087cc577a4SJonathan Peyton     /* Finally,  advance  to   the  buffer  that   follows  the  newly
8097cc577a4SJonathan Peyton        consolidated free block.  We must set its  backpointer  to  the
8107cc577a4SJonathan Peyton        head  of  the  consolidated free block.  We know the next block
8117cc577a4SJonathan Peyton        must be an allocated block because the process of recombination
8127cc577a4SJonathan Peyton        guarantees  that  two  free  blocks will never be contiguous in
8137cc577a4SJonathan Peyton        memory.  */
8147cc577a4SJonathan Peyton     bn = BFH(((char *)b) + b->bh.bb.bsize);
8157cc577a4SJonathan Peyton   }
8167cc577a4SJonathan Peyton #ifdef FreeWipe
8177cc577a4SJonathan Peyton   (void)memset(((char *)b) + sizeof(bfhead_t), 0x55,
8187cc577a4SJonathan Peyton                (size_t)(b->bh.bb.bsize - sizeof(bfhead_t)));
8197cc577a4SJonathan Peyton #endif
8207cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(bn->bh.bb.bsize < 0);
8217cc577a4SJonathan Peyton 
8227cc577a4SJonathan Peyton   /* The next buffer is allocated.  Set the backpointer in it  to  point
8237cc577a4SJonathan Peyton      to this buffer; the previous free buffer in memory. */
8247cc577a4SJonathan Peyton 
8257cc577a4SJonathan Peyton   bn->bh.bb.prevfree = b->bh.bb.bsize;
8267cc577a4SJonathan Peyton 
8277cc577a4SJonathan Peyton   /*  If  a  block-release function is defined, and this free buffer
8287cc577a4SJonathan Peyton       constitutes the entire block, release it.  Note that  pool_len
8297cc577a4SJonathan Peyton       is  defined  in  such a way that the test will fail unless all
8307cc577a4SJonathan Peyton       pool blocks are the same size.  */
8317cc577a4SJonathan Peyton   if (thr->relfcn != 0 &&
8323041982dSJonathan Peyton       b->bh.bb.bsize == (bufsize)(thr->pool_len - sizeof(bhead_t))) {
8337cc577a4SJonathan Peyton #if BufStats
8343041982dSJonathan Peyton     if (thr->numpblk !=
8353041982dSJonathan Peyton         1) { /* Do not release the last buffer until finalization time */
8367cc577a4SJonathan Peyton #endif
8377cc577a4SJonathan Peyton 
8387cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(b->bh.bb.prevfree == 0);
8397cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.bsize == ESent);
8403041982dSJonathan Peyton       KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.prevfree ==
8413041982dSJonathan Peyton                        b->bh.bb.bsize);
8427cc577a4SJonathan Peyton 
8437cc577a4SJonathan Peyton       /*  Unlink the buffer from the free list  */
8447cc577a4SJonathan Peyton       __kmp_bget_remove_from_freelist(b);
8457cc577a4SJonathan Peyton 
8467cc577a4SJonathan Peyton       KE_TRACE(10, ("%%%%%% FREE( %p )\n", (void *)b));
8477cc577a4SJonathan Peyton 
8487cc577a4SJonathan Peyton       (*thr->relfcn)(b);
8497cc577a4SJonathan Peyton #if BufStats
8507cc577a4SJonathan Peyton       thr->numprel++; /* Nr of expansion block releases */
8517cc577a4SJonathan Peyton       thr->numpblk--; /* Total number of blocks */
8527cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(thr->numpblk == thr->numpget - thr->numprel);
8537cc577a4SJonathan Peyton 
8543041982dSJonathan Peyton       // avoid leaving stale last_pool pointer around if it is being dealloced
8553041982dSJonathan Peyton       if (thr->last_pool == b)
8563041982dSJonathan Peyton         thr->last_pool = 0;
8573041982dSJonathan Peyton     } else {
8587cc577a4SJonathan Peyton       thr->last_pool = b;
8597cc577a4SJonathan Peyton     }
8607cc577a4SJonathan Peyton #endif /* BufStats */
8617cc577a4SJonathan Peyton   }
8627cc577a4SJonathan Peyton }
8637cc577a4SJonathan Peyton 
8647cc577a4SJonathan Peyton /*  BECTL  --  Establish automatic pool expansion control  */
bectl(kmp_info_t * th,bget_compact_t compact,bget_acquire_t acquire,bget_release_t release,bufsize pool_incr)8653041982dSJonathan Peyton static void bectl(kmp_info_t *th, bget_compact_t compact,
8663041982dSJonathan Peyton                   bget_acquire_t acquire, bget_release_t release,
8673041982dSJonathan Peyton                   bufsize pool_incr) {
8687cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
8697cc577a4SJonathan Peyton 
8707cc577a4SJonathan Peyton   thr->compfcn = compact;
8717cc577a4SJonathan Peyton   thr->acqfcn = acquire;
8727cc577a4SJonathan Peyton   thr->relfcn = release;
8737cc577a4SJonathan Peyton   thr->exp_incr = pool_incr;
8747cc577a4SJonathan Peyton }
8757cc577a4SJonathan Peyton 
8767cc577a4SJonathan Peyton /*  BPOOL  --  Add a region of memory to the buffer pool.  */
bpool(kmp_info_t * th,void * buf,bufsize len)8773041982dSJonathan Peyton static void bpool(kmp_info_t *th, void *buf, bufsize len) {
8787cc577a4SJonathan Peyton   /*    int bin = 0; */
8797cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
8807cc577a4SJonathan Peyton   bfhead_t *b = BFH(buf);
8817cc577a4SJonathan Peyton   bhead_t *bn;
8827cc577a4SJonathan Peyton 
8837cc577a4SJonathan Peyton   __kmp_bget_dequeue(th); /* Release any queued buffers */
8847cc577a4SJonathan Peyton 
8857cc577a4SJonathan Peyton #ifdef SizeQuant
88652cac541SAndreyChurbanov   len &= ~((bufsize)(SizeQuant - 1));
8877cc577a4SJonathan Peyton #endif
8887cc577a4SJonathan Peyton   if (thr->pool_len == 0) {
8897cc577a4SJonathan Peyton     thr->pool_len = len;
8907cc577a4SJonathan Peyton   } else if (len != thr->pool_len) {
8917cc577a4SJonathan Peyton     thr->pool_len = -1;
8927cc577a4SJonathan Peyton   }
8937cc577a4SJonathan Peyton #if BufStats
8947cc577a4SJonathan Peyton   thr->numpget++; /* Number of block acquisitions */
8957cc577a4SJonathan Peyton   thr->numpblk++; /* Number of blocks total */
8967cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(thr->numpblk == thr->numpget - thr->numprel);
8977cc577a4SJonathan Peyton #endif /* BufStats */
8987cc577a4SJonathan Peyton 
8997cc577a4SJonathan Peyton   /* Since the block is initially occupied by a single free  buffer,
9007cc577a4SJonathan Peyton      it  had  better  not  be  (much) larger than the largest buffer
9017cc577a4SJonathan Peyton      whose size we can store in bhead.bb.bsize. */
9027cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(len - sizeof(bhead_t) <= -((bufsize)ESent + 1));
9037cc577a4SJonathan Peyton 
9047cc577a4SJonathan Peyton   /* Clear  the  backpointer at  the start of the block to indicate that
9057cc577a4SJonathan Peyton      there  is  no  free  block  prior  to  this   one.    That   blocks
9067cc577a4SJonathan Peyton      recombination when the first block in memory is released. */
9077cc577a4SJonathan Peyton   b->bh.bb.prevfree = 0;
9087cc577a4SJonathan Peyton 
9097cc577a4SJonathan Peyton   /* Create a dummy allocated buffer at the end of the pool.  This dummy
9107cc577a4SJonathan Peyton      buffer is seen when a buffer at the end of the pool is released and
9117cc577a4SJonathan Peyton      blocks  recombination  of  the last buffer with the dummy buffer at
9127cc577a4SJonathan Peyton      the end.  The length in the dummy buffer  is  set  to  the  largest
9137cc577a4SJonathan Peyton      negative  number  to  denote  the  end  of  the pool for diagnostic
9147cc577a4SJonathan Peyton      routines (this specific value is  not  counted  on  by  the  actual
9157cc577a4SJonathan Peyton      allocation and release functions). */
9167cc577a4SJonathan Peyton   len -= sizeof(bhead_t);
9177cc577a4SJonathan Peyton   b->bh.bb.bsize = (bufsize)len;
9187cc577a4SJonathan Peyton   /* Set the owner of this buffer */
9193041982dSJonathan Peyton   TCW_PTR(b->bh.bb.bthr,
9203041982dSJonathan Peyton           (kmp_info_t *)((kmp_uintptr_t)th |
9213041982dSJonathan Peyton                          1)); // mark the buffer as allocated address
9227cc577a4SJonathan Peyton 
9237cc577a4SJonathan Peyton   /* Chain the new block to the free list. */
9247cc577a4SJonathan Peyton   __kmp_bget_insert_into_freelist(thr, b);
9257cc577a4SJonathan Peyton 
9267cc577a4SJonathan Peyton #ifdef FreeWipe
9277cc577a4SJonathan Peyton   (void)memset(((char *)b) + sizeof(bfhead_t), 0x55,
9287cc577a4SJonathan Peyton                (size_t)(len - sizeof(bfhead_t)));
9297cc577a4SJonathan Peyton #endif
9307cc577a4SJonathan Peyton   bn = BH(((char *)b) + len);
9317cc577a4SJonathan Peyton   bn->bb.prevfree = (bufsize)len;
9327cc577a4SJonathan Peyton   /* Definition of ESent assumes two's complement! */
9337cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((~0) == -1 && (bn != 0));
9347cc577a4SJonathan Peyton 
9357cc577a4SJonathan Peyton   bn->bb.bsize = ESent;
9367cc577a4SJonathan Peyton }
9377cc577a4SJonathan Peyton 
9387cc577a4SJonathan Peyton /*  BFREED  --  Dump the free lists for this thread. */
bfreed(kmp_info_t * th)9393041982dSJonathan Peyton static void bfreed(kmp_info_t *th) {
9407cc577a4SJonathan Peyton   int bin = 0, count = 0;
9417cc577a4SJonathan Peyton   int gtid = __kmp_gtid_from_thread(th);
9427cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
9437cc577a4SJonathan Peyton 
9447cc577a4SJonathan Peyton #if BufStats
9453041982dSJonathan Peyton   __kmp_printf_no_lock("__kmp_printpool: T#%d total=%" KMP_UINT64_SPEC
9463041982dSJonathan Peyton                        " get=%" KMP_INT64_SPEC " rel=%" KMP_INT64_SPEC
9473041982dSJonathan Peyton                        " pblk=%" KMP_INT64_SPEC " pget=%" KMP_INT64_SPEC
9483041982dSJonathan Peyton                        " prel=%" KMP_INT64_SPEC " dget=%" KMP_INT64_SPEC
9493041982dSJonathan Peyton                        " drel=%" KMP_INT64_SPEC "\n",
9503041982dSJonathan Peyton                        gtid, (kmp_uint64)thr->totalloc, (kmp_int64)thr->numget,
9513041982dSJonathan Peyton                        (kmp_int64)thr->numrel, (kmp_int64)thr->numpblk,
9527cc577a4SJonathan Peyton                        (kmp_int64)thr->numpget, (kmp_int64)thr->numprel,
9537cc577a4SJonathan Peyton                        (kmp_int64)thr->numdget, (kmp_int64)thr->numdrel);
9547cc577a4SJonathan Peyton #endif
9557cc577a4SJonathan Peyton 
9567cc577a4SJonathan Peyton   for (bin = 0; bin < MAX_BGET_BINS; ++bin) {
9577cc577a4SJonathan Peyton     bfhead_t *b;
9587cc577a4SJonathan Peyton 
9593041982dSJonathan Peyton     for (b = thr->freelist[bin].ql.flink; b != &thr->freelist[bin];
9603041982dSJonathan Peyton          b = b->ql.flink) {
9617cc577a4SJonathan Peyton       bufsize bs = b->bh.bb.bsize;
9627cc577a4SJonathan Peyton 
9637cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(b->ql.blink->ql.flink == b);
9647cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(b->ql.flink->ql.blink == b);
9657cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(bs > 0);
9667cc577a4SJonathan Peyton 
9677cc577a4SJonathan Peyton       count += 1;
9687cc577a4SJonathan Peyton 
9693041982dSJonathan Peyton       __kmp_printf_no_lock(
9703041982dSJonathan Peyton           "__kmp_printpool: T#%d Free block: 0x%p size %6ld bytes.\n", gtid, b,
9713041982dSJonathan Peyton           (long)bs);
9727cc577a4SJonathan Peyton #ifdef FreeWipe
9737cc577a4SJonathan Peyton       {
9747cc577a4SJonathan Peyton         char *lerr = ((char *)b) + sizeof(bfhead_t);
9753041982dSJonathan Peyton         if ((bs > sizeof(bfhead_t)) &&
9763041982dSJonathan Peyton             ((*lerr != 0x55) ||
9773041982dSJonathan Peyton              (memcmp(lerr, lerr + 1, (size_t)(bs - (sizeof(bfhead_t) + 1))) !=
9783041982dSJonathan Peyton               0))) {
9793041982dSJonathan Peyton           __kmp_printf_no_lock("__kmp_printpool: T#%d     (Contents of above "
9803041982dSJonathan Peyton                                "free block have been overstored.)\n",
9813041982dSJonathan Peyton                                gtid);
9827cc577a4SJonathan Peyton         }
9837cc577a4SJonathan Peyton       }
9847cc577a4SJonathan Peyton #endif
9857cc577a4SJonathan Peyton     }
9867cc577a4SJonathan Peyton   }
9877cc577a4SJonathan Peyton 
9887cc577a4SJonathan Peyton   if (count == 0)
9897cc577a4SJonathan Peyton     __kmp_printf_no_lock("__kmp_printpool: T#%d No free blocks\n", gtid);
9907cc577a4SJonathan Peyton }
9917cc577a4SJonathan Peyton 
__kmp_initialize_bget(kmp_info_t * th)9923041982dSJonathan Peyton void __kmp_initialize_bget(kmp_info_t *th) {
9937cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(SizeQuant >= sizeof(void *) && (th != 0));
9947cc577a4SJonathan Peyton 
9957cc577a4SJonathan Peyton   set_thr_data(th);
9967cc577a4SJonathan Peyton 
9977cc577a4SJonathan Peyton   bectl(th, (bget_compact_t)0, (bget_acquire_t)malloc, (bget_release_t)free,
9987cc577a4SJonathan Peyton         (bufsize)__kmp_malloc_pool_incr);
9997cc577a4SJonathan Peyton }
10007cc577a4SJonathan Peyton 
__kmp_finalize_bget(kmp_info_t * th)10013041982dSJonathan Peyton void __kmp_finalize_bget(kmp_info_t *th) {
10027cc577a4SJonathan Peyton   thr_data_t *thr;
10037cc577a4SJonathan Peyton   bfhead_t *b;
10047cc577a4SJonathan Peyton 
10057cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(th != 0);
10067cc577a4SJonathan Peyton 
10077cc577a4SJonathan Peyton #if BufStats
10087cc577a4SJonathan Peyton   thr = (thr_data_t *)th->th.th_local.bget_data;
10097cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(thr != NULL);
10107cc577a4SJonathan Peyton   b = thr->last_pool;
10117cc577a4SJonathan Peyton 
10123041982dSJonathan Peyton   /*  If a block-release function is defined, and this free buffer constitutes
10133041982dSJonathan Peyton       the entire block, release it. Note that pool_len is defined in such a way
10143041982dSJonathan Peyton       that the test will fail unless all pool blocks are the same size.  */
10157cc577a4SJonathan Peyton 
10163041982dSJonathan Peyton   // Deallocate the last pool if one exists because we no longer do it in brel()
10177cc577a4SJonathan Peyton   if (thr->relfcn != 0 && b != 0 && thr->numpblk != 0 &&
10183041982dSJonathan Peyton       b->bh.bb.bsize == (bufsize)(thr->pool_len - sizeof(bhead_t))) {
10197cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(b->bh.bb.prevfree == 0);
10207cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.bsize == ESent);
10213041982dSJonathan Peyton     KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.prevfree ==
10223041982dSJonathan Peyton                      b->bh.bb.bsize);
10237cc577a4SJonathan Peyton 
10247cc577a4SJonathan Peyton     /*  Unlink the buffer from the free list  */
10257cc577a4SJonathan Peyton     __kmp_bget_remove_from_freelist(b);
10267cc577a4SJonathan Peyton 
10277cc577a4SJonathan Peyton     KE_TRACE(10, ("%%%%%% FREE( %p )\n", (void *)b));
10287cc577a4SJonathan Peyton 
10297cc577a4SJonathan Peyton     (*thr->relfcn)(b);
10307cc577a4SJonathan Peyton     thr->numprel++; /* Nr of expansion block releases */
10317cc577a4SJonathan Peyton     thr->numpblk--; /* Total number of blocks */
10327cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(thr->numpblk == thr->numpget - thr->numprel);
10337cc577a4SJonathan Peyton   }
10347cc577a4SJonathan Peyton #endif /* BufStats */
10357cc577a4SJonathan Peyton 
10367cc577a4SJonathan Peyton   /* Deallocate bget_data */
10377cc577a4SJonathan Peyton   if (th->th.th_local.bget_data != NULL) {
10387cc577a4SJonathan Peyton     __kmp_free(th->th.th_local.bget_data);
10397cc577a4SJonathan Peyton     th->th.th_local.bget_data = NULL;
1040bd3a7633SJonathan Peyton   }
10417cc577a4SJonathan Peyton }
10427cc577a4SJonathan Peyton 
kmpc_set_poolsize(size_t size)10433041982dSJonathan Peyton void kmpc_set_poolsize(size_t size) {
10447cc577a4SJonathan Peyton   bectl(__kmp_get_thread(), (bget_compact_t)0, (bget_acquire_t)malloc,
10457cc577a4SJonathan Peyton         (bget_release_t)free, (bufsize)size);
10467cc577a4SJonathan Peyton }
10477cc577a4SJonathan Peyton 
kmpc_get_poolsize(void)10483041982dSJonathan Peyton size_t kmpc_get_poolsize(void) {
10497cc577a4SJonathan Peyton   thr_data_t *p;
10507cc577a4SJonathan Peyton 
10517cc577a4SJonathan Peyton   p = get_thr_data(__kmp_get_thread());
10527cc577a4SJonathan Peyton 
10537cc577a4SJonathan Peyton   return p->exp_incr;
10547cc577a4SJonathan Peyton }
10557cc577a4SJonathan Peyton 
kmpc_set_poolmode(int mode)10563041982dSJonathan Peyton void kmpc_set_poolmode(int mode) {
10577cc577a4SJonathan Peyton   thr_data_t *p;
10587cc577a4SJonathan Peyton 
10593041982dSJonathan Peyton   if (mode == bget_mode_fifo || mode == bget_mode_lifo ||
10603041982dSJonathan Peyton       mode == bget_mode_best) {
10617cc577a4SJonathan Peyton     p = get_thr_data(__kmp_get_thread());
10627cc577a4SJonathan Peyton     p->mode = (bget_mode_t)mode;
10637cc577a4SJonathan Peyton   }
10647cc577a4SJonathan Peyton }
10657cc577a4SJonathan Peyton 
kmpc_get_poolmode(void)10663041982dSJonathan Peyton int kmpc_get_poolmode(void) {
10677cc577a4SJonathan Peyton   thr_data_t *p;
10687cc577a4SJonathan Peyton 
10697cc577a4SJonathan Peyton   p = get_thr_data(__kmp_get_thread());
10707cc577a4SJonathan Peyton 
10717cc577a4SJonathan Peyton   return p->mode;
10727cc577a4SJonathan Peyton }
10737cc577a4SJonathan Peyton 
kmpc_get_poolstat(size_t * maxmem,size_t * allmem)10743041982dSJonathan Peyton void kmpc_get_poolstat(size_t *maxmem, size_t *allmem) {
10757cc577a4SJonathan Peyton   kmp_info_t *th = __kmp_get_thread();
10767cc577a4SJonathan Peyton   bufsize a, b;
10777cc577a4SJonathan Peyton 
10787cc577a4SJonathan Peyton   __kmp_bget_dequeue(th); /* Release any queued buffers */
10797cc577a4SJonathan Peyton 
10807cc577a4SJonathan Peyton   bcheck(th, &a, &b);
10817cc577a4SJonathan Peyton 
10827cc577a4SJonathan Peyton   *maxmem = a;
10837cc577a4SJonathan Peyton   *allmem = b;
10847cc577a4SJonathan Peyton }
10857cc577a4SJonathan Peyton 
kmpc_poolprint(void)10863041982dSJonathan Peyton void kmpc_poolprint(void) {
10877cc577a4SJonathan Peyton   kmp_info_t *th = __kmp_get_thread();
10887cc577a4SJonathan Peyton 
10897cc577a4SJonathan Peyton   __kmp_bget_dequeue(th); /* Release any queued buffers */
10907cc577a4SJonathan Peyton 
10917cc577a4SJonathan Peyton   bfreed(th);
10927cc577a4SJonathan Peyton }
10937cc577a4SJonathan Peyton 
10947cc577a4SJonathan Peyton #endif // #if KMP_USE_BGET
10957cc577a4SJonathan Peyton 
kmpc_malloc(size_t size)10963041982dSJonathan Peyton void *kmpc_malloc(size_t size) {
10977cc577a4SJonathan Peyton   void *ptr;
10987cc577a4SJonathan Peyton   ptr = bget(__kmp_entry_thread(), (bufsize)(size + sizeof(ptr)));
10997cc577a4SJonathan Peyton   if (ptr != NULL) {
11007cc577a4SJonathan Peyton     // save allocated pointer just before one returned to user
11017cc577a4SJonathan Peyton     *(void **)ptr = ptr;
11027cc577a4SJonathan Peyton     ptr = (void **)ptr + 1;
11037cc577a4SJonathan Peyton   }
11047cc577a4SJonathan Peyton   return ptr;
11057cc577a4SJonathan Peyton }
11067cc577a4SJonathan Peyton 
11077cc577a4SJonathan Peyton #define IS_POWER_OF_TWO(n) (((n) & ((n)-1)) == 0)
11087cc577a4SJonathan Peyton 
kmpc_aligned_malloc(size_t size,size_t alignment)11093041982dSJonathan Peyton void *kmpc_aligned_malloc(size_t size, size_t alignment) {
11107cc577a4SJonathan Peyton   void *ptr;
11117cc577a4SJonathan Peyton   void *ptr_allocated;
11127cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(alignment < 32 * 1024); // Alignment should not be too big
11137cc577a4SJonathan Peyton   if (!IS_POWER_OF_TWO(alignment)) {
11147cc577a4SJonathan Peyton     // AC: do we need to issue a warning here?
11157cc577a4SJonathan Peyton     errno = EINVAL;
11167cc577a4SJonathan Peyton     return NULL;
11177cc577a4SJonathan Peyton   }
11187cc577a4SJonathan Peyton   size = size + sizeof(void *) + alignment;
11197cc577a4SJonathan Peyton   ptr_allocated = bget(__kmp_entry_thread(), (bufsize)size);
11207cc577a4SJonathan Peyton   if (ptr_allocated != NULL) {
11217cc577a4SJonathan Peyton     // save allocated pointer just before one returned to user
11223041982dSJonathan Peyton     ptr = (void *)(((kmp_uintptr_t)ptr_allocated + sizeof(void *) + alignment) &
11233041982dSJonathan Peyton                    ~(alignment - 1));
11247cc577a4SJonathan Peyton     *((void **)ptr - 1) = ptr_allocated;
11257cc577a4SJonathan Peyton   } else {
11267cc577a4SJonathan Peyton     ptr = NULL;
11277cc577a4SJonathan Peyton   }
11287cc577a4SJonathan Peyton   return ptr;
11297cc577a4SJonathan Peyton }
11307cc577a4SJonathan Peyton 
kmpc_calloc(size_t nelem,size_t elsize)11313041982dSJonathan Peyton void *kmpc_calloc(size_t nelem, size_t elsize) {
11327cc577a4SJonathan Peyton   void *ptr;
11337cc577a4SJonathan Peyton   ptr = bgetz(__kmp_entry_thread(), (bufsize)(nelem * elsize + sizeof(ptr)));
11347cc577a4SJonathan Peyton   if (ptr != NULL) {
11357cc577a4SJonathan Peyton     // save allocated pointer just before one returned to user
11367cc577a4SJonathan Peyton     *(void **)ptr = ptr;
11377cc577a4SJonathan Peyton     ptr = (void **)ptr + 1;
11387cc577a4SJonathan Peyton   }
11397cc577a4SJonathan Peyton   return ptr;
11407cc577a4SJonathan Peyton }
11417cc577a4SJonathan Peyton 
kmpc_realloc(void * ptr,size_t size)11423041982dSJonathan Peyton void *kmpc_realloc(void *ptr, size_t size) {
11437cc577a4SJonathan Peyton   void *result = NULL;
11447cc577a4SJonathan Peyton   if (ptr == NULL) {
11457cc577a4SJonathan Peyton     // If pointer is NULL, realloc behaves like malloc.
11467cc577a4SJonathan Peyton     result = bget(__kmp_entry_thread(), (bufsize)(size + sizeof(ptr)));
11477cc577a4SJonathan Peyton     // save allocated pointer just before one returned to user
11487cc577a4SJonathan Peyton     if (result != NULL) {
11497cc577a4SJonathan Peyton       *(void **)result = result;
11507cc577a4SJonathan Peyton       result = (void **)result + 1;
11517cc577a4SJonathan Peyton     }
11527cc577a4SJonathan Peyton   } else if (size == 0) {
11537cc577a4SJonathan Peyton     // If size is 0, realloc behaves like free.
11543041982dSJonathan Peyton     // The thread must be registered by the call to kmpc_malloc() or
11553041982dSJonathan Peyton     // kmpc_calloc() before.
11563041982dSJonathan Peyton     // So it should be safe to call __kmp_get_thread(), not
11573041982dSJonathan Peyton     // __kmp_entry_thread().
11587cc577a4SJonathan Peyton     KMP_ASSERT(*((void **)ptr - 1));
11597cc577a4SJonathan Peyton     brel(__kmp_get_thread(), *((void **)ptr - 1));
11607cc577a4SJonathan Peyton   } else {
11613041982dSJonathan Peyton     result = bgetr(__kmp_entry_thread(), *((void **)ptr - 1),
11623041982dSJonathan Peyton                    (bufsize)(size + sizeof(ptr)));
11637cc577a4SJonathan Peyton     if (result != NULL) {
11647cc577a4SJonathan Peyton       *(void **)result = result;
11657cc577a4SJonathan Peyton       result = (void **)result + 1;
11667cc577a4SJonathan Peyton     }
1167bd3a7633SJonathan Peyton   }
11687cc577a4SJonathan Peyton   return result;
11697cc577a4SJonathan Peyton }
11707cc577a4SJonathan Peyton 
11713041982dSJonathan Peyton // NOTE: the library must have already been initialized by a previous allocate
kmpc_free(void * ptr)11723041982dSJonathan Peyton void kmpc_free(void *ptr) {
11737cc577a4SJonathan Peyton   if (!__kmp_init_serial) {
11747cc577a4SJonathan Peyton     return;
1175bd3a7633SJonathan Peyton   }
11767cc577a4SJonathan Peyton   if (ptr != NULL) {
11777cc577a4SJonathan Peyton     kmp_info_t *th = __kmp_get_thread();
11787cc577a4SJonathan Peyton     __kmp_bget_dequeue(th); /* Release any queued buffers */
11797cc577a4SJonathan Peyton     // extract allocated pointer and free it
11807cc577a4SJonathan Peyton     KMP_ASSERT(*((void **)ptr - 1));
11817cc577a4SJonathan Peyton     brel(th, *((void **)ptr - 1));
1182bd3a7633SJonathan Peyton   }
11837cc577a4SJonathan Peyton }
11847cc577a4SJonathan Peyton 
___kmp_thread_malloc(kmp_info_t * th,size_t size KMP_SRC_LOC_DECL)11853041982dSJonathan Peyton void *___kmp_thread_malloc(kmp_info_t *th, size_t size KMP_SRC_LOC_DECL) {
11867cc577a4SJonathan Peyton   void *ptr;
11873041982dSJonathan Peyton   KE_TRACE(30, ("-> __kmp_thread_malloc( %p, %d ) called from %s:%d\n", th,
11883041982dSJonathan Peyton                 (int)size KMP_SRC_LOC_PARM));
11897cc577a4SJonathan Peyton   ptr = bget(th, (bufsize)size);
11907cc577a4SJonathan Peyton   KE_TRACE(30, ("<- __kmp_thread_malloc() returns %p\n", ptr));
11917cc577a4SJonathan Peyton   return ptr;
11927cc577a4SJonathan Peyton }
11937cc577a4SJonathan Peyton 
___kmp_thread_calloc(kmp_info_t * th,size_t nelem,size_t elsize KMP_SRC_LOC_DECL)11943041982dSJonathan Peyton void *___kmp_thread_calloc(kmp_info_t *th, size_t nelem,
11953041982dSJonathan Peyton                            size_t elsize KMP_SRC_LOC_DECL) {
11967cc577a4SJonathan Peyton   void *ptr;
11973041982dSJonathan Peyton   KE_TRACE(30, ("-> __kmp_thread_calloc( %p, %d, %d ) called from %s:%d\n", th,
11983041982dSJonathan Peyton                 (int)nelem, (int)elsize KMP_SRC_LOC_PARM));
11997cc577a4SJonathan Peyton   ptr = bgetz(th, (bufsize)(nelem * elsize));
12007cc577a4SJonathan Peyton   KE_TRACE(30, ("<- __kmp_thread_calloc() returns %p\n", ptr));
12017cc577a4SJonathan Peyton   return ptr;
12027cc577a4SJonathan Peyton }
12037cc577a4SJonathan Peyton 
___kmp_thread_realloc(kmp_info_t * th,void * ptr,size_t size KMP_SRC_LOC_DECL)12043041982dSJonathan Peyton void *___kmp_thread_realloc(kmp_info_t *th, void *ptr,
12053041982dSJonathan Peyton                             size_t size KMP_SRC_LOC_DECL) {
12063041982dSJonathan Peyton   KE_TRACE(30, ("-> __kmp_thread_realloc( %p, %p, %d ) called from %s:%d\n", th,
12073041982dSJonathan Peyton                 ptr, (int)size KMP_SRC_LOC_PARM));
12087cc577a4SJonathan Peyton   ptr = bgetr(th, ptr, (bufsize)size);
12097cc577a4SJonathan Peyton   KE_TRACE(30, ("<- __kmp_thread_realloc() returns %p\n", ptr));
12107cc577a4SJonathan Peyton   return ptr;
12117cc577a4SJonathan Peyton }
12127cc577a4SJonathan Peyton 
___kmp_thread_free(kmp_info_t * th,void * ptr KMP_SRC_LOC_DECL)12133041982dSJonathan Peyton void ___kmp_thread_free(kmp_info_t *th, void *ptr KMP_SRC_LOC_DECL) {
12143041982dSJonathan Peyton   KE_TRACE(30, ("-> __kmp_thread_free( %p, %p ) called from %s:%d\n", th,
12153041982dSJonathan Peyton                 ptr KMP_SRC_LOC_PARM));
12167cc577a4SJonathan Peyton   if (ptr != NULL) {
12177cc577a4SJonathan Peyton     __kmp_bget_dequeue(th); /* Release any queued buffers */
12187cc577a4SJonathan Peyton     brel(th, ptr);
12197cc577a4SJonathan Peyton   }
12207cc577a4SJonathan Peyton   KE_TRACE(30, ("<- __kmp_thread_free()\n"));
12217cc577a4SJonathan Peyton }
12227cc577a4SJonathan Peyton 
122392ca6188SJonathan Peyton /* OMP 5.0 Memory Management support */
122492ca6188SJonathan Peyton static const char *kmp_mk_lib_name;
122592ca6188SJonathan Peyton static void *h_memkind;
1226ebf1830bSJonathan Peyton /* memkind experimental API: */
1227ebf1830bSJonathan Peyton // memkind_alloc
1228ebf1830bSJonathan Peyton static void *(*kmp_mk_alloc)(void *k, size_t sz);
1229ebf1830bSJonathan Peyton // memkind_free
1230ebf1830bSJonathan Peyton static void (*kmp_mk_free)(void *kind, void *ptr);
1231ebf1830bSJonathan Peyton // memkind_check_available
1232ebf1830bSJonathan Peyton static int (*kmp_mk_check)(void *kind);
1233ebf1830bSJonathan Peyton // kinds we are going to use
1234ebf1830bSJonathan Peyton static void **mk_default;
1235ebf1830bSJonathan Peyton static void **mk_interleave;
1236ebf1830bSJonathan Peyton static void **mk_hbw;
1237ebf1830bSJonathan Peyton static void **mk_hbw_interleave;
1238ebf1830bSJonathan Peyton static void **mk_hbw_preferred;
1239ebf1830bSJonathan Peyton static void **mk_hugetlb;
1240ebf1830bSJonathan Peyton static void **mk_hbw_hugetlb;
1241ebf1830bSJonathan Peyton static void **mk_hbw_preferred_hugetlb;
1242bba3a82bSHansang Bae static void **mk_dax_kmem;
1243bba3a82bSHansang Bae static void **mk_dax_kmem_all;
1244bba3a82bSHansang Bae static void **mk_dax_kmem_preferred;
1245b6c2f538SHansang Bae static void *(*kmp_target_alloc_host)(size_t size, int device);
1246b6c2f538SHansang Bae static void *(*kmp_target_alloc_shared)(size_t size, int device);
1247b6c2f538SHansang Bae static void *(*kmp_target_alloc_device)(size_t size, int device);
1248d6281caaSCarlo Bertolli static void *(*kmp_target_lock_mem)(void *ptr, size_t size, int device);
1249d6281caaSCarlo Bertolli static void *(*kmp_target_unlock_mem)(void *ptr, int device);
125023bc3438SJoseph Huber static void *(*kmp_target_free_host)(void *ptr, int device);
125123bc3438SJoseph Huber static void *(*kmp_target_free_shared)(void *ptr, int device);
125223bc3438SJoseph Huber static void *(*kmp_target_free_device)(void *ptr, int device);
1253b6c2f538SHansang Bae static bool __kmp_target_mem_available;
1254b6c2f538SHansang Bae #define KMP_IS_TARGET_MEM_SPACE(MS)                                            \
1255b6c2f538SHansang Bae   (MS == llvm_omp_target_host_mem_space ||                                     \
1256b6c2f538SHansang Bae    MS == llvm_omp_target_shared_mem_space ||                                   \
1257b6c2f538SHansang Bae    MS == llvm_omp_target_device_mem_space)
1258b6c2f538SHansang Bae #define KMP_IS_TARGET_MEM_ALLOC(MA)                                            \
1259b6c2f538SHansang Bae   (MA == llvm_omp_target_host_mem_alloc ||                                     \
1260b6c2f538SHansang Bae    MA == llvm_omp_target_shared_mem_alloc ||                                   \
1261b6c2f538SHansang Bae    MA == llvm_omp_target_device_mem_alloc)
1262ebf1830bSJonathan Peyton 
12635d25dbffSDaniel Douglas #if KMP_OS_UNIX && KMP_DYNAMIC_LIB && !KMP_OS_DARWIN
chk_kind(void *** pkind)1264ebf1830bSJonathan Peyton static inline void chk_kind(void ***pkind) {
1265ebf1830bSJonathan Peyton   KMP_DEBUG_ASSERT(pkind);
1266ebf1830bSJonathan Peyton   if (*pkind) // symbol found
1267ebf1830bSJonathan Peyton     if (kmp_mk_check(**pkind)) // kind not available or error
1268ebf1830bSJonathan Peyton       *pkind = NULL;
1269ebf1830bSJonathan Peyton }
1270ebf1830bSJonathan Peyton #endif
127192ca6188SJonathan Peyton 
__kmp_init_memkind()127292ca6188SJonathan Peyton void __kmp_init_memkind() {
1273ebf1830bSJonathan Peyton // as of 2018-07-31 memkind does not support Windows*, exclude it for now
12745d25dbffSDaniel Douglas #if KMP_OS_UNIX && KMP_DYNAMIC_LIB && !KMP_OS_DARWIN
1275ebf1830bSJonathan Peyton   // use of statically linked memkind is problematic, as it depends on libnuma
127692ca6188SJonathan Peyton   kmp_mk_lib_name = "libmemkind.so";
127792ca6188SJonathan Peyton   h_memkind = dlopen(kmp_mk_lib_name, RTLD_LAZY);
127892ca6188SJonathan Peyton   if (h_memkind) {
1279ebf1830bSJonathan Peyton     kmp_mk_check = (int (*)(void *))dlsym(h_memkind, "memkind_check_available");
1280ebf1830bSJonathan Peyton     kmp_mk_alloc =
1281ebf1830bSJonathan Peyton         (void *(*)(void *, size_t))dlsym(h_memkind, "memkind_malloc");
1282ebf1830bSJonathan Peyton     kmp_mk_free = (void (*)(void *, void *))dlsym(h_memkind, "memkind_free");
1283ebf1830bSJonathan Peyton     mk_default = (void **)dlsym(h_memkind, "MEMKIND_DEFAULT");
1284ebf1830bSJonathan Peyton     if (kmp_mk_check && kmp_mk_alloc && kmp_mk_free && mk_default &&
1285ebf1830bSJonathan Peyton         !kmp_mk_check(*mk_default)) {
128692ca6188SJonathan Peyton       __kmp_memkind_available = 1;
1287ebf1830bSJonathan Peyton       mk_interleave = (void **)dlsym(h_memkind, "MEMKIND_INTERLEAVE");
1288ebf1830bSJonathan Peyton       chk_kind(&mk_interleave);
1289ebf1830bSJonathan Peyton       mk_hbw = (void **)dlsym(h_memkind, "MEMKIND_HBW");
1290ebf1830bSJonathan Peyton       chk_kind(&mk_hbw);
1291ebf1830bSJonathan Peyton       mk_hbw_interleave = (void **)dlsym(h_memkind, "MEMKIND_HBW_INTERLEAVE");
1292ebf1830bSJonathan Peyton       chk_kind(&mk_hbw_interleave);
1293ebf1830bSJonathan Peyton       mk_hbw_preferred = (void **)dlsym(h_memkind, "MEMKIND_HBW_PREFERRED");
1294ebf1830bSJonathan Peyton       chk_kind(&mk_hbw_preferred);
1295ebf1830bSJonathan Peyton       mk_hugetlb = (void **)dlsym(h_memkind, "MEMKIND_HUGETLB");
1296ebf1830bSJonathan Peyton       chk_kind(&mk_hugetlb);
1297ebf1830bSJonathan Peyton       mk_hbw_hugetlb = (void **)dlsym(h_memkind, "MEMKIND_HBW_HUGETLB");
1298ebf1830bSJonathan Peyton       chk_kind(&mk_hbw_hugetlb);
1299ebf1830bSJonathan Peyton       mk_hbw_preferred_hugetlb =
1300ebf1830bSJonathan Peyton           (void **)dlsym(h_memkind, "MEMKIND_HBW_PREFERRED_HUGETLB");
1301ebf1830bSJonathan Peyton       chk_kind(&mk_hbw_preferred_hugetlb);
1302bba3a82bSHansang Bae       mk_dax_kmem = (void **)dlsym(h_memkind, "MEMKIND_DAX_KMEM");
1303bba3a82bSHansang Bae       chk_kind(&mk_dax_kmem);
1304bba3a82bSHansang Bae       mk_dax_kmem_all = (void **)dlsym(h_memkind, "MEMKIND_DAX_KMEM_ALL");
1305bba3a82bSHansang Bae       chk_kind(&mk_dax_kmem_all);
1306bba3a82bSHansang Bae       mk_dax_kmem_preferred =
1307bba3a82bSHansang Bae           (void **)dlsym(h_memkind, "MEMKIND_DAX_KMEM_PREFERRED");
1308bba3a82bSHansang Bae       chk_kind(&mk_dax_kmem_preferred);
1309ebf1830bSJonathan Peyton       KE_TRACE(25, ("__kmp_init_memkind: memkind library initialized\n"));
1310ebf1830bSJonathan Peyton       return; // success
131192ca6188SJonathan Peyton     }
131292ca6188SJonathan Peyton     dlclose(h_memkind); // failure
131392ca6188SJonathan Peyton   }
1314bba3a82bSHansang Bae #else // !(KMP_OS_UNIX && KMP_DYNAMIC_LIB)
131592ca6188SJonathan Peyton   kmp_mk_lib_name = "";
1316bba3a82bSHansang Bae #endif // !(KMP_OS_UNIX && KMP_DYNAMIC_LIB)
131792ca6188SJonathan Peyton   h_memkind = NULL;
1318ebf1830bSJonathan Peyton   kmp_mk_check = NULL;
1319ebf1830bSJonathan Peyton   kmp_mk_alloc = NULL;
1320ebf1830bSJonathan Peyton   kmp_mk_free = NULL;
1321ebf1830bSJonathan Peyton   mk_default = NULL;
1322ebf1830bSJonathan Peyton   mk_interleave = NULL;
1323ebf1830bSJonathan Peyton   mk_hbw = NULL;
1324ebf1830bSJonathan Peyton   mk_hbw_interleave = NULL;
1325ebf1830bSJonathan Peyton   mk_hbw_preferred = NULL;
1326ebf1830bSJonathan Peyton   mk_hugetlb = NULL;
1327ebf1830bSJonathan Peyton   mk_hbw_hugetlb = NULL;
1328ebf1830bSJonathan Peyton   mk_hbw_preferred_hugetlb = NULL;
1329bba3a82bSHansang Bae   mk_dax_kmem = NULL;
1330bba3a82bSHansang Bae   mk_dax_kmem_all = NULL;
1331bba3a82bSHansang Bae   mk_dax_kmem_preferred = NULL;
133292ca6188SJonathan Peyton }
133392ca6188SJonathan Peyton 
__kmp_fini_memkind()133492ca6188SJonathan Peyton void __kmp_fini_memkind() {
133592ca6188SJonathan Peyton #if KMP_OS_UNIX && KMP_DYNAMIC_LIB
1336ebf1830bSJonathan Peyton   if (__kmp_memkind_available)
1337ebf1830bSJonathan Peyton     KE_TRACE(25, ("__kmp_fini_memkind: finalize memkind library\n"));
133892ca6188SJonathan Peyton   if (h_memkind) {
133992ca6188SJonathan Peyton     dlclose(h_memkind);
134092ca6188SJonathan Peyton     h_memkind = NULL;
134192ca6188SJonathan Peyton   }
1342ebf1830bSJonathan Peyton   kmp_mk_check = NULL;
1343ebf1830bSJonathan Peyton   kmp_mk_alloc = NULL;
1344ebf1830bSJonathan Peyton   kmp_mk_free = NULL;
1345ebf1830bSJonathan Peyton   mk_default = NULL;
1346ebf1830bSJonathan Peyton   mk_interleave = NULL;
1347ebf1830bSJonathan Peyton   mk_hbw = NULL;
1348ebf1830bSJonathan Peyton   mk_hbw_interleave = NULL;
1349ebf1830bSJonathan Peyton   mk_hbw_preferred = NULL;
1350ebf1830bSJonathan Peyton   mk_hugetlb = NULL;
1351ebf1830bSJonathan Peyton   mk_hbw_hugetlb = NULL;
1352ebf1830bSJonathan Peyton   mk_hbw_preferred_hugetlb = NULL;
1353bba3a82bSHansang Bae   mk_dax_kmem = NULL;
1354bba3a82bSHansang Bae   mk_dax_kmem_all = NULL;
1355bba3a82bSHansang Bae   mk_dax_kmem_preferred = NULL;
135692ca6188SJonathan Peyton #endif
135792ca6188SJonathan Peyton }
1358840c0404SJoseph Huber 
__kmp_init_target_mem()1359b6c2f538SHansang Bae void __kmp_init_target_mem() {
1360b6c2f538SHansang Bae   *(void **)(&kmp_target_alloc_host) = KMP_DLSYM("llvm_omp_target_alloc_host");
1361b6c2f538SHansang Bae   *(void **)(&kmp_target_alloc_shared) =
1362b6c2f538SHansang Bae       KMP_DLSYM("llvm_omp_target_alloc_shared");
1363b6c2f538SHansang Bae   *(void **)(&kmp_target_alloc_device) =
1364b6c2f538SHansang Bae       KMP_DLSYM("llvm_omp_target_alloc_device");
136523bc3438SJoseph Huber   *(void **)(&kmp_target_free_host) = KMP_DLSYM("llvm_omp_target_free_host");
136623bc3438SJoseph Huber   *(void **)(&kmp_target_free_shared) =
136723bc3438SJoseph Huber       KMP_DLSYM("llvm_omp_target_free_shared");
136823bc3438SJoseph Huber   *(void **)(&kmp_target_free_device) =
136923bc3438SJoseph Huber       KMP_DLSYM("llvm_omp_target_free_device");
137023bc3438SJoseph Huber   __kmp_target_mem_available =
137123bc3438SJoseph Huber       kmp_target_alloc_host && kmp_target_alloc_shared &&
137223bc3438SJoseph Huber       kmp_target_alloc_device && kmp_target_free_host &&
137323bc3438SJoseph Huber       kmp_target_free_shared && kmp_target_free_device;
1374b215932eSCarlo Bertolli   // lock/pin and unlock/unpin target calls
1375b215932eSCarlo Bertolli   *(void **)(&kmp_target_lock_mem) = KMP_DLSYM("llvm_omp_target_lock_mem");
1376b215932eSCarlo Bertolli   *(void **)(&kmp_target_unlock_mem) = KMP_DLSYM("llvm_omp_target_unlock_mem");
1377b6c2f538SHansang Bae }
137892ca6188SJonathan Peyton 
__kmpc_init_allocator(int gtid,omp_memspace_handle_t ms,int ntraits,omp_alloctrait_t traits[])1379ebf1830bSJonathan Peyton omp_allocator_handle_t __kmpc_init_allocator(int gtid, omp_memspace_handle_t ms,
1380ebf1830bSJonathan Peyton                                              int ntraits,
1381ebf1830bSJonathan Peyton                                              omp_alloctrait_t traits[]) {
1382ebf1830bSJonathan Peyton   // OpenMP 5.0 only allows predefined memspaces
1383ebf1830bSJonathan Peyton   KMP_DEBUG_ASSERT(ms == omp_default_mem_space || ms == omp_low_lat_mem_space ||
1384ebf1830bSJonathan Peyton                    ms == omp_large_cap_mem_space || ms == omp_const_mem_space ||
1385b6c2f538SHansang Bae                    ms == omp_high_bw_mem_space || KMP_IS_TARGET_MEM_SPACE(ms));
1386ebf1830bSJonathan Peyton   kmp_allocator_t *al;
1387ebf1830bSJonathan Peyton   int i;
1388ebf1830bSJonathan Peyton   al = (kmp_allocator_t *)__kmp_allocate(sizeof(kmp_allocator_t)); // zeroed
1389ebf1830bSJonathan Peyton   al->memspace = ms; // not used currently
1390ebf1830bSJonathan Peyton   for (i = 0; i < ntraits; ++i) {
1391ebf1830bSJonathan Peyton     switch (traits[i].key) {
13926f0f0220SHansang Bae     case omp_atk_sync_hint:
1393ad24cf2aSKelvin Li     case omp_atk_access:
1394d6281caaSCarlo Bertolli       break;
1395ad24cf2aSKelvin Li     case omp_atk_pinned:
1396d6281caaSCarlo Bertolli       al->pinned = true;
1397ebf1830bSJonathan Peyton       break;
1398ad24cf2aSKelvin Li     case omp_atk_alignment:
13996b316febSTerry Wilmarth       __kmp_type_convert(traits[i].value, &(al->alignment));
1400ebf1830bSJonathan Peyton       KMP_ASSERT(IS_POWER_OF_TWO(al->alignment));
1401ebf1830bSJonathan Peyton       break;
1402ad24cf2aSKelvin Li     case omp_atk_pool_size:
1403ebf1830bSJonathan Peyton       al->pool_size = traits[i].value;
1404ebf1830bSJonathan Peyton       break;
1405ad24cf2aSKelvin Li     case omp_atk_fallback:
1406ebf1830bSJonathan Peyton       al->fb = (omp_alloctrait_value_t)traits[i].value;
140792ca6188SJonathan Peyton       KMP_DEBUG_ASSERT(
1408ad24cf2aSKelvin Li           al->fb == omp_atv_default_mem_fb || al->fb == omp_atv_null_fb ||
1409ad24cf2aSKelvin Li           al->fb == omp_atv_abort_fb || al->fb == omp_atv_allocator_fb);
1410ebf1830bSJonathan Peyton       break;
1411ad24cf2aSKelvin Li     case omp_atk_fb_data:
1412ebf1830bSJonathan Peyton       al->fb_data = RCAST(kmp_allocator_t *, traits[i].value);
1413ebf1830bSJonathan Peyton       break;
1414ad24cf2aSKelvin Li     case omp_atk_partition:
1415ebf1830bSJonathan Peyton       al->memkind = RCAST(void **, traits[i].value);
1416ebf1830bSJonathan Peyton       break;
1417ebf1830bSJonathan Peyton     default:
1418ebf1830bSJonathan Peyton       KMP_ASSERT2(0, "Unexpected allocator trait");
1419ebf1830bSJonathan Peyton     }
1420ebf1830bSJonathan Peyton   }
1421ebf1830bSJonathan Peyton   if (al->fb == 0) {
1422ebf1830bSJonathan Peyton     // set default allocator
1423ad24cf2aSKelvin Li     al->fb = omp_atv_default_mem_fb;
1424ebf1830bSJonathan Peyton     al->fb_data = (kmp_allocator_t *)omp_default_mem_alloc;
1425ad24cf2aSKelvin Li   } else if (al->fb == omp_atv_allocator_fb) {
1426ebf1830bSJonathan Peyton     KMP_ASSERT(al->fb_data != NULL);
1427ad24cf2aSKelvin Li   } else if (al->fb == omp_atv_default_mem_fb) {
1428ebf1830bSJonathan Peyton     al->fb_data = (kmp_allocator_t *)omp_default_mem_alloc;
1429ebf1830bSJonathan Peyton   }
1430ebf1830bSJonathan Peyton   if (__kmp_memkind_available) {
1431ebf1830bSJonathan Peyton     // Let's use memkind library if available
1432ebf1830bSJonathan Peyton     if (ms == omp_high_bw_mem_space) {
1433ad24cf2aSKelvin Li       if (al->memkind == (void *)omp_atv_interleaved && mk_hbw_interleave) {
1434ebf1830bSJonathan Peyton         al->memkind = mk_hbw_interleave;
1435ebf1830bSJonathan Peyton       } else if (mk_hbw_preferred) {
1436ebf1830bSJonathan Peyton         // AC: do not try to use MEMKIND_HBW for now, because memkind library
1437ebf1830bSJonathan Peyton         // cannot reliably detect exhaustion of HBW memory.
1438ebf1830bSJonathan Peyton         // It could be possible using hbw_verify_memory_region() but memkind
1439ebf1830bSJonathan Peyton         // manual says: "Using this function in production code may result in
1440ebf1830bSJonathan Peyton         // serious performance penalty".
1441ebf1830bSJonathan Peyton         al->memkind = mk_hbw_preferred;
1442ebf1830bSJonathan Peyton       } else {
1443ebf1830bSJonathan Peyton         // HBW is requested but not available --> return NULL allocator
1444ebf1830bSJonathan Peyton         __kmp_free(al);
1445ebf1830bSJonathan Peyton         return omp_null_allocator;
1446ebf1830bSJonathan Peyton       }
1447bba3a82bSHansang Bae     } else if (ms == omp_large_cap_mem_space) {
1448bba3a82bSHansang Bae       if (mk_dax_kmem_all) {
1449bba3a82bSHansang Bae         // All pmem nodes are visited
1450bba3a82bSHansang Bae         al->memkind = mk_dax_kmem_all;
1451bba3a82bSHansang Bae       } else if (mk_dax_kmem) {
1452bba3a82bSHansang Bae         // Only closest pmem node is visited
1453bba3a82bSHansang Bae         al->memkind = mk_dax_kmem;
1454bba3a82bSHansang Bae       } else {
1455bba3a82bSHansang Bae         __kmp_free(al);
1456bba3a82bSHansang Bae         return omp_null_allocator;
1457bba3a82bSHansang Bae       }
1458ebf1830bSJonathan Peyton     } else {
1459ad24cf2aSKelvin Li       if (al->memkind == (void *)omp_atv_interleaved && mk_interleave) {
1460ebf1830bSJonathan Peyton         al->memkind = mk_interleave;
1461ebf1830bSJonathan Peyton       } else {
1462ebf1830bSJonathan Peyton         al->memkind = mk_default;
1463ebf1830bSJonathan Peyton       }
1464ebf1830bSJonathan Peyton     }
1465b6c2f538SHansang Bae   } else if (KMP_IS_TARGET_MEM_SPACE(ms) && !__kmp_target_mem_available) {
1466b6c2f538SHansang Bae     __kmp_free(al);
1467b6c2f538SHansang Bae     return omp_null_allocator;
1468ebf1830bSJonathan Peyton   } else {
1469ebf1830bSJonathan Peyton     if (ms == omp_high_bw_mem_space) {
1470ebf1830bSJonathan Peyton       // cannot detect HBW memory presence without memkind library
1471ebf1830bSJonathan Peyton       __kmp_free(al);
1472ebf1830bSJonathan Peyton       return omp_null_allocator;
1473ebf1830bSJonathan Peyton     }
1474ebf1830bSJonathan Peyton   }
1475ebf1830bSJonathan Peyton   return (omp_allocator_handle_t)al;
1476ebf1830bSJonathan Peyton }
1477ebf1830bSJonathan Peyton 
__kmpc_destroy_allocator(int gtid,omp_allocator_handle_t allocator)1478ebf1830bSJonathan Peyton void __kmpc_destroy_allocator(int gtid, omp_allocator_handle_t allocator) {
1479ebf1830bSJonathan Peyton   if (allocator > kmp_max_mem_alloc)
1480ebf1830bSJonathan Peyton     __kmp_free(allocator);
1481ebf1830bSJonathan Peyton }
1482ebf1830bSJonathan Peyton 
__kmpc_set_default_allocator(int gtid,omp_allocator_handle_t allocator)1483ebf1830bSJonathan Peyton void __kmpc_set_default_allocator(int gtid, omp_allocator_handle_t allocator) {
1484ebf1830bSJonathan Peyton   if (allocator == omp_null_allocator)
1485ebf1830bSJonathan Peyton     allocator = omp_default_mem_alloc;
148692ca6188SJonathan Peyton   __kmp_threads[gtid]->th.th_def_allocator = allocator;
148792ca6188SJonathan Peyton }
1488ebf1830bSJonathan Peyton 
__kmpc_get_default_allocator(int gtid)1489ebf1830bSJonathan Peyton omp_allocator_handle_t __kmpc_get_default_allocator(int gtid) {
149092ca6188SJonathan Peyton   return __kmp_threads[gtid]->th.th_def_allocator;
149192ca6188SJonathan Peyton }
149292ca6188SJonathan Peyton 
149392ca6188SJonathan Peyton typedef struct kmp_mem_desc { // Memory block descriptor
149492ca6188SJonathan Peyton   void *ptr_alloc; // Pointer returned by allocator
149592ca6188SJonathan Peyton   size_t size_a; // Size of allocated memory block (initial+descriptor+align)
14965439db05SNawrin Sultana   size_t size_orig; // Original size requested
149792ca6188SJonathan Peyton   void *ptr_align; // Pointer to aligned memory, returned
1498ebf1830bSJonathan Peyton   kmp_allocator_t *allocator; // allocator
149992ca6188SJonathan Peyton } kmp_mem_desc_t;
1500f5c0c917SAndreyChurbanov static int alignment = sizeof(void *); // align to pointer size by default
150192ca6188SJonathan Peyton 
1502f5c0c917SAndreyChurbanov // external interfaces are wrappers over internal implementation
__kmpc_alloc(int gtid,size_t size,omp_allocator_handle_t allocator)1503ebf1830bSJonathan Peyton void *__kmpc_alloc(int gtid, size_t size, omp_allocator_handle_t allocator) {
1504f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_alloc: T#%d (%d, %p)\n", gtid, (int)size, allocator));
1505f5c0c917SAndreyChurbanov   void *ptr = __kmp_alloc(gtid, 0, size, allocator);
1506f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_alloc returns %p, T#%d\n", ptr, gtid));
1507f5c0c917SAndreyChurbanov   return ptr;
1508f5c0c917SAndreyChurbanov }
1509f5c0c917SAndreyChurbanov 
__kmpc_aligned_alloc(int gtid,size_t algn,size_t size,omp_allocator_handle_t allocator)1510f5c0c917SAndreyChurbanov void *__kmpc_aligned_alloc(int gtid, size_t algn, size_t size,
1511f5c0c917SAndreyChurbanov                            omp_allocator_handle_t allocator) {
1512f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_aligned_alloc: T#%d (%d, %d, %p)\n", gtid, (int)algn,
1513f5c0c917SAndreyChurbanov                 (int)size, allocator));
1514f5c0c917SAndreyChurbanov   void *ptr = __kmp_alloc(gtid, algn, size, allocator);
1515f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_aligned_alloc returns %p, T#%d\n", ptr, gtid));
1516f5c0c917SAndreyChurbanov   return ptr;
1517f5c0c917SAndreyChurbanov }
1518f5c0c917SAndreyChurbanov 
__kmpc_calloc(int gtid,size_t nmemb,size_t size,omp_allocator_handle_t allocator)1519f5c0c917SAndreyChurbanov void *__kmpc_calloc(int gtid, size_t nmemb, size_t size,
1520f5c0c917SAndreyChurbanov                     omp_allocator_handle_t allocator) {
1521f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_calloc: T#%d (%d, %d, %p)\n", gtid, (int)nmemb,
1522f5c0c917SAndreyChurbanov                 (int)size, allocator));
1523f5c0c917SAndreyChurbanov   void *ptr = __kmp_calloc(gtid, 0, nmemb, size, allocator);
1524f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_calloc returns %p, T#%d\n", ptr, gtid));
1525f5c0c917SAndreyChurbanov   return ptr;
1526f5c0c917SAndreyChurbanov }
1527f5c0c917SAndreyChurbanov 
__kmpc_realloc(int gtid,void * ptr,size_t size,omp_allocator_handle_t allocator,omp_allocator_handle_t free_allocator)1528f5c0c917SAndreyChurbanov void *__kmpc_realloc(int gtid, void *ptr, size_t size,
1529f5c0c917SAndreyChurbanov                      omp_allocator_handle_t allocator,
1530f5c0c917SAndreyChurbanov                      omp_allocator_handle_t free_allocator) {
1531f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_realloc: T#%d (%p, %d, %p, %p)\n", gtid, ptr, (int)size,
1532f5c0c917SAndreyChurbanov                 allocator, free_allocator));
1533f5c0c917SAndreyChurbanov   void *nptr = __kmp_realloc(gtid, ptr, size, allocator, free_allocator);
1534f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_realloc returns %p, T#%d\n", nptr, gtid));
1535f5c0c917SAndreyChurbanov   return nptr;
1536f5c0c917SAndreyChurbanov }
1537f5c0c917SAndreyChurbanov 
__kmpc_free(int gtid,void * ptr,omp_allocator_handle_t allocator)1538f5c0c917SAndreyChurbanov void __kmpc_free(int gtid, void *ptr, omp_allocator_handle_t allocator) {
1539f5c0c917SAndreyChurbanov   KE_TRACE(25, ("__kmpc_free: T#%d free(%p,%p)\n", gtid, ptr, allocator));
1540f5c0c917SAndreyChurbanov   ___kmpc_free(gtid, ptr, allocator);
1541f5c0c917SAndreyChurbanov   KE_TRACE(10, ("__kmpc_free: T#%d freed %p (%p)\n", gtid, ptr, allocator));
1542f5c0c917SAndreyChurbanov   return;
1543f5c0c917SAndreyChurbanov }
1544f5c0c917SAndreyChurbanov 
1545f5c0c917SAndreyChurbanov // internal implementation, called from inside the library
__kmp_alloc(int gtid,size_t algn,size_t size,omp_allocator_handle_t allocator)1546f5c0c917SAndreyChurbanov void *__kmp_alloc(int gtid, size_t algn, size_t size,
1547f5c0c917SAndreyChurbanov                   omp_allocator_handle_t allocator) {
1548ebf1830bSJonathan Peyton   void *ptr = NULL;
1549ebf1830bSJonathan Peyton   kmp_allocator_t *al;
155092ca6188SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_init_serial);
1551938f1b85SNawrin Sultana   if (size == 0)
1552938f1b85SNawrin Sultana     return NULL;
1553ebf1830bSJonathan Peyton   if (allocator == omp_null_allocator)
155492ca6188SJonathan Peyton     allocator = __kmp_threads[gtid]->th.th_def_allocator;
1555d6281caaSCarlo Bertolli   kmp_int32 default_device =
1556d6281caaSCarlo Bertolli       __kmp_threads[gtid]->th.th_current_task->td_icvs.default_device;
155792ca6188SJonathan Peyton 
1558f5c0c917SAndreyChurbanov   al = RCAST(kmp_allocator_t *, allocator);
1559ebf1830bSJonathan Peyton 
156092ca6188SJonathan Peyton   int sz_desc = sizeof(kmp_mem_desc_t);
156192ca6188SJonathan Peyton   kmp_mem_desc_t desc;
156292ca6188SJonathan Peyton   kmp_uintptr_t addr; // address returned by allocator
156392ca6188SJonathan Peyton   kmp_uintptr_t addr_align; // address to return to caller
156492ca6188SJonathan Peyton   kmp_uintptr_t addr_descr; // address of memory block descriptor
1565f5c0c917SAndreyChurbanov   size_t align = alignment; // default alignment
1566f5c0c917SAndreyChurbanov   if (allocator > kmp_max_mem_alloc && al->alignment > align)
1567f5c0c917SAndreyChurbanov     align = al->alignment; // alignment required by allocator trait
1568f5c0c917SAndreyChurbanov   if (align < algn)
1569f5c0c917SAndreyChurbanov     align = algn; // max of allocator trait, parameter and sizeof(void*)
15705439db05SNawrin Sultana   desc.size_orig = size;
1571ebf1830bSJonathan Peyton   desc.size_a = size + sz_desc + align;
1572d6281caaSCarlo Bertolli   bool is_pinned = false;
1573d6281caaSCarlo Bertolli   if (allocator > kmp_max_mem_alloc)
1574d6281caaSCarlo Bertolli     is_pinned = al->pinned;
157592ca6188SJonathan Peyton 
1576e6d2665dSNawrin Sultana   // Use default allocator if libmemkind is not available
1577e6d2665dSNawrin Sultana   int use_default_allocator = (__kmp_memkind_available) ? false : true;
1578e6d2665dSNawrin Sultana 
1579eb0ea28bSNawrin Sultana   if (KMP_IS_TARGET_MEM_ALLOC(allocator)) {
1580eb0ea28bSNawrin Sultana     // Use size input directly as the memory may not be accessible on host.
1581eb0ea28bSNawrin Sultana     // Use default device for now.
1582eb0ea28bSNawrin Sultana     if (__kmp_target_mem_available) {
1583eb0ea28bSNawrin Sultana       kmp_int32 device =
1584eb0ea28bSNawrin Sultana           __kmp_threads[gtid]->th.th_current_task->td_icvs.default_device;
1585eb0ea28bSNawrin Sultana       if (allocator == llvm_omp_target_host_mem_alloc)
1586eb0ea28bSNawrin Sultana         ptr = kmp_target_alloc_host(size, device);
1587eb0ea28bSNawrin Sultana       else if (allocator == llvm_omp_target_shared_mem_alloc)
1588eb0ea28bSNawrin Sultana         ptr = kmp_target_alloc_shared(size, device);
1589eb0ea28bSNawrin Sultana       else // allocator == llvm_omp_target_device_mem_alloc
1590eb0ea28bSNawrin Sultana         ptr = kmp_target_alloc_device(size, device);
1591eb0ea28bSNawrin Sultana       return ptr;
1592*ae46cd72SNawrin Sultana     } else {
1593*ae46cd72SNawrin Sultana       KMP_INFORM(TargetMemNotAvailable);
1594*ae46cd72SNawrin Sultana     }
1595eb0ea28bSNawrin Sultana   }
1596eb0ea28bSNawrin Sultana 
1597eb0ea28bSNawrin Sultana   if (allocator >= kmp_max_mem_alloc && KMP_IS_TARGET_MEM_SPACE(al->memspace)) {
1598eb0ea28bSNawrin Sultana     if (__kmp_target_mem_available) {
1599eb0ea28bSNawrin Sultana       kmp_int32 device =
1600eb0ea28bSNawrin Sultana           __kmp_threads[gtid]->th.th_current_task->td_icvs.default_device;
1601eb0ea28bSNawrin Sultana       if (al->memspace == llvm_omp_target_host_mem_space)
1602eb0ea28bSNawrin Sultana         ptr = kmp_target_alloc_host(size, device);
1603eb0ea28bSNawrin Sultana       else if (al->memspace == llvm_omp_target_shared_mem_space)
1604eb0ea28bSNawrin Sultana         ptr = kmp_target_alloc_shared(size, device);
1605eb0ea28bSNawrin Sultana       else // al->memspace == llvm_omp_target_device_mem_space
1606eb0ea28bSNawrin Sultana         ptr = kmp_target_alloc_device(size, device);
1607eb0ea28bSNawrin Sultana       return ptr;
1608*ae46cd72SNawrin Sultana     } else {
1609*ae46cd72SNawrin Sultana       KMP_INFORM(TargetMemNotAvailable);
1610*ae46cd72SNawrin Sultana     }
1611eb0ea28bSNawrin Sultana   }
1612eb0ea28bSNawrin Sultana 
1613ebf1830bSJonathan Peyton   if (__kmp_memkind_available) {
1614ebf1830bSJonathan Peyton     if (allocator < kmp_max_mem_alloc) {
1615ebf1830bSJonathan Peyton       // pre-defined allocator
1616ebf1830bSJonathan Peyton       if (allocator == omp_high_bw_mem_alloc && mk_hbw_preferred) {
1617ebf1830bSJonathan Peyton         ptr = kmp_mk_alloc(*mk_hbw_preferred, desc.size_a);
1618bba3a82bSHansang Bae       } else if (allocator == omp_large_cap_mem_alloc && mk_dax_kmem_all) {
1619bba3a82bSHansang Bae         ptr = kmp_mk_alloc(*mk_dax_kmem_all, desc.size_a);
1620ebf1830bSJonathan Peyton       } else {
1621ebf1830bSJonathan Peyton         ptr = kmp_mk_alloc(*mk_default, desc.size_a);
1622ebf1830bSJonathan Peyton       }
1623ebf1830bSJonathan Peyton     } else if (al->pool_size > 0) {
1624ebf1830bSJonathan Peyton       // custom allocator with pool size requested
1625ebf1830bSJonathan Peyton       kmp_uint64 used =
1626ebf1830bSJonathan Peyton           KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, desc.size_a);
1627ebf1830bSJonathan Peyton       if (used + desc.size_a > al->pool_size) {
1628ebf1830bSJonathan Peyton         // not enough space, need to go fallback path
1629ebf1830bSJonathan Peyton         KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a);
1630ad24cf2aSKelvin Li         if (al->fb == omp_atv_default_mem_fb) {
1631ebf1830bSJonathan Peyton           al = (kmp_allocator_t *)omp_default_mem_alloc;
1632ebf1830bSJonathan Peyton           ptr = kmp_mk_alloc(*mk_default, desc.size_a);
1633ad24cf2aSKelvin Li         } else if (al->fb == omp_atv_abort_fb) {
1634ebf1830bSJonathan Peyton           KMP_ASSERT(0); // abort fallback requested
1635ad24cf2aSKelvin Li         } else if (al->fb == omp_atv_allocator_fb) {
1636ebf1830bSJonathan Peyton           KMP_ASSERT(al != al->fb_data);
1637ebf1830bSJonathan Peyton           al = al->fb_data;
1638d6281caaSCarlo Bertolli           ptr = __kmp_alloc(gtid, algn, size, (omp_allocator_handle_t)al);
1639d6281caaSCarlo Bertolli           if (is_pinned && kmp_target_lock_mem)
1640d6281caaSCarlo Bertolli             kmp_target_lock_mem(ptr, size, default_device);
1641d6281caaSCarlo Bertolli           return ptr;
1642ebf1830bSJonathan Peyton         } // else ptr == NULL;
1643ebf1830bSJonathan Peyton       } else {
1644ebf1830bSJonathan Peyton         // pool has enough space
1645ebf1830bSJonathan Peyton         ptr = kmp_mk_alloc(*al->memkind, desc.size_a);
1646ebf1830bSJonathan Peyton         if (ptr == NULL) {
1647ad24cf2aSKelvin Li           if (al->fb == omp_atv_default_mem_fb) {
1648ebf1830bSJonathan Peyton             al = (kmp_allocator_t *)omp_default_mem_alloc;
1649ebf1830bSJonathan Peyton             ptr = kmp_mk_alloc(*mk_default, desc.size_a);
1650ad24cf2aSKelvin Li           } else if (al->fb == omp_atv_abort_fb) {
1651ebf1830bSJonathan Peyton             KMP_ASSERT(0); // abort fallback requested
1652ad24cf2aSKelvin Li           } else if (al->fb == omp_atv_allocator_fb) {
1653ebf1830bSJonathan Peyton             KMP_ASSERT(al != al->fb_data);
1654ebf1830bSJonathan Peyton             al = al->fb_data;
1655d6281caaSCarlo Bertolli             ptr = __kmp_alloc(gtid, algn, size, (omp_allocator_handle_t)al);
1656d6281caaSCarlo Bertolli             if (is_pinned && kmp_target_lock_mem)
1657d6281caaSCarlo Bertolli               kmp_target_lock_mem(ptr, size, default_device);
1658d6281caaSCarlo Bertolli             return ptr;
1659ebf1830bSJonathan Peyton           }
1660ebf1830bSJonathan Peyton         }
1661ebf1830bSJonathan Peyton       }
1662ebf1830bSJonathan Peyton     } else {
1663ebf1830bSJonathan Peyton       // custom allocator, pool size not requested
1664ebf1830bSJonathan Peyton       ptr = kmp_mk_alloc(*al->memkind, desc.size_a);
1665ebf1830bSJonathan Peyton       if (ptr == NULL) {
1666ad24cf2aSKelvin Li         if (al->fb == omp_atv_default_mem_fb) {
1667ebf1830bSJonathan Peyton           al = (kmp_allocator_t *)omp_default_mem_alloc;
1668ebf1830bSJonathan Peyton           ptr = kmp_mk_alloc(*mk_default, desc.size_a);
1669ad24cf2aSKelvin Li         } else if (al->fb == omp_atv_abort_fb) {
1670ebf1830bSJonathan Peyton           KMP_ASSERT(0); // abort fallback requested
1671ad24cf2aSKelvin Li         } else if (al->fb == omp_atv_allocator_fb) {
1672ebf1830bSJonathan Peyton           KMP_ASSERT(al != al->fb_data);
1673ebf1830bSJonathan Peyton           al = al->fb_data;
1674d6281caaSCarlo Bertolli           ptr = __kmp_alloc(gtid, algn, size, (omp_allocator_handle_t)al);
1675d6281caaSCarlo Bertolli           if (is_pinned && kmp_target_lock_mem)
1676d6281caaSCarlo Bertolli             kmp_target_lock_mem(ptr, size, default_device);
1677d6281caaSCarlo Bertolli           return ptr;
1678ebf1830bSJonathan Peyton         }
1679ebf1830bSJonathan Peyton       }
1680ebf1830bSJonathan Peyton     }
1681ebf1830bSJonathan Peyton   } else if (allocator < kmp_max_mem_alloc) {
1682ebf1830bSJonathan Peyton     // pre-defined allocator
1683ebf1830bSJonathan Peyton     if (allocator == omp_high_bw_mem_alloc) {
1684e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_high_bw_mem_alloc");
1685bba3a82bSHansang Bae     } else if (allocator == omp_large_cap_mem_alloc) {
1686e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_large_cap_mem_alloc");
1687e6d2665dSNawrin Sultana     } else if (allocator == omp_const_mem_alloc) {
1688e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_const_mem_alloc");
1689e6d2665dSNawrin Sultana     } else if (allocator == omp_low_lat_mem_alloc) {
1690e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_low_lat_mem_alloc");
1691e6d2665dSNawrin Sultana     } else if (allocator == omp_cgroup_mem_alloc) {
1692e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_cgroup_mem_alloc");
1693e6d2665dSNawrin Sultana     } else if (allocator == omp_pteam_mem_alloc) {
1694e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_pteam_mem_alloc");
1695e6d2665dSNawrin Sultana     } else if (allocator == omp_thread_mem_alloc) {
1696e6d2665dSNawrin Sultana       KMP_WARNING(OmpNoAllocator, "omp_thread_mem_alloc");
1697e6d2665dSNawrin Sultana     } else { // default allocator requested
1698e6d2665dSNawrin Sultana       use_default_allocator = true;
1699e6d2665dSNawrin Sultana     }
1700e6d2665dSNawrin Sultana     if (use_default_allocator) {
1701ebf1830bSJonathan Peyton       ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a);
1702e6d2665dSNawrin Sultana       use_default_allocator = false;
1703ebf1830bSJonathan Peyton     }
1704ebf1830bSJonathan Peyton   } else if (al->pool_size > 0) {
1705ebf1830bSJonathan Peyton     // custom allocator with pool size requested
1706ebf1830bSJonathan Peyton     kmp_uint64 used =
1707ebf1830bSJonathan Peyton         KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, desc.size_a);
1708ebf1830bSJonathan Peyton     if (used + desc.size_a > al->pool_size) {
1709ebf1830bSJonathan Peyton       // not enough space, need to go fallback path
1710ebf1830bSJonathan Peyton       KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a);
1711ad24cf2aSKelvin Li       if (al->fb == omp_atv_default_mem_fb) {
1712ebf1830bSJonathan Peyton         al = (kmp_allocator_t *)omp_default_mem_alloc;
1713ebf1830bSJonathan Peyton         ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a);
1714ad24cf2aSKelvin Li       } else if (al->fb == omp_atv_abort_fb) {
1715ebf1830bSJonathan Peyton         KMP_ASSERT(0); // abort fallback requested
1716ad24cf2aSKelvin Li       } else if (al->fb == omp_atv_allocator_fb) {
1717ebf1830bSJonathan Peyton         KMP_ASSERT(al != al->fb_data);
1718ebf1830bSJonathan Peyton         al = al->fb_data;
1719d6281caaSCarlo Bertolli         ptr = __kmp_alloc(gtid, algn, size, (omp_allocator_handle_t)al);
1720d6281caaSCarlo Bertolli         if (is_pinned && kmp_target_lock_mem)
1721d6281caaSCarlo Bertolli           kmp_target_lock_mem(ptr, size, default_device);
1722d6281caaSCarlo Bertolli         return ptr;
1723ebf1830bSJonathan Peyton       } // else ptr == NULL;
1724ebf1830bSJonathan Peyton     } else {
1725ebf1830bSJonathan Peyton       // pool has enough space
1726ebf1830bSJonathan Peyton       ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a);
1727ad24cf2aSKelvin Li       if (ptr == NULL && al->fb == omp_atv_abort_fb) {
1728ebf1830bSJonathan Peyton         KMP_ASSERT(0); // abort fallback requested
1729ebf1830bSJonathan Peyton       } // no sense to look for another fallback because of same internal alloc
1730ebf1830bSJonathan Peyton     }
1731ebf1830bSJonathan Peyton   } else {
1732ebf1830bSJonathan Peyton     // custom allocator, pool size not requested
1733ebf1830bSJonathan Peyton     ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a);
1734ad24cf2aSKelvin Li     if (ptr == NULL && al->fb == omp_atv_abort_fb) {
1735ebf1830bSJonathan Peyton       KMP_ASSERT(0); // abort fallback requested
1736ebf1830bSJonathan Peyton     } // no sense to look for another fallback because of same internal alloc
1737ebf1830bSJonathan Peyton   }
1738f5c0c917SAndreyChurbanov   KE_TRACE(10, ("__kmp_alloc: T#%d %p=alloc(%d)\n", gtid, ptr, desc.size_a));
173992ca6188SJonathan Peyton   if (ptr == NULL)
174092ca6188SJonathan Peyton     return NULL;
174192ca6188SJonathan Peyton 
1742d6281caaSCarlo Bertolli   if (is_pinned && kmp_target_lock_mem)
1743d6281caaSCarlo Bertolli     kmp_target_lock_mem(ptr, desc.size_a, default_device);
1744d6281caaSCarlo Bertolli 
174592ca6188SJonathan Peyton   addr = (kmp_uintptr_t)ptr;
1746ebf1830bSJonathan Peyton   addr_align = (addr + sz_desc + align - 1) & ~(align - 1);
174792ca6188SJonathan Peyton   addr_descr = addr_align - sz_desc;
174892ca6188SJonathan Peyton 
174992ca6188SJonathan Peyton   desc.ptr_alloc = ptr;
175092ca6188SJonathan Peyton   desc.ptr_align = (void *)addr_align;
1751ebf1830bSJonathan Peyton   desc.allocator = al;
175292ca6188SJonathan Peyton   *((kmp_mem_desc_t *)addr_descr) = desc; // save descriptor contents
175392ca6188SJonathan Peyton   KMP_MB();
175492ca6188SJonathan Peyton 
175592ca6188SJonathan Peyton   return desc.ptr_align;
175692ca6188SJonathan Peyton }
175792ca6188SJonathan Peyton 
__kmp_calloc(int gtid,size_t algn,size_t nmemb,size_t size,omp_allocator_handle_t allocator)1758f5c0c917SAndreyChurbanov void *__kmp_calloc(int gtid, size_t algn, size_t nmemb, size_t size,
1759938f1b85SNawrin Sultana                    omp_allocator_handle_t allocator) {
1760938f1b85SNawrin Sultana   void *ptr = NULL;
1761938f1b85SNawrin Sultana   kmp_allocator_t *al;
1762938f1b85SNawrin Sultana   KMP_DEBUG_ASSERT(__kmp_init_serial);
1763938f1b85SNawrin Sultana 
1764938f1b85SNawrin Sultana   if (allocator == omp_null_allocator)
1765938f1b85SNawrin Sultana     allocator = __kmp_threads[gtid]->th.th_def_allocator;
1766938f1b85SNawrin Sultana 
1767f5c0c917SAndreyChurbanov   al = RCAST(kmp_allocator_t *, allocator);
1768938f1b85SNawrin Sultana 
1769938f1b85SNawrin Sultana   if (nmemb == 0 || size == 0)
1770938f1b85SNawrin Sultana     return ptr;
1771938f1b85SNawrin Sultana 
1772938f1b85SNawrin Sultana   if ((SIZE_MAX - sizeof(kmp_mem_desc_t)) / size < nmemb) {
1773938f1b85SNawrin Sultana     if (al->fb == omp_atv_abort_fb) {
1774938f1b85SNawrin Sultana       KMP_ASSERT(0);
1775938f1b85SNawrin Sultana     }
1776938f1b85SNawrin Sultana     return ptr;
1777938f1b85SNawrin Sultana   }
1778938f1b85SNawrin Sultana 
1779f5c0c917SAndreyChurbanov   ptr = __kmp_alloc(gtid, algn, nmemb * size, allocator);
1780938f1b85SNawrin Sultana 
1781938f1b85SNawrin Sultana   if (ptr) {
1782938f1b85SNawrin Sultana     memset(ptr, 0x00, nmemb * size);
1783938f1b85SNawrin Sultana   }
1784938f1b85SNawrin Sultana   return ptr;
1785938f1b85SNawrin Sultana }
1786938f1b85SNawrin Sultana 
__kmp_realloc(int gtid,void * ptr,size_t size,omp_allocator_handle_t allocator,omp_allocator_handle_t free_allocator)1787f5c0c917SAndreyChurbanov void *__kmp_realloc(int gtid, void *ptr, size_t size,
17885439db05SNawrin Sultana                     omp_allocator_handle_t allocator,
17895439db05SNawrin Sultana                     omp_allocator_handle_t free_allocator) {
17905439db05SNawrin Sultana   void *nptr = NULL;
17915439db05SNawrin Sultana   KMP_DEBUG_ASSERT(__kmp_init_serial);
17925439db05SNawrin Sultana 
17935439db05SNawrin Sultana   if (size == 0) {
17945439db05SNawrin Sultana     if (ptr != NULL)
1795f5c0c917SAndreyChurbanov       ___kmpc_free(gtid, ptr, free_allocator);
17965439db05SNawrin Sultana     return nptr;
17975439db05SNawrin Sultana   }
17985439db05SNawrin Sultana 
1799f5c0c917SAndreyChurbanov   nptr = __kmp_alloc(gtid, 0, size, allocator);
18005439db05SNawrin Sultana 
18015439db05SNawrin Sultana   if (nptr != NULL && ptr != NULL) {
18025439db05SNawrin Sultana     kmp_mem_desc_t desc;
18035439db05SNawrin Sultana     kmp_uintptr_t addr_align; // address to return to caller
18045439db05SNawrin Sultana     kmp_uintptr_t addr_descr; // address of memory block descriptor
18055439db05SNawrin Sultana 
18065439db05SNawrin Sultana     addr_align = (kmp_uintptr_t)ptr;
18075439db05SNawrin Sultana     addr_descr = addr_align - sizeof(kmp_mem_desc_t);
18085439db05SNawrin Sultana     desc = *((kmp_mem_desc_t *)addr_descr); // read descriptor
18095439db05SNawrin Sultana 
18105439db05SNawrin Sultana     KMP_DEBUG_ASSERT(desc.ptr_align == ptr);
18115439db05SNawrin Sultana     KMP_DEBUG_ASSERT(desc.size_orig > 0);
18125439db05SNawrin Sultana     KMP_DEBUG_ASSERT(desc.size_orig < desc.size_a);
18135439db05SNawrin Sultana     KMP_MEMCPY((char *)nptr, (char *)ptr,
18145439db05SNawrin Sultana                (size_t)((size < desc.size_orig) ? size : desc.size_orig));
18155439db05SNawrin Sultana   }
18165439db05SNawrin Sultana 
18175439db05SNawrin Sultana   if (nptr != NULL) {
1818f5c0c917SAndreyChurbanov     ___kmpc_free(gtid, ptr, free_allocator);
18195439db05SNawrin Sultana   }
18205439db05SNawrin Sultana 
18215439db05SNawrin Sultana   return nptr;
18225439db05SNawrin Sultana }
18235439db05SNawrin Sultana 
___kmpc_free(int gtid,void * ptr,omp_allocator_handle_t allocator)1824f5c0c917SAndreyChurbanov void ___kmpc_free(int gtid, void *ptr, omp_allocator_handle_t allocator) {
182592ca6188SJonathan Peyton   if (ptr == NULL)
182692ca6188SJonathan Peyton     return;
182792ca6188SJonathan Peyton 
1828ebf1830bSJonathan Peyton   kmp_allocator_t *al;
1829ebf1830bSJonathan Peyton   omp_allocator_handle_t oal;
1830ebf1830bSJonathan Peyton   al = RCAST(kmp_allocator_t *, CCAST(omp_allocator_handle_t, allocator));
183192ca6188SJonathan Peyton   kmp_mem_desc_t desc;
183292ca6188SJonathan Peyton   kmp_uintptr_t addr_align; // address to return to caller
183392ca6188SJonathan Peyton   kmp_uintptr_t addr_descr; // address of memory block descriptor
183423bc3438SJoseph Huber   if (__kmp_target_mem_available && (KMP_IS_TARGET_MEM_ALLOC(allocator) ||
1835b6c2f538SHansang Bae                                      (allocator > kmp_max_mem_alloc &&
183623bc3438SJoseph Huber                                       KMP_IS_TARGET_MEM_SPACE(al->memspace)))) {
1837b6c2f538SHansang Bae     kmp_int32 device =
1838b6c2f538SHansang Bae         __kmp_threads[gtid]->th.th_current_task->td_icvs.default_device;
183923bc3438SJoseph Huber     if (allocator == llvm_omp_target_host_mem_alloc) {
184023bc3438SJoseph Huber       kmp_target_free_host(ptr, device);
184123bc3438SJoseph Huber     } else if (allocator == llvm_omp_target_shared_mem_alloc) {
184223bc3438SJoseph Huber       kmp_target_free_shared(ptr, device);
184323bc3438SJoseph Huber     } else if (allocator == llvm_omp_target_device_mem_alloc) {
184423bc3438SJoseph Huber       kmp_target_free_device(ptr, device);
184523bc3438SJoseph Huber     }
1846b6c2f538SHansang Bae     return;
1847b6c2f538SHansang Bae   }
184892ca6188SJonathan Peyton 
184992ca6188SJonathan Peyton   addr_align = (kmp_uintptr_t)ptr;
185092ca6188SJonathan Peyton   addr_descr = addr_align - sizeof(kmp_mem_desc_t);
185192ca6188SJonathan Peyton   desc = *((kmp_mem_desc_t *)addr_descr); // read descriptor
185292ca6188SJonathan Peyton 
185392ca6188SJonathan Peyton   KMP_DEBUG_ASSERT(desc.ptr_align == ptr);
185492ca6188SJonathan Peyton   if (allocator) {
1855ebf1830bSJonathan Peyton     KMP_DEBUG_ASSERT(desc.allocator == al || desc.allocator == al->fb_data);
185692ca6188SJonathan Peyton   }
1857ebf1830bSJonathan Peyton   al = desc.allocator;
1858ebf1830bSJonathan Peyton   oal = (omp_allocator_handle_t)al; // cast to void* for comparisons
1859ebf1830bSJonathan Peyton   KMP_DEBUG_ASSERT(al);
186092ca6188SJonathan Peyton 
1861d6281caaSCarlo Bertolli   if (allocator > kmp_max_mem_alloc && kmp_target_unlock_mem && al->pinned) {
1862d6281caaSCarlo Bertolli     kmp_int32 device =
1863d6281caaSCarlo Bertolli         __kmp_threads[gtid]->th.th_current_task->td_icvs.default_device;
1864d6281caaSCarlo Bertolli     kmp_target_unlock_mem(desc.ptr_alloc, device);
1865d6281caaSCarlo Bertolli   }
1866d6281caaSCarlo Bertolli 
1867ebf1830bSJonathan Peyton   if (__kmp_memkind_available) {
1868ebf1830bSJonathan Peyton     if (oal < kmp_max_mem_alloc) {
1869ebf1830bSJonathan Peyton       // pre-defined allocator
1870ebf1830bSJonathan Peyton       if (oal == omp_high_bw_mem_alloc && mk_hbw_preferred) {
1871ebf1830bSJonathan Peyton         kmp_mk_free(*mk_hbw_preferred, desc.ptr_alloc);
1872bba3a82bSHansang Bae       } else if (oal == omp_large_cap_mem_alloc && mk_dax_kmem_all) {
1873bba3a82bSHansang Bae         kmp_mk_free(*mk_dax_kmem_all, desc.ptr_alloc);
1874ebf1830bSJonathan Peyton       } else {
1875ebf1830bSJonathan Peyton         kmp_mk_free(*mk_default, desc.ptr_alloc);
1876ebf1830bSJonathan Peyton       }
1877ebf1830bSJonathan Peyton     } else {
1878ebf1830bSJonathan Peyton       if (al->pool_size > 0) { // custom allocator with pool size requested
1879ebf1830bSJonathan Peyton         kmp_uint64 used =
1880ebf1830bSJonathan Peyton             KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a);
1881ebf1830bSJonathan Peyton         (void)used; // to suppress compiler warning
1882ebf1830bSJonathan Peyton         KMP_DEBUG_ASSERT(used >= desc.size_a);
1883ebf1830bSJonathan Peyton       }
1884ebf1830bSJonathan Peyton       kmp_mk_free(*al->memkind, desc.ptr_alloc);
1885ebf1830bSJonathan Peyton     }
1886ebf1830bSJonathan Peyton   } else {
1887ebf1830bSJonathan Peyton     if (oal > kmp_max_mem_alloc && al->pool_size > 0) {
1888ebf1830bSJonathan Peyton       kmp_uint64 used =
1889ebf1830bSJonathan Peyton           KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a);
1890ebf1830bSJonathan Peyton       (void)used; // to suppress compiler warning
1891ebf1830bSJonathan Peyton       KMP_DEBUG_ASSERT(used >= desc.size_a);
1892ebf1830bSJonathan Peyton     }
1893ebf1830bSJonathan Peyton     __kmp_thread_free(__kmp_thread_from_gtid(gtid), desc.ptr_alloc);
189492ca6188SJonathan Peyton   }
189592ca6188SJonathan Peyton }
189692ca6188SJonathan Peyton 
18973041982dSJonathan Peyton /* If LEAK_MEMORY is defined, __kmp_free() will *not* free memory. It causes
18983041982dSJonathan Peyton    memory leaks, but it may be useful for debugging memory corruptions, used
18993041982dSJonathan Peyton    freed pointers, etc. */
19007cc577a4SJonathan Peyton /* #define LEAK_MEMORY */
19017cc577a4SJonathan Peyton struct kmp_mem_descr { // Memory block descriptor.
19027cc577a4SJonathan Peyton   void *ptr_allocated; // Pointer returned by malloc(), subject for free().
19037cc577a4SJonathan Peyton   size_t size_allocated; // Size of allocated memory block.
19047cc577a4SJonathan Peyton   void *ptr_aligned; // Pointer to aligned memory, to be used by client code.
19057cc577a4SJonathan Peyton   size_t size_aligned; // Size of aligned memory block.
19067cc577a4SJonathan Peyton };
19077cc577a4SJonathan Peyton typedef struct kmp_mem_descr kmp_mem_descr_t;
19087cc577a4SJonathan Peyton 
19093041982dSJonathan Peyton /* Allocate memory on requested boundary, fill allocated memory with 0x00.
19103041982dSJonathan Peyton    NULL is NEVER returned, __kmp_abort() is called in case of memory allocation
19113041982dSJonathan Peyton    error. Must use __kmp_free when freeing memory allocated by this routine! */
___kmp_allocate_align(size_t size,size_t alignment KMP_SRC_LOC_DECL)19123041982dSJonathan Peyton static void *___kmp_allocate_align(size_t size,
19133041982dSJonathan Peyton                                    size_t alignment KMP_SRC_LOC_DECL) {
19143041982dSJonathan Peyton   /* __kmp_allocate() allocates (by call to malloc()) bigger memory block than
19153041982dSJonathan Peyton      requested to return properly aligned pointer. Original pointer returned
19163041982dSJonathan Peyton      by malloc() and size of allocated block is saved in descriptor just
19173041982dSJonathan Peyton      before the aligned pointer. This information used by __kmp_free() -- it
19183041982dSJonathan Peyton      has to pass to free() original pointer, not aligned one.
19197cc577a4SJonathan Peyton 
19207cc577a4SJonathan Peyton           +---------+------------+-----------------------------------+---------+
19217cc577a4SJonathan Peyton           | padding | descriptor |           aligned block           | padding |
19227cc577a4SJonathan Peyton           +---------+------------+-----------------------------------+---------+
19237cc577a4SJonathan Peyton           ^                      ^
19247cc577a4SJonathan Peyton           |                      |
19257cc577a4SJonathan Peyton           |                      +- Aligned pointer returned to caller
19267cc577a4SJonathan Peyton           +- Pointer returned by malloc()
19277cc577a4SJonathan Peyton 
19283041982dSJonathan Peyton       Aligned block is filled with zeros, paddings are filled with 0xEF. */
19297cc577a4SJonathan Peyton 
19307cc577a4SJonathan Peyton   kmp_mem_descr_t descr;
19317cc577a4SJonathan Peyton   kmp_uintptr_t addr_allocated; // Address returned by malloc().
19327cc577a4SJonathan Peyton   kmp_uintptr_t addr_aligned; // Aligned address to return to caller.
19337cc577a4SJonathan Peyton   kmp_uintptr_t addr_descr; // Address of memory block descriptor.
19347cc577a4SJonathan Peyton 
19353041982dSJonathan Peyton   KE_TRACE(25, ("-> ___kmp_allocate_align( %d, %d ) called from %s:%d\n",
19363041982dSJonathan Peyton                 (int)size, (int)alignment KMP_SRC_LOC_PARM));
19377cc577a4SJonathan Peyton 
19387cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(alignment < 32 * 1024); // Alignment should not be too
19397cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(sizeof(void *) <= sizeof(kmp_uintptr_t));
19407cc577a4SJonathan Peyton   // Make sure kmp_uintptr_t is enough to store addresses.
19417cc577a4SJonathan Peyton 
19427cc577a4SJonathan Peyton   descr.size_aligned = size;
19433041982dSJonathan Peyton   descr.size_allocated =
19443041982dSJonathan Peyton       descr.size_aligned + sizeof(kmp_mem_descr_t) + alignment;
19457cc577a4SJonathan Peyton 
19467cc577a4SJonathan Peyton #if KMP_DEBUG
19477cc577a4SJonathan Peyton   descr.ptr_allocated = _malloc_src_loc(descr.size_allocated, _file_, _line_);
19487cc577a4SJonathan Peyton #else
19497cc577a4SJonathan Peyton   descr.ptr_allocated = malloc_src_loc(descr.size_allocated KMP_SRC_LOC_PARM);
19507cc577a4SJonathan Peyton #endif
19513041982dSJonathan Peyton   KE_TRACE(10, ("   malloc( %d ) returned %p\n", (int)descr.size_allocated,
19523041982dSJonathan Peyton                 descr.ptr_allocated));
19537cc577a4SJonathan Peyton   if (descr.ptr_allocated == NULL) {
19547cc577a4SJonathan Peyton     KMP_FATAL(OutOfHeapMemory);
1955bd3a7633SJonathan Peyton   }
19567cc577a4SJonathan Peyton 
19577cc577a4SJonathan Peyton   addr_allocated = (kmp_uintptr_t)descr.ptr_allocated;
19587cc577a4SJonathan Peyton   addr_aligned =
19593041982dSJonathan Peyton       (addr_allocated + sizeof(kmp_mem_descr_t) + alignment) & ~(alignment - 1);
19607cc577a4SJonathan Peyton   addr_descr = addr_aligned - sizeof(kmp_mem_descr_t);
19617cc577a4SJonathan Peyton 
19627cc577a4SJonathan Peyton   descr.ptr_aligned = (void *)addr_aligned;
19637cc577a4SJonathan Peyton 
19643041982dSJonathan Peyton   KE_TRACE(26, ("   ___kmp_allocate_align: "
19657cc577a4SJonathan Peyton                 "ptr_allocated=%p, size_allocated=%d, "
19667cc577a4SJonathan Peyton                 "ptr_aligned=%p, size_aligned=%d\n",
19673041982dSJonathan Peyton                 descr.ptr_allocated, (int)descr.size_allocated,
19683041982dSJonathan Peyton                 descr.ptr_aligned, (int)descr.size_aligned));
19697cc577a4SJonathan Peyton 
19707cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(addr_allocated <= addr_descr);
19717cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(addr_descr + sizeof(kmp_mem_descr_t) == addr_aligned);
19723041982dSJonathan Peyton   KMP_DEBUG_ASSERT(addr_aligned + descr.size_aligned <=
19733041982dSJonathan Peyton                    addr_allocated + descr.size_allocated);
19747cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(addr_aligned % alignment == 0);
19757cc577a4SJonathan Peyton #ifdef KMP_DEBUG
19767cc577a4SJonathan Peyton   memset(descr.ptr_allocated, 0xEF, descr.size_allocated);
19777cc577a4SJonathan Peyton // Fill allocated memory block with 0xEF.
19787cc577a4SJonathan Peyton #endif
19797cc577a4SJonathan Peyton   memset(descr.ptr_aligned, 0x00, descr.size_aligned);
19803041982dSJonathan Peyton   // Fill the aligned memory block (which is intended for using by caller) with
19813041982dSJonathan Peyton   // 0x00. Do not
19823041982dSJonathan Peyton   // put this filling under KMP_DEBUG condition! Many callers expect zeroed
19833041982dSJonathan Peyton   // memory. (Padding
19847cc577a4SJonathan Peyton   // bytes remain filled with 0xEF in debugging library.)
19857cc577a4SJonathan Peyton   *((kmp_mem_descr_t *)addr_descr) = descr;
19867cc577a4SJonathan Peyton 
19877cc577a4SJonathan Peyton   KMP_MB();
19887cc577a4SJonathan Peyton 
19897cc577a4SJonathan Peyton   KE_TRACE(25, ("<- ___kmp_allocate_align() returns %p\n", descr.ptr_aligned));
19907cc577a4SJonathan Peyton   return descr.ptr_aligned;
19917cc577a4SJonathan Peyton } // func ___kmp_allocate_align
19927cc577a4SJonathan Peyton 
19933041982dSJonathan Peyton /* Allocate memory on cache line boundary, fill allocated memory with 0x00.
19947cc577a4SJonathan Peyton    Do not call this func directly! Use __kmp_allocate macro instead.
19953041982dSJonathan Peyton    NULL is NEVER returned, __kmp_abort() is called in case of memory allocation
19963041982dSJonathan Peyton    error. Must use __kmp_free when freeing memory allocated by this routine! */
___kmp_allocate(size_t size KMP_SRC_LOC_DECL)19973041982dSJonathan Peyton void *___kmp_allocate(size_t size KMP_SRC_LOC_DECL) {
19987cc577a4SJonathan Peyton   void *ptr;
19993041982dSJonathan Peyton   KE_TRACE(25, ("-> __kmp_allocate( %d ) called from %s:%d\n",
20003041982dSJonathan Peyton                 (int)size KMP_SRC_LOC_PARM));
20017cc577a4SJonathan Peyton   ptr = ___kmp_allocate_align(size, __kmp_align_alloc KMP_SRC_LOC_PARM);
20027cc577a4SJonathan Peyton   KE_TRACE(25, ("<- __kmp_allocate() returns %p\n", ptr));
20037cc577a4SJonathan Peyton   return ptr;
20047cc577a4SJonathan Peyton } // func ___kmp_allocate
20057cc577a4SJonathan Peyton 
20063041982dSJonathan Peyton /* Allocate memory on page boundary, fill allocated memory with 0x00.
20077cc577a4SJonathan Peyton    Does not call this func directly! Use __kmp_page_allocate macro instead.
20083041982dSJonathan Peyton    NULL is NEVER returned, __kmp_abort() is called in case of memory allocation
20093041982dSJonathan Peyton    error. Must use __kmp_free when freeing memory allocated by this routine! */
___kmp_page_allocate(size_t size KMP_SRC_LOC_DECL)20103041982dSJonathan Peyton void *___kmp_page_allocate(size_t size KMP_SRC_LOC_DECL) {
20117cc577a4SJonathan Peyton   int page_size = 8 * 1024;
20127cc577a4SJonathan Peyton   void *ptr;
20137cc577a4SJonathan Peyton 
20143041982dSJonathan Peyton   KE_TRACE(25, ("-> __kmp_page_allocate( %d ) called from %s:%d\n",
20153041982dSJonathan Peyton                 (int)size KMP_SRC_LOC_PARM));
20167cc577a4SJonathan Peyton   ptr = ___kmp_allocate_align(size, page_size KMP_SRC_LOC_PARM);
20177cc577a4SJonathan Peyton   KE_TRACE(25, ("<- __kmp_page_allocate( %d ) returns %p\n", (int)size, ptr));
20187cc577a4SJonathan Peyton   return ptr;
20197cc577a4SJonathan Peyton } // ___kmp_page_allocate
20207cc577a4SJonathan Peyton 
20213041982dSJonathan Peyton /* Free memory allocated by __kmp_allocate() and __kmp_page_allocate().
20223041982dSJonathan Peyton    In debug mode, fill the memory block with 0xEF before call to free(). */
___kmp_free(void * ptr KMP_SRC_LOC_DECL)20233041982dSJonathan Peyton void ___kmp_free(void *ptr KMP_SRC_LOC_DECL) {
20247cc577a4SJonathan Peyton   kmp_mem_descr_t descr;
20258b81524cSAndreyChurbanov #if KMP_DEBUG
20267cc577a4SJonathan Peyton   kmp_uintptr_t addr_allocated; // Address returned by malloc().
20277cc577a4SJonathan Peyton   kmp_uintptr_t addr_aligned; // Aligned address passed by caller.
20288b81524cSAndreyChurbanov #endif
20293041982dSJonathan Peyton   KE_TRACE(25,
20303041982dSJonathan Peyton            ("-> __kmp_free( %p ) called from %s:%d\n", ptr KMP_SRC_LOC_PARM));
20317cc577a4SJonathan Peyton   KMP_ASSERT(ptr != NULL);
20327cc577a4SJonathan Peyton 
20337cc577a4SJonathan Peyton   descr = *(kmp_mem_descr_t *)((kmp_uintptr_t)ptr - sizeof(kmp_mem_descr_t));
20347cc577a4SJonathan Peyton 
20357cc577a4SJonathan Peyton   KE_TRACE(26, ("   __kmp_free:     "
20367cc577a4SJonathan Peyton                 "ptr_allocated=%p, size_allocated=%d, "
20377cc577a4SJonathan Peyton                 "ptr_aligned=%p, size_aligned=%d\n",
20387cc577a4SJonathan Peyton                 descr.ptr_allocated, (int)descr.size_allocated,
20397cc577a4SJonathan Peyton                 descr.ptr_aligned, (int)descr.size_aligned));
20408b81524cSAndreyChurbanov #if KMP_DEBUG
20417cc577a4SJonathan Peyton   addr_allocated = (kmp_uintptr_t)descr.ptr_allocated;
20427cc577a4SJonathan Peyton   addr_aligned = (kmp_uintptr_t)descr.ptr_aligned;
20437cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(addr_aligned % CACHE_LINE == 0);
20447cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(descr.ptr_aligned == ptr);
20457cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(addr_allocated + sizeof(kmp_mem_descr_t) <= addr_aligned);
20467cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(descr.size_aligned < descr.size_allocated);
20473041982dSJonathan Peyton   KMP_DEBUG_ASSERT(addr_aligned + descr.size_aligned <=
20483041982dSJonathan Peyton                    addr_allocated + descr.size_allocated);
20497cc577a4SJonathan Peyton   memset(descr.ptr_allocated, 0xEF, descr.size_allocated);
20507cc577a4SJonathan Peyton // Fill memory block with 0xEF, it helps catch using freed memory.
20517cc577a4SJonathan Peyton #endif
20527cc577a4SJonathan Peyton 
20537cc577a4SJonathan Peyton #ifndef LEAK_MEMORY
20547cc577a4SJonathan Peyton   KE_TRACE(10, ("   free( %p )\n", descr.ptr_allocated));
20557cc577a4SJonathan Peyton #ifdef KMP_DEBUG
20567cc577a4SJonathan Peyton   _free_src_loc(descr.ptr_allocated, _file_, _line_);
20577cc577a4SJonathan Peyton #else
20587cc577a4SJonathan Peyton   free_src_loc(descr.ptr_allocated KMP_SRC_LOC_PARM);
20597cc577a4SJonathan Peyton #endif
20607cc577a4SJonathan Peyton #endif
20617cc577a4SJonathan Peyton   KMP_MB();
20627cc577a4SJonathan Peyton   KE_TRACE(25, ("<- __kmp_free() returns\n"));
20637cc577a4SJonathan Peyton } // func ___kmp_free
20647cc577a4SJonathan Peyton 
20657cc577a4SJonathan Peyton #if USE_FAST_MEMORY == 3
20667cc577a4SJonathan Peyton // Allocate fast memory by first scanning the thread's free lists
20677cc577a4SJonathan Peyton // If a chunk the right size exists, grab it off the free list.
20687cc577a4SJonathan Peyton // Otherwise allocate normally using kmp_thread_malloc.
20697cc577a4SJonathan Peyton 
20707cc577a4SJonathan Peyton // AC: How to choose the limit? Just get 16 for now...
20717cc577a4SJonathan Peyton #define KMP_FREE_LIST_LIMIT 16
20727cc577a4SJonathan Peyton 
20737cc577a4SJonathan Peyton // Always use 128 bytes for determining buckets for caching memory blocks
20747cc577a4SJonathan Peyton #define DCACHE_LINE 128
20757cc577a4SJonathan Peyton 
___kmp_fast_allocate(kmp_info_t * this_thr,size_t size KMP_SRC_LOC_DECL)20763041982dSJonathan Peyton void *___kmp_fast_allocate(kmp_info_t *this_thr, size_t size KMP_SRC_LOC_DECL) {
20777cc577a4SJonathan Peyton   void *ptr;
20786b316febSTerry Wilmarth   size_t num_lines, idx;
20797cc577a4SJonathan Peyton   int index;
20807cc577a4SJonathan Peyton   void *alloc_ptr;
20817cc577a4SJonathan Peyton   size_t alloc_size;
20827cc577a4SJonathan Peyton   kmp_mem_descr_t *descr;
20837cc577a4SJonathan Peyton 
20847cc577a4SJonathan Peyton   KE_TRACE(25, ("-> __kmp_fast_allocate( T#%d, %d ) called from %s:%d\n",
20857cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr), (int)size KMP_SRC_LOC_PARM));
20867cc577a4SJonathan Peyton 
20877cc577a4SJonathan Peyton   num_lines = (size + DCACHE_LINE - 1) / DCACHE_LINE;
20887cc577a4SJonathan Peyton   idx = num_lines - 1;
20897cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(idx >= 0);
20907cc577a4SJonathan Peyton   if (idx < 2) {
20917cc577a4SJonathan Peyton     index = 0; // idx is [ 0, 1 ], use first free list
20927cc577a4SJonathan Peyton     num_lines = 2; // 1, 2 cache lines or less than cache line
20937cc577a4SJonathan Peyton   } else if ((idx >>= 2) == 0) {
20947cc577a4SJonathan Peyton     index = 1; // idx is [ 2, 3 ], use second free list
20957cc577a4SJonathan Peyton     num_lines = 4; // 3, 4 cache lines
20967cc577a4SJonathan Peyton   } else if ((idx >>= 2) == 0) {
20977cc577a4SJonathan Peyton     index = 2; // idx is [ 4, 15 ], use third free list
20987cc577a4SJonathan Peyton     num_lines = 16; // 5, 6, ..., 16 cache lines
20997cc577a4SJonathan Peyton   } else if ((idx >>= 2) == 0) {
21007cc577a4SJonathan Peyton     index = 3; // idx is [ 16, 63 ], use fourth free list
21017cc577a4SJonathan Peyton     num_lines = 64; // 17, 18, ..., 64 cache lines
21027cc577a4SJonathan Peyton   } else {
21037cc577a4SJonathan Peyton     goto alloc_call; // 65 or more cache lines ( > 8KB ), don't use free lists
21047cc577a4SJonathan Peyton   }
21057cc577a4SJonathan Peyton 
21067cc577a4SJonathan Peyton   ptr = this_thr->th.th_free_lists[index].th_free_list_self;
21077cc577a4SJonathan Peyton   if (ptr != NULL) {
21087cc577a4SJonathan Peyton     // pop the head of no-sync free list
21097cc577a4SJonathan Peyton     this_thr->th.th_free_lists[index].th_free_list_self = *((void **)ptr);
2110309b00a4SShilei Tian     KMP_DEBUG_ASSERT(this_thr == ((kmp_mem_descr_t *)((kmp_uintptr_t)ptr -
2111309b00a4SShilei Tian                                                       sizeof(kmp_mem_descr_t)))
21123041982dSJonathan Peyton                                      ->ptr_aligned);
21137cc577a4SJonathan Peyton     goto end;
2114bd3a7633SJonathan Peyton   }
21157cc577a4SJonathan Peyton   ptr = TCR_SYNC_PTR(this_thr->th.th_free_lists[index].th_free_list_sync);
21167cc577a4SJonathan Peyton   if (ptr != NULL) {
21173041982dSJonathan Peyton     // no-sync free list is empty, use sync free list (filled in by other
21183041982dSJonathan Peyton     // threads only)
21197cc577a4SJonathan Peyton     // pop the head of the sync free list, push NULL instead
21207cc577a4SJonathan Peyton     while (!KMP_COMPARE_AND_STORE_PTR(
21215ba90c79SAndrey Churbanov         &this_thr->th.th_free_lists[index].th_free_list_sync, ptr, nullptr)) {
21227cc577a4SJonathan Peyton       KMP_CPU_PAUSE();
21237cc577a4SJonathan Peyton       ptr = TCR_SYNC_PTR(this_thr->th.th_free_lists[index].th_free_list_sync);
21247cc577a4SJonathan Peyton     }
21253041982dSJonathan Peyton     // push the rest of chain into no-sync free list (can be NULL if there was
21263041982dSJonathan Peyton     // the only block)
21277cc577a4SJonathan Peyton     this_thr->th.th_free_lists[index].th_free_list_self = *((void **)ptr);
2128309b00a4SShilei Tian     KMP_DEBUG_ASSERT(this_thr == ((kmp_mem_descr_t *)((kmp_uintptr_t)ptr -
2129309b00a4SShilei Tian                                                       sizeof(kmp_mem_descr_t)))
21303041982dSJonathan Peyton                                      ->ptr_aligned);
21317cc577a4SJonathan Peyton     goto end;
21327cc577a4SJonathan Peyton   }
21337cc577a4SJonathan Peyton 
21347cc577a4SJonathan Peyton alloc_call:
21357cc577a4SJonathan Peyton   // haven't found block in the free lists, thus allocate it
21367cc577a4SJonathan Peyton   size = num_lines * DCACHE_LINE;
21377cc577a4SJonathan Peyton 
21387cc577a4SJonathan Peyton   alloc_size = size + sizeof(kmp_mem_descr_t) + DCACHE_LINE;
21393041982dSJonathan Peyton   KE_TRACE(25, ("__kmp_fast_allocate: T#%d Calling __kmp_thread_malloc with "
21403041982dSJonathan Peyton                 "alloc_size %d\n",
21417cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr), alloc_size));
21427cc577a4SJonathan Peyton   alloc_ptr = bget(this_thr, (bufsize)alloc_size);
21437cc577a4SJonathan Peyton 
21447cc577a4SJonathan Peyton   // align ptr to DCACHE_LINE
21453041982dSJonathan Peyton   ptr = (void *)((((kmp_uintptr_t)alloc_ptr) + sizeof(kmp_mem_descr_t) +
21463041982dSJonathan Peyton                   DCACHE_LINE) &
21473041982dSJonathan Peyton                  ~(DCACHE_LINE - 1));
21487cc577a4SJonathan Peyton   descr = (kmp_mem_descr_t *)(((kmp_uintptr_t)ptr) - sizeof(kmp_mem_descr_t));
21497cc577a4SJonathan Peyton 
21507cc577a4SJonathan Peyton   descr->ptr_allocated = alloc_ptr; // remember allocated pointer
21517cc577a4SJonathan Peyton   // we don't need size_allocated
21527cc577a4SJonathan Peyton   descr->ptr_aligned = (void *)this_thr; // remember allocating thread
21537cc577a4SJonathan Peyton   // (it is already saved in bget buffer,
21547cc577a4SJonathan Peyton   // but we may want to use another allocator in future)
21557cc577a4SJonathan Peyton   descr->size_aligned = size;
21567cc577a4SJonathan Peyton 
21577cc577a4SJonathan Peyton end:
21587cc577a4SJonathan Peyton   KE_TRACE(25, ("<- __kmp_fast_allocate( T#%d ) returns %p\n",
21597cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr), ptr));
21607cc577a4SJonathan Peyton   return ptr;
21617cc577a4SJonathan Peyton } // func __kmp_fast_allocate
21627cc577a4SJonathan Peyton 
21637cc577a4SJonathan Peyton // Free fast memory and place it on the thread's free list if it is of
21647cc577a4SJonathan Peyton // the correct size.
___kmp_fast_free(kmp_info_t * this_thr,void * ptr KMP_SRC_LOC_DECL)21653041982dSJonathan Peyton void ___kmp_fast_free(kmp_info_t *this_thr, void *ptr KMP_SRC_LOC_DECL) {
21667cc577a4SJonathan Peyton   kmp_mem_descr_t *descr;
21677cc577a4SJonathan Peyton   kmp_info_t *alloc_thr;
21687cc577a4SJonathan Peyton   size_t size;
21697cc577a4SJonathan Peyton   size_t idx;
21707cc577a4SJonathan Peyton   int index;
21717cc577a4SJonathan Peyton 
21727cc577a4SJonathan Peyton   KE_TRACE(25, ("-> __kmp_fast_free( T#%d, %p ) called from %s:%d\n",
21737cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr), ptr KMP_SRC_LOC_PARM));
21747cc577a4SJonathan Peyton   KMP_ASSERT(ptr != NULL);
21757cc577a4SJonathan Peyton 
21767cc577a4SJonathan Peyton   descr = (kmp_mem_descr_t *)(((kmp_uintptr_t)ptr) - sizeof(kmp_mem_descr_t));
21777cc577a4SJonathan Peyton 
21787cc577a4SJonathan Peyton   KE_TRACE(26, ("   __kmp_fast_free:     size_aligned=%d\n",
21797cc577a4SJonathan Peyton                 (int)descr->size_aligned));
21807cc577a4SJonathan Peyton 
21817cc577a4SJonathan Peyton   size = descr->size_aligned; // 2, 4, 16, 64, 65, 66, ... cache lines
21827cc577a4SJonathan Peyton 
21837cc577a4SJonathan Peyton   idx = DCACHE_LINE * 2; // 2 cache lines is minimal size of block
21847cc577a4SJonathan Peyton   if (idx == size) {
21857cc577a4SJonathan Peyton     index = 0; // 2 cache lines
21867cc577a4SJonathan Peyton   } else if ((idx <<= 1) == size) {
21877cc577a4SJonathan Peyton     index = 1; // 4 cache lines
21887cc577a4SJonathan Peyton   } else if ((idx <<= 2) == size) {
21897cc577a4SJonathan Peyton     index = 2; // 16 cache lines
21907cc577a4SJonathan Peyton   } else if ((idx <<= 2) == size) {
21917cc577a4SJonathan Peyton     index = 3; // 64 cache lines
21927cc577a4SJonathan Peyton   } else {
21937cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(size > DCACHE_LINE * 64);
21947cc577a4SJonathan Peyton     goto free_call; // 65 or more cache lines ( > 8KB )
21957cc577a4SJonathan Peyton   }
21967cc577a4SJonathan Peyton 
21977cc577a4SJonathan Peyton   alloc_thr = (kmp_info_t *)descr->ptr_aligned; // get thread owning the block
21987cc577a4SJonathan Peyton   if (alloc_thr == this_thr) {
21997cc577a4SJonathan Peyton     // push block to self no-sync free list, linking previous head (LIFO)
22007cc577a4SJonathan Peyton     *((void **)ptr) = this_thr->th.th_free_lists[index].th_free_list_self;
22017cc577a4SJonathan Peyton     this_thr->th.th_free_lists[index].th_free_list_self = ptr;
22027cc577a4SJonathan Peyton   } else {
22037cc577a4SJonathan Peyton     void *head = this_thr->th.th_free_lists[index].th_free_list_other;
22047cc577a4SJonathan Peyton     if (head == NULL) {
22057cc577a4SJonathan Peyton       // Create new free list
22067cc577a4SJonathan Peyton       this_thr->th.th_free_lists[index].th_free_list_other = ptr;
22077cc577a4SJonathan Peyton       *((void **)ptr) = NULL; // mark the tail of the list
22087cc577a4SJonathan Peyton       descr->size_allocated = (size_t)1; // head of the list keeps its length
22097cc577a4SJonathan Peyton     } else {
22107cc577a4SJonathan Peyton       // need to check existed "other" list's owner thread and size of queue
22113041982dSJonathan Peyton       kmp_mem_descr_t *dsc =
22123041982dSJonathan Peyton           (kmp_mem_descr_t *)((char *)head - sizeof(kmp_mem_descr_t));
22133041982dSJonathan Peyton       // allocating thread, same for all queue nodes
22143041982dSJonathan Peyton       kmp_info_t *q_th = (kmp_info_t *)(dsc->ptr_aligned);
22153041982dSJonathan Peyton       size_t q_sz =
22163041982dSJonathan Peyton           dsc->size_allocated + 1; // new size in case we add current task
22177cc577a4SJonathan Peyton       if (q_th == alloc_thr && q_sz <= KMP_FREE_LIST_LIMIT) {
22187cc577a4SJonathan Peyton         // we can add current task to "other" list, no sync needed
22197cc577a4SJonathan Peyton         *((void **)ptr) = head;
22207cc577a4SJonathan Peyton         descr->size_allocated = q_sz;
22217cc577a4SJonathan Peyton         this_thr->th.th_free_lists[index].th_free_list_other = ptr;
22227cc577a4SJonathan Peyton       } else {
22237cc577a4SJonathan Peyton         // either queue blocks owner is changing or size limit exceeded
222442016791SKazuaki Ishizaki         // return old queue to allocating thread (q_th) synchronously,
22257cc577a4SJonathan Peyton         // and start new list for alloc_thr's tasks
22267cc577a4SJonathan Peyton         void *old_ptr;
22277cc577a4SJonathan Peyton         void *tail = head;
22287cc577a4SJonathan Peyton         void *next = *((void **)head);
22297cc577a4SJonathan Peyton         while (next != NULL) {
22307cc577a4SJonathan Peyton           KMP_DEBUG_ASSERT(
22317cc577a4SJonathan Peyton               // queue size should decrease by 1 each step through the list
22323041982dSJonathan Peyton               ((kmp_mem_descr_t *)((char *)next - sizeof(kmp_mem_descr_t)))
22333041982dSJonathan Peyton                       ->size_allocated +
22343041982dSJonathan Peyton                   1 ==
22353041982dSJonathan Peyton               ((kmp_mem_descr_t *)((char *)tail - sizeof(kmp_mem_descr_t)))
22363041982dSJonathan Peyton                   ->size_allocated);
22377cc577a4SJonathan Peyton           tail = next; // remember tail node
22387cc577a4SJonathan Peyton           next = *((void **)next);
22397cc577a4SJonathan Peyton         }
22407cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(q_th != NULL);
22417cc577a4SJonathan Peyton         // push block to owner's sync free list
22427cc577a4SJonathan Peyton         old_ptr = TCR_PTR(q_th->th.th_free_lists[index].th_free_list_sync);
22437cc577a4SJonathan Peyton         /* the next pointer must be set before setting free_list to ptr to avoid
22447cc577a4SJonathan Peyton            exposing a broken list to other threads, even for an instant. */
22457cc577a4SJonathan Peyton         *((void **)tail) = old_ptr;
22467cc577a4SJonathan Peyton 
22477cc577a4SJonathan Peyton         while (!KMP_COMPARE_AND_STORE_PTR(
22483041982dSJonathan Peyton             &q_th->th.th_free_lists[index].th_free_list_sync, old_ptr, head)) {
22497cc577a4SJonathan Peyton           KMP_CPU_PAUSE();
22507cc577a4SJonathan Peyton           old_ptr = TCR_PTR(q_th->th.th_free_lists[index].th_free_list_sync);
22517cc577a4SJonathan Peyton           *((void **)tail) = old_ptr;
22527cc577a4SJonathan Peyton         }
22537cc577a4SJonathan Peyton 
22547cc577a4SJonathan Peyton         // start new list of not-selt tasks
22557cc577a4SJonathan Peyton         this_thr->th.th_free_lists[index].th_free_list_other = ptr;
22567cc577a4SJonathan Peyton         *((void **)ptr) = NULL;
22577cc577a4SJonathan Peyton         descr->size_allocated = (size_t)1; // head of queue keeps its length
22587cc577a4SJonathan Peyton       }
22597cc577a4SJonathan Peyton     }
22607cc577a4SJonathan Peyton   }
22617cc577a4SJonathan Peyton   goto end;
22627cc577a4SJonathan Peyton 
22637cc577a4SJonathan Peyton free_call:
22647cc577a4SJonathan Peyton   KE_TRACE(25, ("__kmp_fast_free: T#%d Calling __kmp_thread_free for size %d\n",
22657cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr), size));
22667cc577a4SJonathan Peyton   __kmp_bget_dequeue(this_thr); /* Release any queued buffers */
22677cc577a4SJonathan Peyton   brel(this_thr, descr->ptr_allocated);
22687cc577a4SJonathan Peyton 
22697cc577a4SJonathan Peyton end:
22707cc577a4SJonathan Peyton   KE_TRACE(25, ("<- __kmp_fast_free() returns\n"));
22717cc577a4SJonathan Peyton 
22727cc577a4SJonathan Peyton } // func __kmp_fast_free
22737cc577a4SJonathan Peyton 
22747cc577a4SJonathan Peyton // Initialize the thread free lists related to fast memory
22757cc577a4SJonathan Peyton // Only do this when a thread is initially created.
__kmp_initialize_fast_memory(kmp_info_t * this_thr)22763041982dSJonathan Peyton void __kmp_initialize_fast_memory(kmp_info_t *this_thr) {
22777cc577a4SJonathan Peyton   KE_TRACE(10, ("__kmp_initialize_fast_memory: Called from th %p\n", this_thr));
22787cc577a4SJonathan Peyton 
22797cc577a4SJonathan Peyton   memset(this_thr->th.th_free_lists, 0, NUM_LISTS * sizeof(kmp_free_list_t));
22807cc577a4SJonathan Peyton }
22817cc577a4SJonathan Peyton 
22827cc577a4SJonathan Peyton // Free the memory in the thread free lists related to fast memory
22837cc577a4SJonathan Peyton // Only do this when a thread is being reaped (destroyed).
__kmp_free_fast_memory(kmp_info_t * th)22843041982dSJonathan Peyton void __kmp_free_fast_memory(kmp_info_t *th) {
22857cc577a4SJonathan Peyton   // Suppose we use BGET underlying allocator, walk through its structures...
22867cc577a4SJonathan Peyton   int bin;
22877cc577a4SJonathan Peyton   thr_data_t *thr = get_thr_data(th);
22887cc577a4SJonathan Peyton   void **lst = NULL;
22897cc577a4SJonathan Peyton 
22903041982dSJonathan Peyton   KE_TRACE(
22913041982dSJonathan Peyton       5, ("__kmp_free_fast_memory: Called T#%d\n", __kmp_gtid_from_thread(th)));
22927cc577a4SJonathan Peyton 
22937cc577a4SJonathan Peyton   __kmp_bget_dequeue(th); // Release any queued buffers
22947cc577a4SJonathan Peyton 
22957cc577a4SJonathan Peyton   // Dig through free lists and extract all allocated blocks
22967cc577a4SJonathan Peyton   for (bin = 0; bin < MAX_BGET_BINS; ++bin) {
22977cc577a4SJonathan Peyton     bfhead_t *b = thr->freelist[bin].ql.flink;
22987cc577a4SJonathan Peyton     while (b != &thr->freelist[bin]) {
22993041982dSJonathan Peyton       if ((kmp_uintptr_t)b->bh.bb.bthr & 1) { // the buffer is allocated address
23003041982dSJonathan Peyton         *((void **)b) =
23013041982dSJonathan Peyton             lst; // link the list (override bthr, but keep flink yet)
23027cc577a4SJonathan Peyton         lst = (void **)b; // push b into lst
23037cc577a4SJonathan Peyton       }
23047cc577a4SJonathan Peyton       b = b->ql.flink; // get next buffer
23057cc577a4SJonathan Peyton     }
23067cc577a4SJonathan Peyton   }
23077cc577a4SJonathan Peyton   while (lst != NULL) {
23087cc577a4SJonathan Peyton     void *next = *lst;
23097cc577a4SJonathan Peyton     KE_TRACE(10, ("__kmp_free_fast_memory: freeing %p, next=%p th %p (%d)\n",
23107cc577a4SJonathan Peyton                   lst, next, th, __kmp_gtid_from_thread(th)));
23117cc577a4SJonathan Peyton     (*thr->relfcn)(lst);
23127cc577a4SJonathan Peyton #if BufStats
23137cc577a4SJonathan Peyton     // count blocks to prevent problems in __kmp_finalize_bget()
23147cc577a4SJonathan Peyton     thr->numprel++; /* Nr of expansion block releases */
23157cc577a4SJonathan Peyton     thr->numpblk--; /* Total number of blocks */
23167cc577a4SJonathan Peyton #endif
23177cc577a4SJonathan Peyton     lst = (void **)next;
23187cc577a4SJonathan Peyton   }
23197cc577a4SJonathan Peyton 
23203041982dSJonathan Peyton   KE_TRACE(
23213041982dSJonathan Peyton       5, ("__kmp_free_fast_memory: Freed T#%d\n", __kmp_gtid_from_thread(th)));
23227cc577a4SJonathan Peyton }
23237cc577a4SJonathan Peyton 
23247cc577a4SJonathan Peyton #endif // USE_FAST_MEMORY
2325