be7fc2a7172b102c8e1262cbed669b8210f52687
[mono.git] / mono / metadata / rawbuffer.c
1 /*
2  * rawbuffer.c: Manages buffers that might have been mmapped or malloced
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #if defined(PLATFORM_WIN32)
11 #define USE_WIN32_API           1
12 #endif
13
14 #include <unistd.h>
15 #ifdef USE_WIN32_API
16 #include <windows.h>
17 #include <io.h>
18 #else
19 #include <sys/mman.h>
20 #endif
21 #include <sys/types.h>
22 #include <glib.h>
23 #include "rawbuffer.h"
24
25 #include <mono/io-layer/io-layer.h>
26
27 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
28 #define ROUND_UP(VALUE,SIZE)    (ROUND_DOWN((VALUE) + (SIZE) - 1, (SIZE)))
29 #if SIZEOF_VOID_P == 8
30 #define UINTPTR_TYPE guint64
31 #else
32 #define UINTPTR_TYPE guint32
33 #endif
34
35 static GHashTable *mmap_map = NULL;
36 static size_t alignment = 0;
37 static CRITICAL_SECTION mmap_mutex;
38
39 static void
40 get_alignment (void)
41 {
42 #ifdef USE_WIN32_API
43         SYSTEM_INFO info;
44
45         GetSystemInfo (&info);
46         alignment = info.dwAllocationGranularity;
47 #else
48         alignment = getpagesize ();
49 #endif
50 }
51
52 static void *
53 mono_raw_buffer_load_malloc (int fd, int is_writable, guint32 base, size_t size)
54 {
55         void *ptr;
56
57         ptr = g_malloc (size);
58         if (ptr == NULL)
59                 return NULL;
60
61         if (lseek (fd, base, 0) == (off_t) -1) {
62                 g_free (ptr);
63                 return NULL;
64         }
65
66         read (fd, ptr, size);
67         return ptr;
68 }
69
70 static void
71 mono_raw_buffer_free_malloc (void *base)
72 {
73         g_free (base);
74 }
75
76 void
77 mono_raw_buffer_init (void)
78 {
79         InitializeCriticalSection (&mmap_mutex);
80
81         get_alignment ();
82
83         mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
84 }
85
86 static void *
87 mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
88 {
89 #ifdef USE_WIN32_API
90         /* FileMapping implementation */
91
92         DWORD start, end;
93         int prot, access;
94         void *ptr;
95         HANDLE file, mapping;
96
97         start = ROUND_DOWN (base, alignment);
98         end = base + size;
99         
100         if (is_writable) {
101                 prot = PAGE_WRITECOPY;
102                 access = FILE_MAP_COPY;
103         }
104         else {
105                 prot = PAGE_READONLY;
106                 access = FILE_MAP_READ;
107         }
108
109         file = (HANDLE) _get_osfhandle (fd);
110         mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
111         if (mapping == NULL)
112                 return 0;
113
114         ptr = MapViewOfFile (mapping, access, 0, start, end - start);
115         if (ptr == NULL) {
116                 CloseHandle (mapping);
117                 return 0;
118         }
119
120         EnterCriticalSection (&mmap_mutex);
121         g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping));
122         LeaveCriticalSection (&mmap_mutex);
123         
124         return ((char *)ptr) + (base - start);
125
126 #else
127         /* mmap implementation */
128
129
130         size_t start, end;
131         int prot = PROT_READ;
132         int flags = 0;
133         void *ptr;
134
135         start = ROUND_DOWN (base, alignment);
136         end = ROUND_UP (base + size, alignment);
137
138         if (is_writable){
139                 prot |= PROT_WRITE;
140                 flags = MAP_SHARED;
141         } else {
142                 flags = MAP_PRIVATE;
143         }
144
145         ptr = mmap (0, end - start, prot, flags, fd, start);
146
147         if (ptr == (void *) -1)
148                 return 0;
149         
150         EnterCriticalSection (&mmap_mutex);
151         g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size));
152         LeaveCriticalSection (&mmap_mutex);
153
154         return ((char *)ptr) + (base - start);
155 #endif
156 }
157
158 static void
159 mono_raw_buffer_free_mmap (void *base)
160 {
161         int value;
162
163         EnterCriticalSection (&mmap_mutex);
164         value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base));
165         LeaveCriticalSection (&mmap_mutex);
166
167 #ifdef USE_WIN32_API
168         UnmapViewOfFile (base);
169         CloseHandle ((HANDLE) value);
170 #else
171         munmap (base, value);
172 #endif
173 }
174
175 static void
176 mono_raw_buffer_update_mmap (void *base, size_t size)
177 {
178 #ifdef USE_WIN32_API
179         FlushViewOfFile (base, size);
180 #else
181         msync (base, size, MS_SYNC);
182 #endif
183 }
184
185 void *
186 mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
187 {
188         void *ptr;
189
190         ptr = mono_raw_buffer_load_mmap (fd, is_writable, base, size);
191         if (ptr == 0)
192                 ptr = mono_raw_buffer_load_malloc (fd, is_writable, base, size);
193         
194         return ptr;
195 }
196
197 void
198 mono_raw_buffer_update (void *buffer, size_t size)
199 {
200         char *mmap_base;
201         gboolean exists;
202
203         mmap_base =  (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
204
205         EnterCriticalSection (&mmap_mutex);
206         exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
207         LeaveCriticalSection (&mmap_mutex);
208         if (exists)
209                 mono_raw_buffer_update_mmap (mmap_base, size);
210 }
211
212 void
213 mono_raw_buffer_free (void *buffer)
214 {
215         char *mmap_base;
216         gboolean exists;
217
218         mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
219         
220         exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
221         if (exists)
222                 mono_raw_buffer_free_mmap (mmap_base);
223         else
224                 mono_raw_buffer_free_malloc (buffer);
225 }
226