Merge pull request #3707 from lateralusX/jlorenss/win-api-family-support-libmonoutils
[mono.git] / mono / utils / mono-mmap.c
index bc574bfe750a3e7854449da96ec774ba8908a076..91fe5a12def4517d7c1d364df7117cef53aa988f 100644 (file)
@@ -5,14 +5,12 @@
  *   Mono Team (mono-list@lists.ximian.com)
  *
  * Copyright 2001-2008 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "config.h"
+#include <config.h>
 
-#ifdef HOST_WIN32
-#include <windows.h>
-#include <io.h>
-#else
+#ifndef HOST_WIN32
 #include <sys/types.h>
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
-#endif
+#endif /* !HOST_WIN32 */
 
 #include "mono-mmap.h"
-#include "mono-mmap-internal.h"
+#include "mono-mmap-internals.h"
 #include "mono-proclib.h"
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/atomic.h>
+#include <mono/utils/mono-counters.h>
+
+#define BEGIN_CRITICAL_SECTION do { \
+       MonoThreadInfo *__info = mono_thread_info_current_unchecked (); \
+       if (__info) __info->inside_critical_region = TRUE;      \
+
+#define END_CRITICAL_SECTION \
+       if (__info) __info->inside_critical_region = FALSE;     \
+} while (0)    \
 
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
@@ -50,9 +59,7 @@ typedef struct {
        short stats_end;
 } SAreaHeader;
 
-static void* malloced_shared_area = NULL;
-
-static void*
+void*
 malloc_shared_area (int pid)
 {
        int size = mono_pagesize ();
@@ -65,7 +72,7 @@ malloc_shared_area (int pid)
        return sarea;
 }
 
-static char*
+char*
 aligned_address (char *mem, size_t size, size_t alignment)
 {
        char *aligned = (char*)((size_t)(mem + (alignment - 1)) & ~(alignment - 1));
@@ -73,180 +80,61 @@ aligned_address (char *mem, size_t size, size_t alignment)
        return aligned;
 }
 
-#ifdef HOST_WIN32
-
-int
-mono_pagesize (void)
-{
-       SYSTEM_INFO info;
-       static int saved_pagesize = 0;
-       if (saved_pagesize)
-               return saved_pagesize;
-       GetSystemInfo (&info);
-       saved_pagesize = info.dwAllocationGranularity;
-       return saved_pagesize;
-}
-
-static int
-prot_from_flags (int flags)
-{
-       int prot = flags & (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
-       switch (prot) {
-       case 0: prot = PAGE_NOACCESS; break;
-       case MONO_MMAP_READ: prot = PAGE_READONLY; break;
-       case MONO_MMAP_READ|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READ; break;
-       case MONO_MMAP_READ|MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
-       case MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
-       case MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
-       case MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
-       case MONO_MMAP_EXEC: prot = PAGE_EXECUTE; break;
-       default:
-               g_assert_not_reached ();
-       }
-       return prot;
-}
-
-void*
-mono_valloc (void *addr, size_t length, int flags)
-{
-       void *ptr;
-       int mflags = MEM_RESERVE|MEM_COMMIT;
-       int prot = prot_from_flags (flags);
-       /* translate the flags */
-
-       ptr = VirtualAlloc (addr, length, mflags, prot);
-       return ptr;
-}
-
-void*
-mono_valloc_aligned (size_t length, size_t alignment, int flags)
-{
-       int prot = prot_from_flags (flags);
-       char *mem = VirtualAlloc (NULL, length + alignment, MEM_RESERVE, prot);
-       char *aligned;
-
-       if (!mem)
-               return NULL;
-
-       aligned = aligned_address (mem, length, alignment);
-
-       aligned = VirtualAlloc (aligned, length, MEM_COMMIT, prot);
-       g_assert (aligned);
-
-       return aligned;
-}
-
-#define HAVE_VALLOC_ALIGNED
-
-int
-mono_vfree (void *addr, size_t length)
-{
-       MEMORY_BASIC_INFORMATION mbi;
-       SIZE_T query_result = VirtualQuery (addr, &mbi, sizeof (mbi));
-       BOOL res;
-
-       g_assert (query_result);
-
-       res = VirtualFree (mbi.AllocationBase, 0, MEM_RELEASE);
-
-       g_assert (res);
-
-       return 0;
-}
-
-void*
-mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
-{
-       void *ptr;
-       int mflags = 0;
-       HANDLE file, mapping;
-       int prot = prot_from_flags (flags);
-       /* translate the flags */
-       /*if (flags & MONO_MMAP_PRIVATE)
-               mflags |= MAP_PRIVATE;
-       if (flags & MONO_MMAP_SHARED)
-               mflags |= MAP_SHARED;
-       if (flags & MONO_MMAP_ANON)
-               mflags |= MAP_ANONYMOUS;
-       if (flags & MONO_MMAP_FIXED)
-               mflags |= MAP_FIXED;
-       if (flags & MONO_MMAP_32BIT)
-               mflags |= MAP_32BIT;*/
-
-       mflags = FILE_MAP_READ;
-       if (flags & MONO_MMAP_WRITE)
-               mflags = FILE_MAP_COPY;
-
-       file = (HANDLE) _get_osfhandle (fd);
-       mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
-       if (mapping == NULL)
-               return NULL;
-       ptr = MapViewOfFile (mapping, mflags, 0, offset, length);
-       if (ptr == NULL) {
-               CloseHandle (mapping);
-               return NULL;
-       }
-       *ret_handle = (void*)mapping;
-       return ptr;
-}
-
-int
-mono_file_unmap (void *addr, void *handle)
-{
-       UnmapViewOfFile (addr);
-       CloseHandle ((HANDLE)handle);
-       return 0;
-}
-
-int
-mono_mprotect (void *addr, size_t length, int flags)
-{
-       DWORD oldprot;
-       int prot = prot_from_flags (flags);
-
-       if (flags & MONO_MMAP_DISCARD) {
-               VirtualFree (addr, length, MEM_DECOMMIT);
-               VirtualAlloc (addr, length, MEM_COMMIT, prot);
-               return 0;
-       }
-       return VirtualProtect (addr, length, prot, &oldprot) == 0;
-}
-
-void*
-mono_shared_area (void)
-{
-       if (!malloced_shared_area)
-               malloced_shared_area = malloc_shared_area (0);
-       /* get the pid here */
-       return malloced_shared_area;
-}
+static volatile size_t allocation_count [MONO_MEM_ACCOUNT_MAX];
 
 void
-mono_shared_area_remove (void)
+account_mem (MonoMemAccountType type, ssize_t size)
 {
-       if (malloced_shared_area)
-               g_free (malloced_shared_area);
-       malloced_shared_area = NULL;
+#if SIZEOF_VOID_P == 4
+       InterlockedAdd ((volatile gint32*)&allocation_count [type], (gint32)size);
+#else
+       InterlockedAdd64 ((volatile gint64*)&allocation_count [type], (gint64)size);
+#endif
 }
 
-void*
-mono_shared_area_for_pid (void *pid)
+const char*
+mono_mem_account_type_name (MonoMemAccountType type)
 {
-       return NULL;
+       static const char *names[] = {
+               "code",
+               "hazard pointers",
+               "domain",
+               "SGen internal",
+               "SGen nursery",
+               "SGen LOS",
+               "SGen mark&sweep",
+               "SGen card table",
+               "SGen shadow card table",
+               "SGen debugging",
+               "SGen binary protocol",
+               "exceptions",
+               "profiler",
+               "other"
+       };
+
+       return names [type];
 }
 
 void
-mono_shared_area_unload (void *area)
-{
+mono_mem_account_register_counters (void)
+{
+       for (int i = 0; i < MONO_MEM_ACCOUNT_MAX; ++i) {
+               const char *prefix = "Valloc ";
+               const char *name = mono_mem_account_type_name (i);
+               char descr [128];
+               g_assert (strlen (prefix) + strlen (name) < sizeof (descr));
+               sprintf (descr, "%s%s", prefix, name);
+               mono_counters_register (descr, MONO_COUNTER_WORD | MONO_COUNTER_RUNTIME | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE, (void*)&allocation_count [i]);
+       }
 }
 
-int
-mono_shared_area_instances (void **array, int count)
-{
-       return 0;
-}
+#ifdef HOST_WIN32
+// Windows specific implementation in mono-mmap-windows.c
+#define HAVE_VALLOC_ALIGNED
 
 #else
+
+static void* malloced_shared_area = NULL;
 #if defined(HAVE_MMAP)
 
 /**
@@ -296,7 +184,7 @@ prot_from_flags (int flags)
  * Returns: NULL on failure, the address of the memory area otherwise
  */
 void*
-mono_valloc (void *addr, size_t length, int flags)
+mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
 {
        void *ptr;
        int mflags = 0;
@@ -310,6 +198,7 @@ mono_valloc (void *addr, size_t length, int flags)
        mflags |= MAP_ANONYMOUS;
        mflags |= MAP_PRIVATE;
 
+       BEGIN_CRITICAL_SECTION;
        ptr = mmap (addr, length, prot, mflags, -1, 0);
        if (ptr == MAP_FAILED) {
                int fd = open ("/dev/zero", O_RDONLY);
@@ -317,9 +206,14 @@ mono_valloc (void *addr, size_t length, int flags)
                        ptr = mmap (addr, length, prot, mflags, fd, 0);
                        close (fd);
                }
-               if (ptr == MAP_FAILED)
-                       return NULL;
        }
+       END_CRITICAL_SECTION;
+
+       if (ptr == MAP_FAILED)
+               return NULL;
+
+       account_mem (type, (ssize_t)length);
+
        return ptr;
 }
 
@@ -333,9 +227,16 @@ mono_valloc (void *addr, size_t length, int flags)
  * Returns: 0 on success.
  */
 int
-mono_vfree (void *addr, size_t length)
+mono_vfree (void *addr, size_t length, MonoMemAccountType type)
 {
-       return munmap (addr, length);
+       int res;
+       BEGIN_CRITICAL_SECTION;
+       res = munmap (addr, length);
+       END_CRITICAL_SECTION;
+
+       account_mem (type, -(ssize_t)length);
+
+       return res;
 }
 
 /**
@@ -370,7 +271,9 @@ mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_hand
        if (flags & MONO_MMAP_32BIT)
                mflags |= MAP_32BIT;
 
+       BEGIN_CRITICAL_SECTION;
        ptr = mmap (0, length, prot, mflags, fd, offset);
+       END_CRITICAL_SECTION;
        if (ptr == MAP_FAILED)
                return NULL;
        *ret_handle = (void*)length;
@@ -390,7 +293,13 @@ mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_hand
 int
 mono_file_unmap (void *addr, void *handle)
 {
-       return munmap (addr, (size_t)handle);
+       int res;
+
+       BEGIN_CRITICAL_SECTION;
+       res = munmap (addr, (size_t)handle);
+       END_CRITICAL_SECTION;
+
+       return res;
 }
 
 /**
@@ -456,13 +365,13 @@ mono_pagesize (void)
 }
 
 void*
-mono_valloc (void *addr, size_t length, int flags)
+mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
 {
-       return malloc (length);
+       return g_malloc (length);
 }
 
 void*
-mono_valloc_aligned (size_t length, size_t alignment, int flags)
+mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type)
 {
        g_assert_not_reached ();
 }
@@ -470,9 +379,9 @@ mono_valloc_aligned (size_t length, size_t alignment, int flags)
 #define HAVE_VALLOC_ALIGNED
 
 int
-mono_vfree (void *addr, size_t length)
+mono_vfree (void *addr, size_t length, MonoMemAccountType type)
 {
-       free (addr);
+       g_free (addr);
        return 0;
 }
 
@@ -597,7 +506,10 @@ mono_shared_area (void)
                shm_unlink (buf);
                close (fd);
        }
+       BEGIN_CRITICAL_SECTION;
        res = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+       END_CRITICAL_SECTION;
+
        if (res == MAP_FAILED) {
                shm_unlink (buf);
                close (fd);
@@ -649,7 +561,10 @@ mono_shared_area_for_pid (void *pid)
        fd = shm_open (buf, O_RDONLY, S_IRUSR|S_IRGRP);
        if (fd == -1)
                return NULL;
+       BEGIN_CRITICAL_SECTION;
        res = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+       END_CRITICAL_SECTION;
+
        if (res == MAP_FAILED) {
                close (fd);
                return NULL;
@@ -664,7 +579,9 @@ void
 mono_shared_area_unload  (void *area)
 {
        /* FIXME: currently we load only a page */
+       BEGIN_CRITICAL_SECTION;
        munmap (area, mono_pagesize ());
+       END_CRITICAL_SECTION;
 }
 
 int
@@ -713,10 +630,10 @@ mono_shared_area_instances (void **array, int count)
 
 #ifndef HAVE_VALLOC_ALIGNED
 void*
-mono_valloc_aligned (size_t size, size_t alignment, int flags)
+mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type)
 {
        /* Allocate twice the memory to be able to put the block on an aligned address */
-       char *mem = (char *) mono_valloc (NULL, size + alignment, flags);
+       char *mem = (char *) mono_valloc (NULL, size + alignment, flags, type);
        char *aligned;
 
        if (!mem)
@@ -725,9 +642,9 @@ mono_valloc_aligned (size_t size, size_t alignment, int flags)
        aligned = aligned_address (mem, size, alignment);
 
        if (aligned > mem)
-               mono_vfree (mem, aligned - mem);
+               mono_vfree (mem, aligned - mem, type);
        if (aligned + size < mem + size + alignment)
-               mono_vfree (aligned + size, (mem + size + alignment) - (aligned + size));
+               mono_vfree (aligned + size, (mem + size + alignment) - (aligned + size), type);
 
        return aligned;
 }