Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/MariaDB/mysys/   (MariaDB Server Version 8.1-8.4©)  Datei vom 1.9.2026 mit Größe 6 kB image not shown  

Quelle  my_virtual_mem.c   Sprache: C

 

/* Copyright (c) 2025, 2026, MariaDB plc.

   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 <my_global.h>
#include <my_sys.h>
#include <mysys_err.h>
#include <my_virtual_mem.h>
#ifdef _AIX
# include <sys/shm.h>
#endif

/*
  Functionality for handling virtual memory

  - reserve range - memory is reserved, not allocated.
  - commit memory (within reserved range) - memory is allocated
  - decommit previously commited memory  - memory is deallocated, stays reserved
  - release range - reserved range is released to OS

  Not every OS has a "reserve" functionality, i.e it is not always
  possible to reserve memory larger than swap or RAM for example.

  The unfortunate terminology comes from WinAPI, see MEM_* flags below.
  It's rather confusing in the context of a database (and specifically,
  InnoDB, the only user of this functionality), but it's the established
  terminology.

  We try to respect use_large_pages setting, both on Windows and Linux
*/

char *my_virtual_mem_reserve(size_t *size)
{
#ifdef _WIN32
  DWORD flags= my_use_large_pages
    ? MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT
    : MEM_RESERVE;
  char *ptr= VirtualAlloc(NULL, *size, flags, PAGE_READWRITE);
  if (!ptr && (flags & MEM_LARGE_PAGES))
  {
    /* Try without large pages */
    ptr= VirtualAlloc(NULL, *size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if (!ptr)
      my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), *size);
  }
  return ptr;
#else
  return my_large_virtual_alloc(size);
#endif
}

#if defined _WIN32 && !defined DBUG_OFF
static my_bool is_memory_committed(char *ptr, size_t size)
{
  MEMORY_BASIC_INFORMATION mbi;
  if (VirtualQuery(ptr, &mbi, sizeof mbi) == 0)
    DBUG_ASSERT(0);
  return !!(mbi.State & MEM_COMMIT);
}
#endif

/*
  "commit" - in other words, allocate - memory.
  ptr must lie within a previously reserved range or be NULL.
  in the latter case new memory is reserved and committed.

  This is compatible with the mmap / VirtualAlloc semantics.
*/

char *my_virtual_mem_commit(char *ptr, size_t size)
{
#ifdef _WIN32
  if (!ptr)
    return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if (my_use_large_pages)
  {
    DBUG_ASSERT(is_memory_committed(ptr, size));
  }
  else
  {
    void *p= VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE);
    DBUG_ASSERT(p == ptr);
    if (!p)
    {
      my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
      return NULL;
    }
  }
#else
  if (!ptr)
  {
    void *p= mmap(NULL, size, PROT_READ | PROT_WRITE,
                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
    return p == MAP_FAILED ? NULL : p;
  }
  if (my_use_large_pages)
    /* my_large_virtual_alloc() already created a read/write mapping. */;
  else
  {
# ifdef _AIX
    /*
      MAP_FIXED does not not work on IBM AIX in the way does works elsewhere.
      Apparently, it is not possible to mmap(2) a range that is already in use,
      at least not by default.

      mprotect(2) is the fallback, it can't communicate out-of-memory
      conditions, but it looks like overcommitting is not possible on
      AIX anyway.
    */

    if (mprotect(ptr, size, PROT_READ | PROT_WRITE))
    {
      my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
      return NULL;
    }
# else
    void *p= 0;
    const int flags=
      MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
    p= mmap(ptr, size, PROT_READ | PROT_WRITE, flags, -1, 0);
    if (p == MAP_FAILED)
    {
      my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
      return NULL;
    }
    DBUG_ASSERT(p == ptr);
#  if defined MADV_FREE_REUSABLE && defined MADV_FREE_REUSE /* Apple macOS */
    madvise(ptr, size, MADV_FREE_REUSE); /* cancel MADV_FREE_REUSABLE */
#  endif
# endif
  }
#endif
  update_malloc_size(size, 0);
  return ptr;
}

void my_virtual_mem_decommit(char *ptr, size_t size)
{
#ifdef _WIN32
  DBUG_ASSERT(is_memory_committed(ptr, size));
  if (!my_use_large_pages)
  {
    if (!VirtualFree(ptr, size, MEM_DECOMMIT))
    {
      my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size,
               GetLastError());
      DBUG_ASSERT(0);
    }
  }
#else
# ifdef _AIX
  disclaim(ptr, size, DISCLAIM_ZEROMEM);
# elif defined __linux__ || defined __osf__
  madvise(ptr, size, MADV_DONTNEED); /* OSF/1, Linux mimicing AIX disclaim() */
# elif defined MADV_FREE_REUSABLE && defined MADV_FREE_REUSE
  /* Mac OS X 10.9; undocumented in Apple macOS */
  madvise(ptr, size, MADV_FREE_REUSABLE); /* macOS mimicing AIX disclaim() */
# elif defined MADV_PURGE /* Illumos */
  madvise(ptr, size, MADV_PURGE); /* Illumos mimicing AIX disclaim() */
# elif defined MADV_FREE
  /* FreeBSD, NetBSD, OpenBSD, Dragonfly BSD, OpenSolaris, Apple macOS */
  madvise(ptr, size, MADV_FREE); /* allow lazy zeroing out */
# elif defined MADV_DONTNEED
#  warning "It is unclear if madvise(MADV_DONTNEED) works as intended"
  madvise(ptr, size, MADV_DONTNEED);
# else
#  warning "Do not know how to decommit memory"
# endif
  if (mprotect(ptr, size, PROT_NONE))
  {
    my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size, errno);
    DBUG_ASSERT(0);
  }
#endif
  update_malloc_size(-(longlong) size, 0);
}

void my_virtual_mem_release(char *ptr, size_t size)
{
#ifdef _WIN32
  if (!VirtualFree(ptr, 0, MEM_RELEASE))
  {
    my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size,
             GetLastError());
    DBUG_ASSERT(0);
  }
#else
  if (munmap(ptr, size))
  {
    my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size, errno);
    DBUG_ASSERT(0);
  }
#endif
}


void my_virtual_mem_protect(void *ptr, size_t size, enum my_vmem_prot prot)
{
  int res __attribute__((unused));
#ifdef _WIN32
  DWORD old_prot;
  res= !VirtualProtect(ptr, size, prot ? PAGE_READWRITE : PAGE_READONLY, &old_prot);
#else
  res= mprotect(ptr, size, prot ? PROT_READ | PROT_WRITE : PROT_READ);
#endif
  DBUG_ASSERT(res == 0); // bad ptr or size alignment, neither should be possible
}

Messung V0.5 in Prozent
C=93 H=100 G=96

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-10-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.