Mon Mar 25 13:04:56 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / rawbuffer.c
index 8e9d2f8301dfb5e3eb880572d2245229203ca4cb..b8d75b97a57d931c029e20b26398245a9d2aabb3 100644 (file)
  * (C) 2001 Ximian, Inc.
  */
 #include <config.h>
+#if defined(PLATFORM_WIN32)
+#define USE_WIN32_API          1
+#endif
+
 #include <unistd.h>
+#ifdef USE_WIN32_API
+#include <windows.h>
+#include <io.h>
+#else
 #include <sys/mman.h>
+#endif
 #include <sys/types.h>
 #include <glib.h>
 #include "rawbuffer.h"
 
-#define PAGESIZE 8192
+#define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
+#define ROUND_UP(VALUE,SIZE)   (ROUND_DOWN((VALUE) + (SIZE) - 1, (SIZE)))
 
-static GHashTable *malloc_map = NULL;
+static GHashTable *mmap_map = NULL;
+static size_t alignment = 0;
 
-void *
-mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
+static void
+get_alignment ()
+{
+#ifdef USE_WIN32_API
+       SYSTEM_INFO info;
+
+       GetSystemInfo (&info);
+       alignment = info.dwAllocationGranularity;
+#else
+       alignment = getpagesize ();
+#endif
+}
+
+static void *
+mono_raw_buffer_load_malloc (int fd, int is_writable, guint32 base, size_t size)
 {
+       void *ptr;
+
+       ptr = g_malloc (size);
+       if (ptr == NULL)
+               return NULL;
+
+       if (lseek (fd, base, 0) == (off_t) -1) {
+               g_free (ptr);
+               return NULL;
+       }
+
+       read (fd, ptr, size);
+       return ptr;
+}
+
+static void
+mono_raw_buffer_free_malloc (void *base)
+{
+       g_free (base);
+}
+
+static void *
+mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
+{
+#ifdef USE_WIN32_API
+       /* FileMapping implementation */
+
+       DWORD start, end;
+       int prot, access;
+       void *ptr;
+       HANDLE file, mapping;
+
+       if (alignment == 0)
+               get_alignment ();
+       start = ROUND_DOWN (base, alignment);
+       end = base + size;
+       
+       if (is_writable) {
+               prot = PAGE_WRITECOPY;
+               access = FILE_MAP_COPY;
+       }
+       else {
+               prot = PAGE_READONLY;
+               access = FILE_MAP_READ;
+       }
+
+       file = (HANDLE) _get_osfhandle (fd);
+       mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
+       if (mapping == NULL)
+               return 0;
+
+       ptr = MapViewOfFile (mapping, access, 0, start, end - start);
+       if (ptr == NULL) {
+               CloseHandle (mapping);
+               return 0;
+       }
+
+       if (mmap_map == NULL)
+               mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+       g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping));
+       
+       return ((char *)ptr) + (base - start);
+
+#else
+       /* mmap implementation */
+
+
        size_t start, end;
        int prot = PROT_READ;
        int flags = 0;
-       void *ptr, *mmap_ptr;
-       
+       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;
 
-       start = base & ~(PAGESIZE - 1);
-       end = (base + size + PAGESIZE - 1) & ~(PAGESIZE - 1);
+       ptr = mmap (0, end - start, prot, flags, fd, start);
 
-       /*
-        * Apparently on cygwin the mmap succedes, but not all the
-        * area is mapped in and we get segfaults later.
-        */
-#ifdef __CYGWIN__
-       mmap_ptr = (void *) -1;
+       if (ptr == (void *) -1)
+               return 0;
+       
+       if (mmap_map == NULL)
+               mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+       
+       g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size));
+
+       return ((char *)ptr) + (base - start);
+#endif
+}
+
+static void
+mono_raw_buffer_free_mmap (void *base)
+{
+       int value;
+
+       value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base));
+
+#ifdef USE_WIN32_API
+       UnmapViewOfFile (base);
+       CloseHandle ((HANDLE) value);
 #else
-       mmap_ptr = mmap (0, end - start, prot, flags, fd, start);
+       munmap (base, value);
 #endif
-       if (mmap_ptr == (void *) -1){
-               ptr = g_malloc (size);
-               if (ptr == NULL)
-                       return NULL;
-               if (lseek (fd, base, 0) == (off_t) -1)
-                       return NULL;
-               read (fd, ptr, size);
-               return ptr;
-       }
-       if (malloc_map == NULL)
-               malloc_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+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
+}
 
-       g_hash_table_insert (malloc_map, mmap_ptr, GINT_TO_POINTER (size));
+void *
+mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
+{
+       void *ptr;
 
-       return ((char *)mmap_ptr) + (base - start);
+       ptr = mono_raw_buffer_load_mmap (fd, is_writable, base, size);
+       if (ptr == 0)
+               ptr = mono_raw_buffer_load_malloc (fd, is_writable, base, size);
+       
+       return ptr;
 }
 
 void
-mono_raw_buffer_free (void *buffer)
+mono_raw_buffer_update (void *buffer, size_t size)
 {
-       int size, diff;
-       char *base;
+       char *mmap_base;
+
+       mmap_base = GINT_TO_POINTER (ROUND_DOWN (GPOINTER_TO_INT (buffer), alignment));
        
-       if (!malloc_map){
-               g_free (buffer);
-               return;
-       }
+       if (mmap_map && g_hash_table_lookup (mmap_map, mmap_base))
+               mono_raw_buffer_update_mmap (mmap_base, size);
+}
+
+void
+mono_raw_buffer_free (void *buffer)
+{
+       char *mmap_base;
 
-       diff = ((unsigned int) buffer) & (PAGESIZE - 1);
-       base = ((char *)buffer) - diff;
+       mmap_base = GINT_TO_POINTER (ROUND_DOWN (GPOINTER_TO_INT (buffer), alignment));
        
-       size = GPOINTER_TO_INT (g_hash_table_lookup (malloc_map, base));
-       munmap (base, size);
+       if (mmap_map && g_hash_table_lookup (mmap_map, mmap_base))
+               mono_raw_buffer_free_mmap (mmap_base);
+       else
+               mono_raw_buffer_free_malloc (buffer);
 }
+