mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			597 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			597 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
 | 
						|
   Copyright (c) 2019, 2020 IBM.
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation; version 2 of the License.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
 | 
						|
 | 
						|
#include "mysys_priv.h"
 | 
						|
#include <mysys_err.h>
 | 
						|
 | 
						|
#ifdef __linux__
 | 
						|
#include <dirent.h>
 | 
						|
#endif
 | 
						|
#if defined(__linux__) || defined(MAP_ALIGNED)
 | 
						|
#include "my_bit.h"
 | 
						|
#endif
 | 
						|
#ifdef HAVE_LINUX_MMAN_H
 | 
						|
#include <linux/mman.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_SOLARIS_LARGE_PAGES
 | 
						|
#if defined(__sun__) && defined(__GNUC__) && defined(__cplusplus) \
 | 
						|
    && defined(_XOPEN_SOURCE)
 | 
						|
/* memcntl exist within sys/mman.h, but under-defines what is need to use it */
 | 
						|
extern int memcntl(caddr_t, size_t, int, caddr_t, int, int);
 | 
						|
#endif /* __sun__ ... */
 | 
						|
#endif /* HAVE_SOLARIS_LARGE_PAGES */
 | 
						|
 | 
						|
 | 
						|
my_bool my_use_large_pages;
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
static size_t my_large_page_size;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(HAVE_GETPAGESIZES) || defined(__linux__)
 | 
						|
/* Descending sort */
 | 
						|
 | 
						|
static int size_t_cmp(const void *a, const void *b)
 | 
						|
{
 | 
						|
  const size_t ia= *(const size_t *) a;
 | 
						|
  const size_t ib= *(const size_t *) b;
 | 
						|
  if (ib > ia)
 | 
						|
  {
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  else if (ib < ia)
 | 
						|
  {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
#endif /* defined(HAVE_GETPAGESIZES) || defined(__linux__) */
 | 
						|
 | 
						|
 | 
						|
#if defined(__linux__) || defined(HAVE_GETPAGESIZES)
 | 
						|
#define my_large_page_sizes_length 8
 | 
						|
static size_t my_large_page_sizes[my_large_page_sizes_length];
 | 
						|
#endif
 | 
						|
 | 
						|
/**
 | 
						|
  Linux-specific function to determine the sizes of large pages
 | 
						|
*/
 | 
						|
#ifdef __linux__
 | 
						|
static inline my_bool my_is_2pow(size_t n) { return !((n) & ((n) - 1)); }
 | 
						|
 | 
						|
static void my_get_large_page_sizes(size_t sizes[my_large_page_sizes_length])
 | 
						|
{
 | 
						|
  DIR *dirp;
 | 
						|
  struct dirent *r;
 | 
						|
  int i= 0;
 | 
						|
  DBUG_ENTER("my_get_large_page_sizes");
 | 
						|
 | 
						|
  dirp= opendir("/sys/kernel/mm/hugepages");
 | 
						|
  if (dirp == NULL)
 | 
						|
  {
 | 
						|
    my_error(EE_DIR, MYF(ME_BELL), "/sys/kernel/mm/hugepages", errno);
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    while (i < my_large_page_sizes_length && (r= readdir(dirp)))
 | 
						|
    {
 | 
						|
      if (strncmp("hugepages-", r->d_name, 10) == 0)
 | 
						|
      {
 | 
						|
        sizes[i]= strtoull(r->d_name + 10, NULL, 10) * 1024ULL;
 | 
						|
        if (!my_is_2pow(sizes[i]))
 | 
						|
        {
 | 
						|
          my_printf_error(0,
 | 
						|
                          "non-power of 2 large page size (%zu) found,"
 | 
						|
                          " skipping", MYF(ME_NOTE | ME_ERROR_LOG_ONLY),
 | 
						|
                          sizes[i]);
 | 
						|
          sizes[i]= 0;
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        ++i;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (closedir(dirp))
 | 
						|
    {
 | 
						|
      my_error(EE_BADCLOSE, MYF(ME_BELL), "/sys/kernel/mm/hugepages", errno);
 | 
						|
    }
 | 
						|
    qsort(sizes, i, sizeof(size_t), size_t_cmp);
 | 
						|
  }
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#elif defined(HAVE_GETPAGESIZES)
 | 
						|
static void my_get_large_page_sizes(size_t sizes[my_large_page_sizes_length])
 | 
						|
{
 | 
						|
  int nelem;
 | 
						|
 | 
						|
  nelem= getpagesizes(NULL, 0);
 | 
						|
 | 
						|
  assert(nelem <= my_large_page_sizes_length);
 | 
						|
  getpagesizes(sizes, my_large_page_sizes_length);
 | 
						|
  qsort(sizes, nelem, sizeof(size_t), size_t_cmp);
 | 
						|
  if (nelem < my_large_page_sizes_length)
 | 
						|
  {
 | 
						|
    sizes[nelem]= 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#elif defined(_WIN32)
 | 
						|
#define my_large_page_sizes_length 0
 | 
						|
#define my_get_large_page_sizes(A) do {} while(0)
 | 
						|
 | 
						|
#else
 | 
						|
#define my_large_page_sizes_length 1
 | 
						|
static size_t my_large_page_sizes[my_large_page_sizes_length];
 | 
						|
static void my_get_large_page_sizes(size_t sizes[])
 | 
						|
{
 | 
						|
  sizes[0]= my_getpagesize();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the next large page size smaller or equal to the passed in size.
 | 
						|
 | 
						|
  The search starts at my_large_page_sizes[*start].
 | 
						|
 | 
						|
  Assumes my_get_large_page_sizes(my_large_page_sizes) has been called before
 | 
						|
  use.
 | 
						|
 | 
						|
  For first use, have *start=0. There is no need to increment *start.
 | 
						|
 | 
						|
  @param[in]     sz size to be searched for.
 | 
						|
  @param[in,out] start ptr to int representing offset in my_large_page_sizes to
 | 
						|
                       start from.
 | 
						|
  *start is updated during search and can be used to search again if 0 isn't
 | 
						|
  returned.
 | 
						|
 | 
						|
  @returns the next size found. *start will be incremented to the next potential
 | 
						|
           size.
 | 
						|
  @retval  a large page size that is valid on this system or 0 if no large page
 | 
						|
           size possible.
 | 
						|
*/
 | 
						|
#ifndef _WIN32
 | 
						|
static size_t my_next_large_page_size(size_t sz, int *start)
 | 
						|
{
 | 
						|
  DBUG_ENTER("my_next_large_page_size");
 | 
						|
 | 
						|
  while (*start < my_large_page_sizes_length && my_large_page_sizes[*start] > 0)
 | 
						|
  {
 | 
						|
    size_t cur= *start;
 | 
						|
    (*start)++;
 | 
						|
    if (my_large_page_sizes[cur] <= sz)
 | 
						|
    {
 | 
						|
      DBUG_RETURN(my_large_page_sizes[cur]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
int my_init_large_pages(void)
 | 
						|
{
 | 
						|
  my_use_large_pages= 1;
 | 
						|
#ifdef _WIN32
 | 
						|
  if (!my_obtain_privilege(SE_LOCK_MEMORY_NAME))
 | 
						|
  {
 | 
						|
    my_printf_error(EE_PERM_LOCK_MEMORY,
 | 
						|
                    "Lock Pages in memory access rights required for use with"
 | 
						|
                    " large-pages, see https://mariadb.com/kb/en/library/"
 | 
						|
                    "mariadb-memory-allocation/#huge-pages", MYF(MY_WME));
 | 
						|
    my_use_large_pages= 0;
 | 
						|
  }
 | 
						|
  my_large_page_size= GetLargePageMinimum();
 | 
						|
#endif
 | 
						|
 | 
						|
  my_get_large_page_sizes(my_large_page_sizes);
 | 
						|
 | 
						|
#ifdef HAVE_SOLARIS_LARGE_PAGES
 | 
						|
  extern my_bool opt_super_large_pages;
 | 
						|
  /*
 | 
						|
    tell the kernel that we want to use 4/256MB page for heap storage
 | 
						|
    and also for the stack. We use 4 MByte as default and if the
 | 
						|
    super-large-page is set we increase it to 256 MByte. 256 MByte
 | 
						|
    is for server installations with GBytes of RAM memory where
 | 
						|
    the MySQL Server will have page caches and other memory regions
 | 
						|
    measured in a number of GBytes.
 | 
						|
    We use as big pages as possible which isn't bigger than the above
 | 
						|
    desired page sizes.
 | 
						|
 | 
						|
    Note: This refers to some implementations of the SPARC ISA,
 | 
						|
    where the supported page sizes are
 | 
						|
    8KiB, 64KiB, 512KiB, 4MiB, 32MiB, 256MiB, 2GiB, and 16GiB.
 | 
						|
    On implementations of the AMD64 ISA, the available page sizes
 | 
						|
    should be 4KiB, 2MiB, and 1GiB.
 | 
						|
  */
 | 
						|
  int nelem= 0;
 | 
						|
  size_t max_desired_page_size= opt_super_large_pages ? 256 << 20 : 4 << 20;
 | 
						|
  size_t max_page_size= my_next_large_page_size(max_desired_page_size, &nelem);
 | 
						|
 | 
						|
  if (max_page_size > 0)
 | 
						|
  {
 | 
						|
    struct memcntl_mha mpss;
 | 
						|
 | 
						|
    mpss.mha_cmd= MHA_MAPSIZE_BSSBRK;
 | 
						|
    mpss.mha_pagesize= max_page_size;
 | 
						|
    mpss.mha_flags= 0;
 | 
						|
    if (memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t) &mpss, 0, 0))
 | 
						|
    {
 | 
						|
      my_error(EE_MEMCNTL, MYF(ME_WARNING | ME_ERROR_LOG_ONLY), "MC_HAT_ADVISE",
 | 
						|
               "MHA_MAPSIZE_BSSBRK");
 | 
						|
    }
 | 
						|
    mpss.mha_cmd= MHA_MAPSIZE_STACK;
 | 
						|
    if (memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t) &mpss, 0, 0))
 | 
						|
    {
 | 
						|
      my_error(EE_MEMCNTL, MYF(ME_WARNING | ME_ERROR_LOG_ONLY), "MC_HAT_ADVISE",
 | 
						|
               "MHA_MAPSIZE_STACK");
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif /* HAVE_SOLARIS_LARGE_PAGES */
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
   Large page size helper.
 | 
						|
   This rounds down, if needed, the size parameter to the largest
 | 
						|
   multiple of an available large page size on the system.
 | 
						|
*/
 | 
						|
void my_large_page_truncate(size_t *size)
 | 
						|
{
 | 
						|
  if (my_use_large_pages)
 | 
						|
  {
 | 
						|
    size_t large_page_size= 0;
 | 
						|
#ifdef _WIN32
 | 
						|
    large_page_size= my_large_page_size;
 | 
						|
#elif defined(HAVE_MMAP)
 | 
						|
    int page_i= 0;
 | 
						|
    large_page_size= my_next_large_page_size(*size, &page_i);
 | 
						|
#endif
 | 
						|
    if (large_page_size > 0)
 | 
						|
      *size-= *size % large_page_size;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if defined(HAVE_MMAP) && !defined(_WIN32)
 | 
						|
/* Solaris for example has only MAP_ANON, FreeBSD has MAP_ANONYMOUS and
 | 
						|
MAP_ANON but MAP_ANONYMOUS is marked "for compatibility" */
 | 
						|
#if defined(MAP_ANONYMOUS)
 | 
						|
#define OS_MAP_ANON     MAP_ANONYMOUS
 | 
						|
#elif defined(MAP_ANON)
 | 
						|
#define OS_MAP_ANON     MAP_ANON
 | 
						|
#else
 | 
						|
#error unsupported mmap - no MAP_ANON{YMOUS}
 | 
						|
#endif
 | 
						|
#endif /* HAVE_MMAP && !_WIN32 */
 | 
						|
 | 
						|
/**
 | 
						|
  General large pages allocator.
 | 
						|
  Tries to allocate memory from large pages pool and falls back to
 | 
						|
  my_malloc_lock() in case of failure.
 | 
						|
  Every implementation returns a zero filled buffer here.
 | 
						|
*/
 | 
						|
uchar *my_large_malloc(size_t *size, myf my_flags)
 | 
						|
{
 | 
						|
  uchar *ptr= NULL;
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
  DWORD alloc_type= MEM_COMMIT | MEM_RESERVE;
 | 
						|
  size_t orig_size= *size;
 | 
						|
  DBUG_ENTER("my_large_malloc");
 | 
						|
 | 
						|
  if (my_use_large_pages)
 | 
						|
  {
 | 
						|
    alloc_type|= MEM_LARGE_PAGES;
 | 
						|
    /* Align block size to my_large_page_size */
 | 
						|
    *size= MY_ALIGN(*size, (size_t) my_large_page_size);
 | 
						|
  }
 | 
						|
  ptr= VirtualAlloc(NULL, *size, alloc_type, PAGE_READWRITE);
 | 
						|
  if (!ptr)
 | 
						|
  {
 | 
						|
    if (my_flags & MY_WME)
 | 
						|
    {
 | 
						|
      if (my_use_large_pages)
 | 
						|
      {
 | 
						|
        my_printf_error(EE_OUTOFMEMORY,
 | 
						|
                        "Couldn't allocate %zu bytes (MEM_LARGE_PAGES page "
 | 
						|
                        "size %zu); Windows error %lu",
 | 
						|
                        MYF(ME_WARNING | ME_ERROR_LOG_ONLY), *size,
 | 
						|
                        my_large_page_size, GetLastError());
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_ERROR_LOG), *size);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (my_use_large_pages)
 | 
						|
    {
 | 
						|
      *size= orig_size;
 | 
						|
      ptr= VirtualAlloc(NULL, *size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 | 
						|
      if (!ptr && my_flags & MY_WME)
 | 
						|
      {
 | 
						|
        my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_ERROR_LOG), *size);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
#elif defined(HAVE_MMAP)
 | 
						|
  int mapflag;
 | 
						|
  int page_i= 0;
 | 
						|
  size_t large_page_size= 0;
 | 
						|
  size_t aligned_size= *size;
 | 
						|
  DBUG_ENTER("my_large_malloc");
 | 
						|
 | 
						|
  while (1)
 | 
						|
  {
 | 
						|
    mapflag= MAP_PRIVATE | OS_MAP_ANON;
 | 
						|
    if (my_use_large_pages)
 | 
						|
    {
 | 
						|
      large_page_size= my_next_large_page_size(*size, &page_i);
 | 
						|
      /* this might be 0, in which case we do a standard mmap */
 | 
						|
      if (large_page_size)
 | 
						|
      {
 | 
						|
#if defined(MAP_HUGETLB) /* linux 2.6.32 */
 | 
						|
        mapflag|= MAP_HUGETLB;
 | 
						|
#if defined(MAP_HUGE_SHIFT) /* Linux-3.8+ */
 | 
						|
        mapflag|= my_bit_log2_size_t(large_page_size) << MAP_HUGE_SHIFT;
 | 
						|
#else
 | 
						|
# warning "No explicit large page (HUGETLB pages) support in Linux < 3.8"
 | 
						|
#endif
 | 
						|
#elif defined(MAP_ALIGNED)
 | 
						|
        mapflag|= MAP_ALIGNED(my_bit_log2_size_t(large_page_size));
 | 
						|
#if defined(MAP_ALIGNED_SUPER)
 | 
						|
        mapflag|= MAP_ALIGNED_SUPER;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
        aligned_size= MY_ALIGN(*size, (size_t) large_page_size);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        aligned_size= *size;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    ptr= mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, mapflag, -1, 0);
 | 
						|
    if (ptr == (void*) -1)
 | 
						|
    {
 | 
						|
      ptr= NULL;
 | 
						|
      if (my_flags & MY_WME)
 | 
						|
      {
 | 
						|
        if (large_page_size && errno == ENOMEM)
 | 
						|
        {
 | 
						|
          my_printf_error(EE_OUTOFMEMORY,
 | 
						|
                          "Couldn't allocate %zu bytes (Large/HugeTLB memory "
 | 
						|
                          "page size %zu); errno %u; continuing to smaller size",
 | 
						|
                          MYF(ME_WARNING | ME_ERROR_LOG_ONLY),
 | 
						|
                          aligned_size, large_page_size, errno);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_ERROR_LOG), aligned_size);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      /* try next smaller memory size */
 | 
						|
      if (large_page_size && errno == ENOMEM)
 | 
						|
        continue;
 | 
						|
 | 
						|
      /* other errors are more serious */
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    else /* success */
 | 
						|
    {
 | 
						|
      if (large_page_size)
 | 
						|
      {
 | 
						|
        /*
 | 
						|
          we do need to record the adjustment so that munmap gets called with
 | 
						|
          the right size. This is only the case for HUGETLB pages.
 | 
						|
        */
 | 
						|
        *size= aligned_size;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (large_page_size == 0)
 | 
						|
    {
 | 
						|
      break; /* no more options to try */
 | 
						|
    }
 | 
						|
  }
 | 
						|
#else
 | 
						|
  DBUG_RETURN(my_malloc_lock(*size, my_flags));
 | 
						|
#endif /* defined(HAVE_MMAP) */
 | 
						|
 | 
						|
  if (ptr != NULL)
 | 
						|
  {
 | 
						|
    MEM_MAKE_DEFINED(ptr, *size);
 | 
						|
    update_malloc_size(*size, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  DBUG_RETURN(ptr);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
/**
 | 
						|
  Special large pages allocator, with possibility to commit to allocating
 | 
						|
  more memory later.
 | 
						|
  Every implementation returns a zero filled buffer here.
 | 
						|
*/
 | 
						|
char *my_large_virtual_alloc(size_t *size)
 | 
						|
{
 | 
						|
  char *ptr;
 | 
						|
  DBUG_ENTER("my_large_virtual_alloc");
 | 
						|
 | 
						|
  if (my_use_large_pages)
 | 
						|
  {
 | 
						|
    size_t s= *size;
 | 
						|
    s= MY_ALIGN(s, (size_t) my_large_page_size);
 | 
						|
    ptr= VirtualAlloc(NULL, s, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES,
 | 
						|
                      PAGE_READWRITE);
 | 
						|
    if (ptr)
 | 
						|
    {
 | 
						|
      *size= s;
 | 
						|
      DBUG_RETURN(ptr);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DBUG_RETURN(VirtualAlloc(NULL, *size, MEM_RESERVE, PAGE_READWRITE));
 | 
						|
}
 | 
						|
#elif defined HAVE_MMAP
 | 
						|
/**
 | 
						|
  Special large pages allocator, with possibility to commit to allocating
 | 
						|
  more memory later.
 | 
						|
  Every implementation returns a zero filled buffer here.
 | 
						|
*/
 | 
						|
char *my_large_mmap(size_t *size, int prot)
 | 
						|
{
 | 
						|
  char *ptr;
 | 
						|
  DBUG_ENTER("my_large_virtual_alloc");
 | 
						|
 | 
						|
  if (my_use_large_pages)
 | 
						|
  {
 | 
						|
    size_t large_page_size;
 | 
						|
    int page_i= 0;
 | 
						|
    prot= PROT_READ | PROT_WRITE;
 | 
						|
 | 
						|
    while ((large_page_size= my_next_large_page_size(*size, &page_i)) != 0)
 | 
						|
    {
 | 
						|
      int mapflag= MAP_PRIVATE |
 | 
						|
# ifdef MAP_POPULATE
 | 
						|
        MAP_POPULATE |
 | 
						|
# endif
 | 
						|
# if defined MAP_HUGETLB /* linux 2.6.32 */
 | 
						|
        MAP_HUGETLB |
 | 
						|
#  if defined MAP_HUGE_SHIFT /* Linux-3.8+ */
 | 
						|
        my_bit_log2_size_t(large_page_size) << MAP_HUGE_SHIFT |
 | 
						|
#  else
 | 
						|
#   warning "No explicit large page (HUGETLB pages) support in Linux < 3.8"
 | 
						|
#  endif
 | 
						|
# elif defined MAP_ALIGNED
 | 
						|
        MAP_ALIGNED(my_bit_log2_size_t(large_page_size)) |
 | 
						|
#  if defined MAP_ALIGNED_SUPER
 | 
						|
        MAP_ALIGNED_SUPER |
 | 
						|
#  endif
 | 
						|
# endif
 | 
						|
        OS_MAP_ANON;
 | 
						|
 | 
						|
      size_t aligned_size= MY_ALIGN(*size, (size_t) large_page_size);
 | 
						|
      ptr= mmap(NULL, aligned_size, prot, mapflag, -1, 0);
 | 
						|
      if (ptr == (void*) -1)
 | 
						|
      {
 | 
						|
        ptr= NULL;
 | 
						|
        /* try next smaller memory size */
 | 
						|
        if (errno == ENOMEM)
 | 
						|
          continue;
 | 
						|
 | 
						|
        /* other errors are more serious */
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      else /* success */
 | 
						|
      {
 | 
						|
        /*
 | 
						|
          we do need to record the adjustment so that munmap gets called with
 | 
						|
          the right size. This is only the case for HUGETLB pages.
 | 
						|
        */
 | 
						|
        *size= aligned_size;
 | 
						|
        DBUG_RETURN(ptr);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ptr= mmap(NULL, *size, prot,
 | 
						|
# ifdef MAP_NORESERVE
 | 
						|
            MAP_NORESERVE |
 | 
						|
# endif
 | 
						|
            MAP_PRIVATE | OS_MAP_ANON, -1, 0);
 | 
						|
  if (ptr == MAP_FAILED)
 | 
						|
  {
 | 
						|
    my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
 | 
						|
    ptr= NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  DBUG_RETURN(ptr);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Special large pages allocator, with possibility to commit to allocating
 | 
						|
  more memory later.
 | 
						|
  Every implementation returns a zero filled buffer here.
 | 
						|
*/
 | 
						|
char *my_large_virtual_alloc(size_t *size)
 | 
						|
{
 | 
						|
  return my_large_mmap(size, PROT_READ | PROT_WRITE);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/**
 | 
						|
  General large pages deallocator.
 | 
						|
  Tries to deallocate memory as if it was from large pages pool and falls back
 | 
						|
  to my_free_lock() in case of failure
 | 
						|
*/
 | 
						|
void my_large_free(void *ptr, size_t size)
 | 
						|
{
 | 
						|
  DBUG_ENTER("my_large_free");
 | 
						|
 | 
						|
  /*
 | 
						|
    The following implementations can only fail if ptr was not allocated with
 | 
						|
    my_large_malloc(), i.e. my_malloc_lock() was used so we should free it
 | 
						|
    with my_free_lock()
 | 
						|
 | 
						|
    For ASAN, we need to explicitly unpoison this memory region because the OS
 | 
						|
    may reuse that memory for some TLS or stack variable. It will remain
 | 
						|
    poisoned if it was explicitly poisoned before release. If this happens,
 | 
						|
    we'll have hard to debug false positives like in MDEV-21239.
 | 
						|
    For valgrind, we mark it as UNDEFINED rather than NOACCESS because of the
 | 
						|
    implicit reuse possibility.
 | 
						|
  */
 | 
						|
#if defined(HAVE_MMAP) && !defined(_WIN32)
 | 
						|
  if (munmap(ptr, size))
 | 
						|
  {
 | 
						|
    my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size, errno);
 | 
						|
  }
 | 
						|
#if !__has_feature(memory_sanitizer)
 | 
						|
  else
 | 
						|
  {
 | 
						|
    MEM_MAKE_ADDRESSABLE(ptr, size);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  update_malloc_size(- (longlong) size, 0);
 | 
						|
#elif defined(_WIN32)
 | 
						|
  /*
 | 
						|
     When RELEASE memory, the size parameter must be 0.
 | 
						|
     Do not use MEM_RELEASE with MEM_DECOMMIT.
 | 
						|
  */
 | 
						|
  if (ptr)
 | 
						|
  {
 | 
						|
    if (!VirtualFree(ptr, 0, MEM_RELEASE))
 | 
						|
    {
 | 
						|
      my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size,
 | 
						|
               GetLastError());
 | 
						|
    }
 | 
						|
    update_malloc_size(- (longlong) size, 0);
 | 
						|
  }
 | 
						|
#if !__has_feature(memory_sanitizer)
 | 
						|
  else
 | 
						|
  {
 | 
						|
    MEM_MAKE_ADDRESSABLE(ptr, size);
 | 
						|
  }
 | 
						|
#endif /* memory_sanitizer */
 | 
						|
#else
 | 
						|
  my_free_lock(ptr);
 | 
						|
#endif /* HAVE_MMAP */
 | 
						|
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 |