2 * mono-mmap.c: Support for mapping code into the process address space
5 * Mono Team (mono-list@lists.ximian.com)
7 * Copyright 2001-2008 Novell, Inc.
16 #include <sys/types.h>
31 #include "mono-mmap.h"
32 #include "mono-proclib.h"
35 #define MAP_ANONYMOUS MAP_ANON
50 static void* malloced_shared_area
= NULL
;
53 malloc_shared_area (int pid
)
55 int size
= mono_pagesize ();
56 SAreaHeader
*sarea
= g_malloc0 (size
);
59 sarea
->stats_start
= sizeof (SAreaHeader
);
60 sarea
->stats_end
= sizeof (SAreaHeader
);
71 static int saved_pagesize
= 0;
73 return saved_pagesize
;
74 GetSystemInfo (&info
);
75 saved_pagesize
= info
.dwAllocationGranularity
;
76 return saved_pagesize
;
80 prot_from_flags (int flags
)
82 int prot
= flags
& (MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_EXEC
);
84 case 0: prot
= PAGE_NOACCESS
; break;
85 case MONO_MMAP_READ
: prot
= PAGE_READONLY
; break;
86 case MONO_MMAP_READ
|MONO_MMAP_EXEC
: prot
= PAGE_EXECUTE_READ
; break;
87 case MONO_MMAP_READ
|MONO_MMAP_WRITE
: prot
= PAGE_READWRITE
; break;
88 case MONO_MMAP_READ
|MONO_MMAP_WRITE
|MONO_MMAP_EXEC
: prot
= PAGE_EXECUTE_READWRITE
; break;
89 case MONO_MMAP_WRITE
: prot
= PAGE_READWRITE
; break;
90 case MONO_MMAP_WRITE
|MONO_MMAP_EXEC
: prot
= PAGE_EXECUTE_READWRITE
; break;
91 case MONO_MMAP_EXEC
: prot
= PAGE_EXECUTE
; break;
93 g_assert_not_reached ();
99 mono_valloc (void *addr
, size_t length
, int flags
)
102 int mflags
= MEM_COMMIT
;
103 int prot
= prot_from_flags (flags
);
104 /* translate the flags */
106 ptr
= VirtualAlloc (addr
, length
, mflags
, prot
);
111 mono_vfree (void *addr
, size_t length
)
113 int res
= VirtualFree (addr
, 0, MEM_RELEASE
);
121 mono_file_map (size_t length
, int flags
, int fd
, guint64 offset
, void **ret_handle
)
125 HANDLE file
, mapping
;
126 int prot
= prot_from_flags (flags
);
127 /* translate the flags */
128 /*if (flags & MONO_MMAP_PRIVATE)
129 mflags |= MAP_PRIVATE;
130 if (flags & MONO_MMAP_SHARED)
131 mflags |= MAP_SHARED;
132 if (flags & MONO_MMAP_ANON)
133 mflags |= MAP_ANONYMOUS;
134 if (flags & MONO_MMAP_FIXED)
136 if (flags & MONO_MMAP_32BIT)
137 mflags |= MAP_32BIT;*/
139 mflags
= FILE_MAP_READ
;
140 if (flags
& MONO_MMAP_WRITE
)
141 mflags
= FILE_MAP_COPY
;
143 file
= (HANDLE
) _get_osfhandle (fd
);
144 mapping
= CreateFileMapping (file
, NULL
, prot
, 0, 0, NULL
);
147 ptr
= MapViewOfFile (mapping
, mflags
, 0, offset
, length
);
149 CloseHandle (mapping
);
152 *ret_handle
= (void*)mapping
;
157 mono_file_unmap (void *addr
, void *handle
)
159 UnmapViewOfFile (addr
);
160 CloseHandle ((HANDLE
)handle
);
165 mono_mprotect (void *addr
, size_t length
, int flags
)
168 int prot
= prot_from_flags (flags
);
170 if (flags
& MONO_MMAP_DISCARD
) {
171 VirtualFree (addr
, length
, MEM_DECOMMIT
);
172 VirtualAlloc (addr
, length
, MEM_COMMIT
, prot
);
175 return VirtualProtect (addr
, length
, prot
, &oldprot
) == 0;
179 mono_shared_area (void)
181 /* get the pid here */
182 return malloc_shared_area (0);
186 mono_shared_area_remove (void)
188 if (malloced_shared_area
)
189 g_free (malloced_shared_area
);
193 mono_shared_area_for_pid (void *pid
)
199 mono_shared_area_unload (void *area
)
204 mono_shared_area_instances (void **array
, int count
)
210 #if defined(HAVE_MMAP)
214 * Get the page size in use on the system. Addresses and sizes in the
215 * mono_mmap(), mono_munmap() and mono_mprotect() calls must be pagesize
218 * Returns: the page size in bytes.
223 static int saved_pagesize
= 0;
225 return saved_pagesize
;
226 saved_pagesize
= getpagesize ();
227 return saved_pagesize
;
231 prot_from_flags (int flags
)
233 int prot
= PROT_NONE
;
234 /* translate the protection bits */
235 if (flags
& MONO_MMAP_READ
)
237 if (flags
& MONO_MMAP_WRITE
)
239 if (flags
& MONO_MMAP_EXEC
)
246 * @addr: memory address
247 * @length: memory area size
248 * @flags: protection flags
250 * Allocates @length bytes of virtual memory with the @flags
251 * protection. @addr can be a preferred memory address or a
252 * mandatory one if MONO_MMAP_FIXED is set in @flags.
253 * @addr must be pagesize aligned and can be NULL.
254 * @length must be a multiple of pagesize.
256 * Returns: NULL on failure, the address of the memory area otherwise
259 mono_valloc (void *addr
, size_t length
, int flags
)
263 int prot
= prot_from_flags (flags
);
264 /* translate the flags */
265 if (flags
& MONO_MMAP_FIXED
)
267 if (flags
& MONO_MMAP_32BIT
)
270 mflags
|= MAP_ANONYMOUS
;
271 mflags
|= MAP_PRIVATE
;
273 ptr
= mmap (addr
, length
, prot
, mflags
, -1, 0);
274 if (ptr
== (void*)-1) {
275 int fd
= open ("/dev/zero", O_RDONLY
);
277 ptr
= mmap (addr
, length
, prot
, mflags
, fd
, 0);
280 if (ptr
== (void*)-1)
288 * @addr: memory address returned by mono_valloc ()
289 * @length: size of memory area
291 * Remove the memory mapping at the address @addr.
293 * Returns: 0 on success.
296 mono_vfree (void *addr
, size_t length
)
298 return munmap (addr
, length
);
303 * @length: size of data to map
304 * @flags: protection flags
305 * @fd: file descriptor
306 * @offset: offset in the file
307 * @ret_handle: pointer to storage for returning a handle for the map
309 * Map the area of the file pointed to by the file descriptor @fd, at offset
310 * @offset and of size @length in memory according to the protection flags
312 * @offset and @length must be multiples of the page size.
313 * @ret_handle must point to a void*: this value must be used when unmapping
314 * the memory area using mono_file_unmap ().
318 mono_file_map (size_t length
, int flags
, int fd
, guint64 offset
, void **ret_handle
)
322 int prot
= prot_from_flags (flags
);
323 /* translate the flags */
324 if (flags
& MONO_MMAP_PRIVATE
)
325 mflags
|= MAP_PRIVATE
;
326 if (flags
& MONO_MMAP_SHARED
)
327 mflags
|= MAP_SHARED
;
328 if (flags
& MONO_MMAP_FIXED
)
330 if (flags
& MONO_MMAP_32BIT
)
333 ptr
= mmap (0, length
, prot
, mflags
, fd
, offset
);
334 if (ptr
== (void*)-1)
336 *ret_handle
= (void*)length
;
342 * @addr: memory address returned by mono_file_map ()
343 * @handle: handle of memory map
345 * Remove the memory mapping at the address @addr.
346 * @handle must be the value returned in ret_handle by mono_file_map ().
348 * Returns: 0 on success.
351 mono_file_unmap (void *addr
, void *handle
)
353 return munmap (addr
, (size_t)handle
);
358 * @addr: memory address
359 * @length: size of memory area
360 * @flags: new protection flags
362 * Change the protection for the memory area at @addr for @length bytes
363 * to matche the supplied @flags.
364 * If @flags includes MON_MMAP_DISCARD the pages are discarded from memory
365 * and the area is cleared to zero.
366 * @addr must be aligned to the page size.
367 * @length must be a multiple of the page size.
369 * Returns: 0 on success.
372 mono_mprotect (void *addr
, size_t length
, int flags
)
374 int prot
= prot_from_flags (flags
);
376 if (flags
& MONO_MMAP_DISCARD
) {
377 /* on non-linux the pages are not guaranteed to be zeroed (*bsd, osx at least) */
379 if (madvise (addr
, length
, MADV_DONTNEED
))
380 memset (addr
, 0, length
);
382 memset (addr
, 0, length
);
384 madvise (addr
, length
, MADV_DONTNEED
);
385 madvise (addr
, length
, MADV_FREE
);
387 posix_madvise (addr
, length
, POSIX_MADV_DONTNEED
);
391 return mprotect (addr
, length
, prot
);
396 /* dummy malloc-based implementation */
404 mono_valloc (void *addr
, size_t length
, int flags
)
406 return malloc (length
);
410 mono_vfree (void *addr
, size_t length
)
417 mono_mprotect (void *addr
, size_t length
, int flags
)
419 if (flags
& MONO_MMAP_DISCARD
) {
420 memset (addr
, 0, length
);
426 #if defined(HAVE_SHM_OPEN)
429 mono_shared_area_instances_slow (void **array
, int count
, gboolean cleanup
)
434 gpointer
*processes
= mono_process_list (&num
);
435 for (i
= 0; i
< num
; ++i
) {
436 data
= mono_shared_area_for_pid (processes
[i
]);
439 mono_shared_area_unload (data
);
442 array
[j
++] = processes
[i
];
452 mono_shared_area_instances_helper (void **array
, int count
, gboolean cleanup
)
456 int curpid
= getpid ();
457 GDir
*dir
= g_dir_open ("/dev/shm/", 0, NULL
);
459 return mono_shared_area_instances_slow (array
, count
, cleanup
);
460 while ((name
= g_dir_read_name (dir
))) {
463 if (strncmp (name
, "mono.", 5))
465 pid
= strtol (name
+ 5, &nend
, 10);
466 if (pid
<= 0 || nend
== name
+ 5 || *nend
)
470 array
[i
++] = GINT_TO_POINTER (pid
);
474 if (curpid
!= pid
&& kill (pid
, 0) == -1 && (errno
== ESRCH
|| errno
== ENOMEM
)) {
476 g_snprintf (buf
, sizeof (buf
), "/mono.%d", pid
);
485 mono_shared_area (void)
489 /* we should allow the user to configure the size */
490 int size
= mono_pagesize ();
495 /* perform cleanup of segments left over from dead processes */
496 mono_shared_area_instances_helper (NULL
, 0, TRUE
);
498 g_snprintf (buf
, sizeof (buf
), "/mono.%d", pid
);
500 fd
= shm_open (buf
, O_CREAT
|O_EXCL
|O_RDWR
, S_IRUSR
|S_IWUSR
|S_IRGRP
);
501 if (fd
== -1 && errno
== EEXIST
) {
504 fd
= shm_open (buf
, O_CREAT
|O_EXCL
|O_RDWR
, S_IRUSR
|S_IWUSR
|S_IRGRP
);
506 /* in case of failure we try to return a memory area anyway,
507 * even if it means the data can't be read by other processes
510 return malloc_shared_area (pid
);
511 if (ftruncate (fd
, size
) != 0) {
515 res
= mmap (NULL
, size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
516 if (res
== MAP_FAILED
) {
519 return malloc_shared_area (pid
);
521 /* we don't need the file descriptor anymore */
526 header
->stats_start
= sizeof (SAreaHeader
);
527 header
->stats_end
= sizeof (SAreaHeader
);
529 atexit (mono_shared_area_remove
);
534 mono_shared_area_remove (void)
537 g_snprintf (buf
, sizeof (buf
), "/mono.%d", getpid ());
539 if (malloced_shared_area
)
540 g_free (malloced_shared_area
);
544 mono_shared_area_for_pid (void *pid
)
547 /* we should allow the user to configure the size */
548 int size
= mono_pagesize ();
552 g_snprintf (buf
, sizeof (buf
), "/mono.%d", GPOINTER_TO_INT (pid
));
554 fd
= shm_open (buf
, O_RDONLY
, S_IRUSR
|S_IRGRP
);
557 res
= mmap (NULL
, size
, PROT_READ
, MAP_SHARED
, fd
, 0);
558 if (res
== MAP_FAILED
) {
562 /* FIXME: validate the area */
563 /* we don't need the file descriptor anymore */
569 mono_shared_area_unload (void *area
)
571 /* FIXME: currently we load only a page */
572 munmap (area
, mono_pagesize ());
576 mono_shared_area_instances (void **array
, int count
)
578 return mono_shared_area_instances_helper (array
, count
, FALSE
);
582 mono_shared_area (void)
584 return malloc_shared_area (getpid ());
588 mono_shared_area_remove (void)
590 if (malloced_shared_area
)
591 g_free (malloced_shared_area
);
592 malloced_shared_area
= NULL
;
596 mono_shared_area_for_pid (void *pid
)
602 mono_shared_area_unload (void *area
)
607 mono_shared_area_instances (void **array
, int count
)
612 #endif // HAVE_SHM_OPEN