Merge pull request #409 from Alkarex/patch-1
[mono.git] / mono / utils / mono-mmap.c
index 6339b497d1ea2e3f041b4be4c2b131adfd78ce8b..f1adabee3d0f7fd56c17c65463710f2e75411c50 100644 (file)
@@ -1,12 +1,25 @@
+/*
+ * mono-mmap.c: Support for mapping code into the process address space
+ *
+ * Author:
+ *   Mono Team (mono-list@lists.ximian.com)
+ *
+ * Copyright 2001-2008 Novell, Inc.
+ */
+
 #include "config.h"
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
 #include <windows.h>
 #include <io.h>
 #else
 #include <sys/types.h>
+#if HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#if HAVE_SYS_MMAN_H
 #include <sys/mman.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
@@ -16,6 +29,7 @@
 #endif
 
 #include "mono-mmap.h"
+#include "mono-proclib.h"
 
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
@@ -48,7 +62,15 @@ malloc_shared_area (int pid)
        return sarea;
 }
 
-#ifdef PLATFORM_WIN32
+static char*
+aligned_address (char *mem, size_t size, size_t alignment)
+{
+       char *aligned = (char*)((gulong)(mem + (alignment - 1)) & ~(alignment - 1));
+       g_assert (aligned >= mem && aligned + size <= mem + size + alignment && !((gulong)aligned & (alignment - 1)));
+       return aligned;
+}
+
+#ifdef HOST_WIN32
 
 int
 mono_pagesize (void)
@@ -93,10 +115,36 @@ mono_valloc (void *addr, size_t length, int flags)
        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)
 {
-       int res = VirtualFree (addr, 0, MEM_RELEASE);
+       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);
 
@@ -192,7 +240,8 @@ mono_shared_area_instances (void **array, int count)
        return 0;
 }
 
-#elif defined(HAVE_MMAP)
+#else
+#if defined(HAVE_MMAP)
 
 /**
  * mono_pagesize:
@@ -365,13 +414,83 @@ mono_mprotect (void *addr, size_t length, int flags)
                        memset (addr, 0, length);
 #else
                memset (addr, 0, length);
+#ifdef HAVE_MADVISE
                madvise (addr, length, MADV_DONTNEED);
                madvise (addr, length, MADV_FREE);
+#else
+               posix_madvise (addr, length, POSIX_MADV_DONTNEED);
+#endif
 #endif
        }
        return mprotect (addr, length, prot);
 }
 
+#else
+
+/* dummy malloc-based implementation */
+int
+mono_pagesize (void)
+{
+       return 4096;
+}
+
+void*
+mono_valloc (void *addr, size_t length, int flags)
+{
+       return malloc (length);
+}
+
+void*
+mono_valloc_aligned (size_t length, size_t alignment, int flags)
+{
+       g_assert_not_reached ();
+}
+
+#define HAVE_VALLOC_ALIGNED
+
+int
+mono_vfree (void *addr, size_t length)
+{
+       free (addr);
+       return 0;
+}
+
+int
+mono_mprotect (void *addr, size_t length, int flags)
+{
+       if (flags & MONO_MMAP_DISCARD) {
+               memset (addr, 0, length);
+       }
+       return 0;
+}
+#endif // HAVE_MMAP
+
+#if defined(HAVE_SHM_OPEN) && !defined (DISABLE_SHARED_PERFCOUNTERS)
+
+static int
+mono_shared_area_instances_slow (void **array, int count, gboolean cleanup)
+{
+       int i, j = 0;
+       int num;
+       void *data;
+       gpointer *processes = mono_process_list (&num);
+       for (i = 0; i < num; ++i) {
+               data = mono_shared_area_for_pid (processes [i]);
+               if (!data)
+                       continue;
+               mono_shared_area_unload (data);
+               if (!cleanup) {
+                       if (j < count)
+                               array [j++] = processes [i];
+                       else
+                               break;
+               }
+       }
+       g_free (processes);
+       return j;
+}
+
+#if (defined (__MACH__) && defined (TARGET_ARM))
 static int
 mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
 {
@@ -380,7 +499,7 @@ mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
        int curpid = getpid ();
        GDir *dir = g_dir_open ("/dev/shm/", 0, NULL);
        if (!dir)
-               return i;
+               return mono_shared_area_instances_slow (array, count, cleanup);
        while ((name = g_dir_read_name (dir))) {
                int pid;
                char *nend;
@@ -395,7 +514,7 @@ mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
                        else
                                break;
                }
-               if (curpid != pid && kill (pid, SIGCONT) == -1 && errno == ESRCH) {
+               if (curpid != pid && kill (pid, 0) == -1 && (errno == ESRCH || errno == ENOMEM)) {
                        char buf [128];
                        g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
                        shm_unlink (buf);
@@ -404,6 +523,9 @@ mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
        g_dir_close (dir);
        return i;
 }
+#else
+#define mono_shared_area_instances_helper mono_shared_area_instances_slow
+#endif
 
 void*
 mono_shared_area (void)
@@ -501,64 +623,7 @@ mono_shared_area_instances (void **array, int count)
 {
        return mono_shared_area_instances_helper (array, count, FALSE);
 }
-
 #else
-
-/* dummy malloc-based implementation */
-int
-mono_pagesize (void)
-{
-       return 4096;
-}
-
-void*
-mono_valloc (void *addr, size_t length, int flags)
-{
-       return malloc (length);
-}
-
-int
-mono_vfree (void *addr, size_t length)
-{
-       free (addr);
-       return 0;
-}
-
-void*
-mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
-{
-       guint64 cur_offset;
-       size_t bytes_read;
-       void *ptr = malloc (length);
-       if (!ptr)
-               return NULL;
-       cur_offset = lseek (fd, 0, SEEK_CUR);
-       if (lseek (fd, offset, SEEK_SET) != offset) {
-               free (ptr);
-               return NULL;
-       }
-       bytes_read = read (fd, ptr, length);
-       lseek (fd, cur_offset, SEEK_SET);
-       *ret_handle = NULL;
-       return ptr;
-}
-
-int
-mono_file_unmap (void *addr, void *handle)
-{
-       free (addr);
-       return 0;
-}
-
-int
-mono_mprotect (void *addr, size_t length, int flags)
-{
-       if (flags & MONO_MMAP_DISCARD) {
-               memset (addr, 0, length);
-       }
-       return 0;
-}
-
 void*
 mono_shared_area (void)
 {
@@ -590,5 +655,28 @@ mono_shared_area_instances (void **array, int count)
        return 0;
 }
 
-#endif
+#endif // HAVE_SHM_OPEN
+
+#endif // HOST_WIN32
+
+#ifndef HAVE_VALLOC_ALIGNED
+void*
+mono_valloc_aligned (size_t size, size_t alignment, int flags)
+{
+       /* Allocate twice the memory to be able to put the block on an aligned address */
+       char *mem = mono_valloc (NULL, size + alignment, flags);
+       char *aligned;
+
+       if (!mem)
+               return NULL;
 
+       aligned = aligned_address (mem, size, alignment);
+
+       if (aligned > mem)
+               mono_vfree (mem, aligned - mem);
+       if (aligned + size < mem + size + alignment)
+               mono_vfree (aligned + size, (mem + size + alignment) - (aligned + size));
+
+       return aligned;
+}
+#endif