2004-07-05 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / rawbuffer.c
index cc05e5f2b33f60d3815192ed52963435640603bf..4ecd91abb7d910e6c11553e9ffc41e45a8147733 100644 (file)
@@ -7,11 +7,12 @@
  * (C) 2001 Ximian, Inc.
  */
 #include <config.h>
-#if defined(PLATFORM_WIN32) || defined(PLATFORM_WIN32_NATIVE)
+#if defined(PLATFORM_WIN32)
 #define USE_WIN32_API          1
 #endif
 
 #include <unistd.h>
+#include <errno.h>
 #ifdef USE_WIN32_API
 #include <windows.h>
 #include <io.h>
 #include <glib.h>
 #include "rawbuffer.h"
 
+#include <mono/io-layer/io-layer.h>
+
 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
 #define ROUND_UP(VALUE,SIZE)   (ROUND_DOWN((VALUE) + (SIZE) - 1, (SIZE)))
-
-#if defined(PLATFORM_WIN32_NATIVE)
-#define get_osfhandle          _get_osfhandle
+#if SIZEOF_VOID_P == 8
+#define UINTPTR_TYPE guint64
+#else
+#define UINTPTR_TYPE guint32
 #endif
 
 static GHashTable *mmap_map = NULL;
 static size_t alignment = 0;
+static CRITICAL_SECTION mmap_mutex;
 
 static void
-get_alignment ()
+get_alignment (void)
 {
 #ifdef USE_WIN32_API
        SYSTEM_INFO info;
@@ -69,6 +74,16 @@ mono_raw_buffer_free_malloc (void *base)
        g_free (base);
 }
 
+void
+mono_raw_buffer_init (void)
+{
+       InitializeCriticalSection (&mmap_mutex);
+
+       get_alignment ();
+
+       mmap_map = g_hash_table_new (NULL, NULL);
+}
+
 static void *
 mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
 {
@@ -80,8 +95,6 @@ mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
        void *ptr;
        HANDLE file, mapping;
 
-       if (alignment == 0)
-               get_alignment ();
        start = ROUND_DOWN (base, alignment);
        end = base + size;
        
@@ -94,7 +107,7 @@ mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
                access = FILE_MAP_READ;
        }
 
-       file = (HANDLE) get_osfhandle (fd);
+       file = (HANDLE) _get_osfhandle (fd);
        mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
        if (mapping == NULL)
                return 0;
@@ -105,10 +118,9 @@ mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
                return 0;
        }
 
-       if (mmap_map == NULL)
-               mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
-
+       EnterCriticalSection (&mmap_mutex);
        g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping));
+       LeaveCriticalSection (&mmap_mutex);
        
        return ((char *)ptr) + (base - start);
 
@@ -121,25 +133,34 @@ mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
        int flags = 0;
        void *ptr;
 
-       if (alignment == 0)
-               get_alignment ();
        start = ROUND_DOWN (base, alignment);
        end = ROUND_UP (base + size, alignment);
 
        if (is_writable){
                prot |= PROT_WRITE;
+               flags = MAP_SHARED;
+       } else {
+               flags = MAP_PRIVATE;
        }
-       flags = MAP_PRIVATE;
 
        ptr = mmap (0, end - start, prot, flags, fd, start);
 
        if (ptr == (void *) -1)
                return 0;
+
+       /* 
+        * This seems to prevent segmentation faults on Fedora Linux, no
+        * idea why :). See
+        * http://bugzilla.ximian.com/show_bug.cgi?id=49499
+        * for more info.
+        */
+       if (mprotect (ptr, end - start, prot | PROT_EXEC) != 0)
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                                  ": mprotect failed: %s", g_strerror (errno));
        
-       if (mmap_map == NULL)
-               mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
-       
+       EnterCriticalSection (&mmap_mutex);
        g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size));
+       LeaveCriticalSection (&mmap_mutex);
 
        return ((char *)ptr) + (base - start);
 #endif
@@ -150,7 +171,9 @@ mono_raw_buffer_free_mmap (void *base)
 {
        int value;
 
+       EnterCriticalSection (&mmap_mutex);
        value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base));
+       LeaveCriticalSection (&mmap_mutex);
 
 #ifdef USE_WIN32_API
        UnmapViewOfFile (base);
@@ -160,6 +183,16 @@ mono_raw_buffer_free_mmap (void *base)
 #endif
 }
 
+static void
+mono_raw_buffer_update_mmap (void *base, size_t size)
+{
+#ifdef USE_WIN32_API
+       FlushViewOfFile (base, size);
+#else
+       msync (base, size, MS_SYNC);
+#endif
+}
+
 void *
 mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
 {
@@ -172,14 +205,31 @@ mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
        return ptr;
 }
 
+void
+mono_raw_buffer_update (void *buffer, size_t size)
+{
+       char *mmap_base;
+       gboolean exists;
+
+       mmap_base =  (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
+
+       EnterCriticalSection (&mmap_mutex);
+       exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
+       LeaveCriticalSection (&mmap_mutex);
+       if (exists)
+               mono_raw_buffer_update_mmap (mmap_base, size);
+}
+
 void
 mono_raw_buffer_free (void *buffer)
 {
        char *mmap_base;
+       gboolean exists;
 
-       mmap_base = GINT_TO_POINTER (ROUND_DOWN (GPOINTER_TO_INT (buffer), alignment));
+       mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
        
-       if (mmap_map && g_hash_table_lookup (mmap_map, mmap_base))
+       exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
+       if (exists)
                mono_raw_buffer_free_mmap (mmap_base);
        else
                mono_raw_buffer_free_malloc (buffer);