18 #include "mono-mmap.h"
21 #define MAP_ANONYMOUS MAP_ANON
36 static void* malloced_shared_area = NULL;
39 malloc_shared_area (int pid)
41 int size = mono_pagesize ();
42 SAreaHeader *sarea = g_malloc0 (size);
45 sarea->stats_start = sizeof (SAreaHeader);
46 sarea->stats_end = sizeof (SAreaHeader);
57 static int saved_pagesize = 0;
59 return saved_pagesize;
60 GetSystemInfo (&info);
61 saved_pagesize = info.dwAllocationGranularity;
62 return saved_pagesize;
66 prot_from_flags (int flags)
68 int prot = flags & (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
70 case 0: prot = PAGE_NOACCESS; break;
71 case MONO_MMAP_READ: prot = PAGE_READONLY; break;
72 case MONO_MMAP_READ|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READ; break;
73 case MONO_MMAP_READ|MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
74 case MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
75 case MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
76 case MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
77 case MONO_MMAP_EXEC: prot = PAGE_EXECUTE; break;
79 g_assert_not_reached ();
85 mono_valloc (void *addr, size_t length, int flags)
88 int mflags = MEM_COMMIT;
89 int prot = prot_from_flags (flags);
90 /* translate the flags */
92 ptr = VirtualAlloc (addr, length, mflags, prot);
97 mono_vfree (void *addr, size_t length)
99 int res = VirtualFree (addr, 0, MEM_RELEASE);
107 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
111 HANDLE file, mapping;
112 int prot = prot_from_flags (flags);
113 /* translate the flags */
114 /*if (flags & MONO_MMAP_PRIVATE)
115 mflags |= MAP_PRIVATE;
116 if (flags & MONO_MMAP_SHARED)
117 mflags |= MAP_SHARED;
118 if (flags & MONO_MMAP_ANON)
119 mflags |= MAP_ANONYMOUS;
120 if (flags & MONO_MMAP_FIXED)
122 if (flags & MONO_MMAP_32BIT)
123 mflags |= MAP_32BIT;*/
125 mflags = FILE_MAP_READ;
126 if (flags & MONO_MMAP_WRITE)
127 mflags = FILE_MAP_COPY;
129 file = (HANDLE) _get_osfhandle (fd);
130 mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
133 ptr = MapViewOfFile (mapping, mflags, 0, offset, length);
135 CloseHandle (mapping);
138 *ret_handle = (void*)mapping;
143 mono_file_unmap (void *addr, void *handle)
145 UnmapViewOfFile (addr);
146 CloseHandle ((HANDLE)handle);
151 mono_mprotect (void *addr, size_t length, int flags)
154 int prot = prot_from_flags (flags);
156 if (flags & MONO_MMAP_DISCARD) {
157 VirtualFree (addr, length, MEM_DECOMMIT);
158 VirtualAlloc (addr, length, MEM_COMMIT, prot);
161 return VirtualProtect (addr, length, prot, &oldprot) == 0;
165 mono_shared_area (void)
167 /* get the pid here */
168 return malloc_shared_area (0);
172 mono_shared_area_remove (void)
174 if (malloced_shared_area)
175 g_free (malloced_shared_area);
179 mono_shared_area_for_pid (void *pid)
185 mono_shared_area_unload (void *area)
190 mono_shared_area_instances (void **array, int count)
195 #elif defined(HAVE_MMAP)
199 * Get the page size in use on the system. Addresses and sizes in the
200 * mono_mmap(), mono_munmap() and mono_mprotect() calls must be pagesize
203 * Returns: the page size in bytes.
208 static int saved_pagesize = 0;
210 return saved_pagesize;
211 saved_pagesize = getpagesize ();
212 return saved_pagesize;
216 prot_from_flags (int flags)
218 int prot = PROT_NONE;
219 /* translate the protection bits */
220 if (flags & MONO_MMAP_READ)
222 if (flags & MONO_MMAP_WRITE)
224 if (flags & MONO_MMAP_EXEC)
231 * @addr: memory address
232 * @length: memory area size
233 * @flags: protection flags
235 * Allocates @length bytes of virtual memory with the @flags
236 * protection. @addr can be a preferred memory address or a
237 * mandatory one if MONO_MMAP_FIXED is set in @flags.
238 * @addr must be pagesize aligned and can be NULL.
239 * @length must be a multiple of pagesize.
241 * Returns: NULL on failure, the address of the memory area otherwise
244 mono_valloc (void *addr, size_t length, int flags)
248 int prot = prot_from_flags (flags);
249 /* translate the flags */
250 if (flags & MONO_MMAP_FIXED)
252 if (flags & MONO_MMAP_32BIT)
255 mflags |= MAP_ANONYMOUS;
256 mflags |= MAP_PRIVATE;
258 ptr = mmap (addr, length, prot, mflags, -1, 0);
259 if (ptr == (void*)-1) {
260 int fd = open ("/dev/zero", O_RDONLY);
262 ptr = mmap (addr, length, prot, mflags, fd, 0);
265 if (ptr == (void*)-1)
273 * @addr: memory address returned by mono_valloc ()
274 * @length: size of memory area
276 * Remove the memory mapping at the address @addr.
278 * Returns: 0 on success.
281 mono_vfree (void *addr, size_t length)
283 return munmap (addr, length);
288 * @length: size of data to map
289 * @flags: protection flags
290 * @fd: file descriptor
291 * @offset: offset in the file
292 * @ret_handle: pointer to storage for returning a handle for the map
294 * Map the area of the file pointed to by the file descriptor @fd, at offset
295 * @offset and of size @length in memory according to the protection flags
297 * @offset and @length must be multiples of the page size.
298 * @ret_handle must point to a void*: this value must be used when unmapping
299 * the memory area using mono_file_unmap ().
303 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
307 int prot = prot_from_flags (flags);
308 /* translate the flags */
309 if (flags & MONO_MMAP_PRIVATE)
310 mflags |= MAP_PRIVATE;
311 if (flags & MONO_MMAP_SHARED)
312 mflags |= MAP_SHARED;
313 if (flags & MONO_MMAP_FIXED)
315 if (flags & MONO_MMAP_32BIT)
318 ptr = mmap (0, length, prot, mflags, fd, offset);
319 if (ptr == (void*)-1)
321 *ret_handle = (void*)length;
327 * @addr: memory address returned by mono_file_map ()
328 * @handle: handle of memory map
330 * Remove the memory mapping at the address @addr.
331 * @handle must be the value returned in ret_handle by mono_file_map ().
333 * Returns: 0 on success.
336 mono_file_unmap (void *addr, void *handle)
338 return munmap (addr, (size_t)handle);
343 * @addr: memory address
344 * @length: size of memory area
345 * @flags: new protection flags
347 * Change the protection for the memory area at @addr for @length bytes
348 * to matche the supplied @flags.
349 * If @flags includes MON_MMAP_DISCARD the pages are discarded from memory
350 * and the area is cleared to zero.
351 * @addr must be aligned to the page size.
352 * @length must be a multiple of the page size.
354 * Returns: 0 on success.
357 mono_mprotect (void *addr, size_t length, int flags)
359 int prot = prot_from_flags (flags);
361 if (flags & MONO_MMAP_DISCARD) {
362 /* on non-linux the pages are not guaranteed to be zeroed (*bsd, osx at least) */
364 if (madvise (addr, length, MADV_DONTNEED))
365 memset (addr, 0, length);
367 memset (addr, 0, length);
368 madvise (addr, length, MADV_DONTNEED);
369 madvise (addr, length, MADV_FREE);
372 return mprotect (addr, length, prot);
376 mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
380 int curpid = getpid ();
381 GDir *dir = g_dir_open ("/dev/shm/", 0, NULL);
384 while ((name = g_dir_read_name (dir))) {
387 if (strncmp (name, "mono.", 5))
389 pid = strtol (name + 5, &nend, 10);
390 if (pid <= 0 || nend == name + 5 || *nend)
394 array [i++] = GINT_TO_POINTER (pid);
398 if (curpid != pid && kill (pid, SIGCONT) == -1 && errno == ESRCH) {
400 g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
409 mono_shared_area (void)
413 /* we should allow the user to configure the size */
414 int size = mono_pagesize ();
419 /* perform cleanup of segments left over from dead processes */
420 mono_shared_area_instances_helper (NULL, 0, TRUE);
422 g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
424 fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
425 if (fd == -1 && errno == EEXIST) {
428 fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
430 /* in case of failure we try to return a memory area anyway,
431 * even if it means the data can't be read by other processes
434 return malloc_shared_area (pid);
435 if (ftruncate (fd, size) != 0) {
439 res = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
440 if (res == MAP_FAILED) {
443 return malloc_shared_area (pid);
445 /* we don't need the file descriptor anymore */
450 header->stats_start = sizeof (SAreaHeader);
451 header->stats_end = sizeof (SAreaHeader);
453 atexit (mono_shared_area_remove);
458 mono_shared_area_remove (void)
461 g_snprintf (buf, sizeof (buf), "/mono.%d", getpid ());
463 if (malloced_shared_area)
464 g_free (malloced_shared_area);
468 mono_shared_area_for_pid (void *pid)
471 /* we should allow the user to configure the size */
472 int size = mono_pagesize ();
476 g_snprintf (buf, sizeof (buf), "/mono.%d", GPOINTER_TO_INT (pid));
478 fd = shm_open (buf, O_RDONLY, S_IRUSR|S_IRGRP);
481 res = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
482 if (res == MAP_FAILED) {
486 /* FIXME: validate the area */
487 /* we don't need the file descriptor anymore */
493 mono_shared_area_unload (void *area)
495 /* FIXME: currently we load only a page */
496 munmap (area, mono_pagesize ());
500 mono_shared_area_instances (void **array, int count)
502 return mono_shared_area_instances_helper (array, count, FALSE);
507 /* dummy malloc-based implementation */
515 mono_valloc (void *addr, size_t length, int flags)
517 return malloc (length);
521 mono_vfree (void *addr, size_t length)
528 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
532 void *ptr = malloc (length);
535 cur_offset = lseek (fd, 0, SEEK_CUR);
536 if (lseek (fd, offset, SEEK_SET) != offset) {
540 bytes_read = read (fd, ptr, length);
541 lseek (fd, cur_offset, SEEK_SET);
547 mono_file_unmap (void *addr, void *handle)
554 mono_mprotect (void *addr, size_t length, int flags)
556 if (flags & MONO_MMAP_DISCARD) {
557 memset (addr, 0, length);
563 mono_shared_area (void)
565 return malloc_shared_area (getpid ());
569 mono_shared_area_remove (void)
571 if (malloced_shared_area)
572 g_free (malloced_shared_area);
573 malloced_shared_area = NULL;
577 mono_shared_area_for_pid (void *pid)
583 mono_shared_area_unload (void *area)
588 mono_shared_area_instances (void **array, int count)