2005-01-24 Ben Maurer <bmaurer@ximian.com>
[mono-project.git] / mono / metadata / rawbuffer.c
blob4ecd91abb7d910e6c11553e9ffc41e45a8147733
1 /*
2 * rawbuffer.c: Manages buffers that might have been mmapped or malloced
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
8 */
9 #include <config.h>
10 #if defined(PLATFORM_WIN32)
11 #define USE_WIN32_API 1
12 #endif
14 #include <unistd.h>
15 #include <errno.h>
16 #ifdef USE_WIN32_API
17 #include <windows.h>
18 #include <io.h>
19 #else
20 #include <sys/mman.h>
21 #endif
22 #include <sys/types.h>
23 #include <glib.h>
24 #include "rawbuffer.h"
26 #include <mono/io-layer/io-layer.h>
28 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
29 #define ROUND_UP(VALUE,SIZE) (ROUND_DOWN((VALUE) + (SIZE) - 1, (SIZE)))
30 #if SIZEOF_VOID_P == 8
31 #define UINTPTR_TYPE guint64
32 #else
33 #define UINTPTR_TYPE guint32
34 #endif
36 static GHashTable *mmap_map = NULL;
37 static size_t alignment = 0;
38 static CRITICAL_SECTION mmap_mutex;
40 static void
41 get_alignment (void)
43 #ifdef USE_WIN32_API
44 SYSTEM_INFO info;
46 GetSystemInfo (&info);
47 alignment = info.dwAllocationGranularity;
48 #else
49 alignment = getpagesize ();
50 #endif
53 static void *
54 mono_raw_buffer_load_malloc (int fd, int is_writable, guint32 base, size_t size)
56 void *ptr;
58 ptr = g_malloc (size);
59 if (ptr == NULL)
60 return NULL;
62 if (lseek (fd, base, 0) == (off_t) -1) {
63 g_free (ptr);
64 return NULL;
67 read (fd, ptr, size);
68 return ptr;
71 static void
72 mono_raw_buffer_free_malloc (void *base)
74 g_free (base);
77 void
78 mono_raw_buffer_init (void)
80 InitializeCriticalSection (&mmap_mutex);
82 get_alignment ();
84 mmap_map = g_hash_table_new (NULL, NULL);
87 static void *
88 mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
90 #ifdef USE_WIN32_API
91 /* FileMapping implementation */
93 DWORD start, end;
94 int prot, access;
95 void *ptr;
96 HANDLE file, mapping;
98 start = ROUND_DOWN (base, alignment);
99 end = base + size;
101 if (is_writable) {
102 prot = PAGE_WRITECOPY;
103 access = FILE_MAP_COPY;
105 else {
106 prot = PAGE_READONLY;
107 access = FILE_MAP_READ;
110 file = (HANDLE) _get_osfhandle (fd);
111 mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
112 if (mapping == NULL)
113 return 0;
115 ptr = MapViewOfFile (mapping, access, 0, start, end - start);
116 if (ptr == NULL) {
117 CloseHandle (mapping);
118 return 0;
121 EnterCriticalSection (&mmap_mutex);
122 g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping));
123 LeaveCriticalSection (&mmap_mutex);
125 return ((char *)ptr) + (base - start);
127 #else
128 /* mmap implementation */
131 size_t start, end;
132 int prot = PROT_READ;
133 int flags = 0;
134 void *ptr;
136 start = ROUND_DOWN (base, alignment);
137 end = ROUND_UP (base + size, alignment);
139 if (is_writable){
140 prot |= PROT_WRITE;
141 flags = MAP_SHARED;
142 } else {
143 flags = MAP_PRIVATE;
146 ptr = mmap (0, end - start, prot, flags, fd, start);
148 if (ptr == (void *) -1)
149 return 0;
152 * This seems to prevent segmentation faults on Fedora Linux, no
153 * idea why :). See
154 * http://bugzilla.ximian.com/show_bug.cgi?id=49499
155 * for more info.
157 if (mprotect (ptr, end - start, prot | PROT_EXEC) != 0)
158 g_warning (G_GNUC_PRETTY_FUNCTION
159 ": mprotect failed: %s", g_strerror (errno));
161 EnterCriticalSection (&mmap_mutex);
162 g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size));
163 LeaveCriticalSection (&mmap_mutex);
165 return ((char *)ptr) + (base - start);
166 #endif
169 static void
170 mono_raw_buffer_free_mmap (void *base)
172 int value;
174 EnterCriticalSection (&mmap_mutex);
175 value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base));
176 LeaveCriticalSection (&mmap_mutex);
178 #ifdef USE_WIN32_API
179 UnmapViewOfFile (base);
180 CloseHandle ((HANDLE) value);
181 #else
182 munmap (base, value);
183 #endif
186 static void
187 mono_raw_buffer_update_mmap (void *base, size_t size)
189 #ifdef USE_WIN32_API
190 FlushViewOfFile (base, size);
191 #else
192 msync (base, size, MS_SYNC);
193 #endif
196 void *
197 mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
199 void *ptr;
201 ptr = mono_raw_buffer_load_mmap (fd, is_writable, base, size);
202 if (ptr == 0)
203 ptr = mono_raw_buffer_load_malloc (fd, is_writable, base, size);
205 return ptr;
208 void
209 mono_raw_buffer_update (void *buffer, size_t size)
211 char *mmap_base;
212 gboolean exists;
214 mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
216 EnterCriticalSection (&mmap_mutex);
217 exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
218 LeaveCriticalSection (&mmap_mutex);
219 if (exists)
220 mono_raw_buffer_update_mmap (mmap_base, size);
223 void
224 mono_raw_buffer_free (void *buffer)
226 char *mmap_base;
227 gboolean exists;
229 mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
231 exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
232 if (exists)
233 mono_raw_buffer_free_mmap (mmap_base);
234 else
235 mono_raw_buffer_free_malloc (buffer);