Mon Apr 22 19:28:14 CEST 2002 Paolo Molaro <lupus@ximian.com>
[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 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
26 #define ROUND_UP(VALUE,SIZE)    (ROUND_DOWN((VALUE) + (SIZE) - 1, (SIZE)))
27
28 static GHashTable *mmap_map = NULL;
29 static size_t alignment = 0;
30
31 static void
32 get_alignment (void)
33 {
34 #ifdef USE_WIN32_API
35         SYSTEM_INFO info;
36
37         GetSystemInfo (&info);
38         alignment = info.dwAllocationGranularity;
39 #else
40         alignment = getpagesize ();
41 #endif
42 }
43
44 static void *
45 mono_raw_buffer_load_malloc (int fd, int is_writable, guint32 base, size_t size)
46 {
47         void *ptr;
48
49         ptr = g_malloc (size);
50         if (ptr == NULL)
51                 return NULL;
52
53         if (lseek (fd, base, 0) == (off_t) -1) {
54                 g_free (ptr);
55                 return NULL;
56         }
57
58         read (fd, ptr, size);
59         return ptr;
60 }
61
62 static void
63 mono_raw_buffer_free_malloc (void *base)
64 {
65         g_free (base);
66 }
67
68 static void *
69 mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
70 {
71 #ifdef USE_WIN32_API
72         /* FileMapping implementation */
73
74         DWORD start, end;
75         int prot, access;
76         void *ptr;
77         HANDLE file, mapping;
78
79         if (alignment == 0)
80                 get_alignment ();
81         start = ROUND_DOWN (base, alignment);
82         end = base + size;
83         
84         if (is_writable) {
85                 prot = PAGE_WRITECOPY;
86                 access = FILE_MAP_COPY;
87         }
88         else {
89                 prot = PAGE_READONLY;
90                 access = FILE_MAP_READ;
91         }
92
93         file = (HANDLE) _get_osfhandle (fd);
94         mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
95         if (mapping == NULL)
96                 return 0;
97
98         ptr = MapViewOfFile (mapping, access, 0, start, end - start);
99         if (ptr == NULL) {
100                 CloseHandle (mapping);
101                 return 0;
102         }
103
104         if (mmap_map == NULL)
105                 mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
106
107         g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping));
108         
109         return ((char *)ptr) + (base - start);
110
111 #else
112         /* mmap implementation */
113
114
115         size_t start, end;
116         int prot = PROT_READ;
117         int flags = 0;
118         void *ptr;
119
120         if (alignment == 0)
121                 get_alignment ();
122         start = ROUND_DOWN (base, alignment);
123         end = ROUND_UP (base + size, alignment);
124
125         if (is_writable){
126                 prot |= PROT_WRITE;
127                 flags = MAP_SHARED;
128         } else {
129                 flags = MAP_PRIVATE;
130         }
131
132         ptr = mmap (0, end - start, prot, flags, fd, start);
133
134         if (ptr == (void *) -1)
135                 return 0;
136         
137         if (mmap_map == NULL)
138                 mmap_map = g_hash_table_new (g_direct_hash, g_direct_equal);
139         
140         g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size));
141
142         return ((char *)ptr) + (base - start);
143 #endif
144 }
145
146 static void
147 mono_raw_buffer_free_mmap (void *base)
148 {
149         int value;
150
151         value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base));
152
153 #ifdef USE_WIN32_API
154         UnmapViewOfFile (base);
155         CloseHandle ((HANDLE) value);
156 #else
157         munmap (base, value);
158 #endif
159 }
160
161 static void
162 mono_raw_buffer_update_mmap (void *base, size_t size)
163 {
164 #ifdef USE_WIN32_API
165         FlushViewOfFile (base, size);
166 #else
167         msync (base, size, MS_SYNC);
168 #endif
169 }
170
171 void *
172 mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
173 {
174         void *ptr;
175
176         ptr = mono_raw_buffer_load_mmap (fd, is_writable, base, size);
177         if (ptr == 0)
178                 ptr = mono_raw_buffer_load_malloc (fd, is_writable, base, size);
179         
180         return ptr;
181 }
182
183 void
184 mono_raw_buffer_update (void *buffer, size_t size)
185 {
186         char *mmap_base;
187
188         mmap_base = GINT_TO_POINTER (ROUND_DOWN (GPOINTER_TO_INT (buffer), alignment));
189         
190         if (mmap_map && g_hash_table_lookup (mmap_map, mmap_base))
191                 mono_raw_buffer_update_mmap (mmap_base, size);
192 }
193
194 void
195 mono_raw_buffer_free (void *buffer)
196 {
197         char *mmap_base;
198
199         mmap_base = GINT_TO_POINTER (ROUND_DOWN (GPOINTER_TO_INT (buffer), alignment));
200         
201         if (mmap_map && g_hash_table_lookup (mmap_map, mmap_base))
202                 mono_raw_buffer_free_mmap (mmap_base);
203         else
204                 mono_raw_buffer_free_malloc (buffer);
205 }
206