18 #include "mono-mmap.h"
19 #include "mono-proclib.h"
22 #define MAP_ANONYMOUS MAP_ANON
37 static void* malloced_shared_area = NULL;
40 malloc_shared_area (int pid)
42 int size = mono_pagesize ();
43 SAreaHeader *sarea = g_malloc0 (size);
46 sarea->stats_start = sizeof (SAreaHeader);
47 sarea->stats_end = sizeof (SAreaHeader);
58 static int saved_pagesize = 0;
60 return saved_pagesize;
61 GetSystemInfo (&info);
62 saved_pagesize = info.dwAllocationGranularity;
63 return saved_pagesize;
67 prot_from_flags (int flags)
69 int prot = flags & (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
71 case 0: prot = PAGE_NOACCESS; break;
72 case MONO_MMAP_READ: prot = PAGE_READONLY; break;
73 case MONO_MMAP_READ|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READ; break;
74 case MONO_MMAP_READ|MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
75 case MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
76 case MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
77 case MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
78 case MONO_MMAP_EXEC: prot = PAGE_EXECUTE; break;
80 g_assert_not_reached ();
86 mono_valloc (void *addr, size_t length, int flags)
89 int mflags = MEM_COMMIT;
90 int prot = prot_from_flags (flags);
91 /* translate the flags */
93 ptr = VirtualAlloc (addr, length, mflags, prot);
98 mono_vfree (void *addr, size_t length)
100 int res = VirtualFree (addr, 0, MEM_RELEASE);
108 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
112 HANDLE file, mapping;
113 int prot = prot_from_flags (flags);
114 /* translate the flags */
115 /*if (flags & MONO_MMAP_PRIVATE)
116 mflags |= MAP_PRIVATE;
117 if (flags & MONO_MMAP_SHARED)
118 mflags |= MAP_SHARED;
119 if (flags & MONO_MMAP_ANON)
120 mflags |= MAP_ANONYMOUS;
121 if (flags & MONO_MMAP_FIXED)
123 if (flags & MONO_MMAP_32BIT)
124 mflags |= MAP_32BIT;*/
126 mflags = FILE_MAP_READ;
127 if (flags & MONO_MMAP_WRITE)
128 mflags = FILE_MAP_COPY;
130 file = (HANDLE) _get_osfhandle (fd);
131 mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
134 ptr = MapViewOfFile (mapping, mflags, 0, offset, length);
136 CloseHandle (mapping);
139 *ret_handle = (void*)mapping;
144 mono_file_unmap (void *addr, void *handle)
146 UnmapViewOfFile (addr);
147 CloseHandle ((HANDLE)handle);
152 mono_mprotect (void *addr, size_t length, int flags)
155 int prot = prot_from_flags (flags);
157 if (flags & MONO_MMAP_DISCARD) {
158 VirtualFree (addr, length, MEM_DECOMMIT);
159 VirtualAlloc (addr, length, MEM_COMMIT, prot);
162 return VirtualProtect (addr, length, prot, &oldprot) == 0;
166 mono_shared_area (void)
168 /* get the pid here */
169 return malloc_shared_area (0);
173 mono_shared_area_remove (void)
175 if (malloced_shared_area)
176 g_free (malloced_shared_area);
180 mono_shared_area_for_pid (void *pid)
186 mono_shared_area_unload (void *area)
191 mono_shared_area_instances (void **array, int count)
196 #elif defined(HAVE_MMAP)
200 * Get the page size in use on the system. Addresses and sizes in the
201 * mono_mmap(), mono_munmap() and mono_mprotect() calls must be pagesize
204 * Returns: the page size in bytes.
209 static int saved_pagesize = 0;
211 return saved_pagesize;
212 saved_pagesize = getpagesize ();
213 return saved_pagesize;
217 prot_from_flags (int flags)
219 int prot = PROT_NONE;
220 /* translate the protection bits */
221 if (flags & MONO_MMAP_READ)
223 if (flags & MONO_MMAP_WRITE)
225 if (flags & MONO_MMAP_EXEC)
232 * @addr: memory address
233 * @length: memory area size
234 * @flags: protection flags
236 * Allocates @length bytes of virtual memory with the @flags
237 * protection. @addr can be a preferred memory address or a
238 * mandatory one if MONO_MMAP_FIXED is set in @flags.
239 * @addr must be pagesize aligned and can be NULL.
240 * @length must be a multiple of pagesize.
242 * Returns: NULL on failure, the address of the memory area otherwise
245 mono_valloc (void *addr, size_t length, int flags)
249 int prot = prot_from_flags (flags);
250 /* translate the flags */
251 if (flags & MONO_MMAP_FIXED)
253 if (flags & MONO_MMAP_32BIT)
256 mflags |= MAP_ANONYMOUS;
257 mflags |= MAP_PRIVATE;
259 ptr = mmap (addr, length, prot, mflags, -1, 0);
260 if (ptr == (void*)-1) {
261 int fd = open ("/dev/zero", O_RDONLY);
263 ptr = mmap (addr, length, prot, mflags, fd, 0);
266 if (ptr == (void*)-1)
274 * @addr: memory address returned by mono_valloc ()
275 * @length: size of memory area
277 * Remove the memory mapping at the address @addr.
279 * Returns: 0 on success.
282 mono_vfree (void *addr, size_t length)
284 return munmap (addr, length);
289 * @length: size of data to map
290 * @flags: protection flags
291 * @fd: file descriptor
292 * @offset: offset in the file
293 * @ret_handle: pointer to storage for returning a handle for the map
295 * Map the area of the file pointed to by the file descriptor @fd, at offset
296 * @offset and of size @length in memory according to the protection flags
298 * @offset and @length must be multiples of the page size.
299 * @ret_handle must point to a void*: this value must be used when unmapping
300 * the memory area using mono_file_unmap ().
304 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
308 int prot = prot_from_flags (flags);
309 /* translate the flags */
310 if (flags & MONO_MMAP_PRIVATE)
311 mflags |= MAP_PRIVATE;
312 if (flags & MONO_MMAP_SHARED)
313 mflags |= MAP_SHARED;
314 if (flags & MONO_MMAP_FIXED)
316 if (flags & MONO_MMAP_32BIT)
319 ptr = mmap (0, length, prot, mflags, fd, offset);
320 if (ptr == (void*)-1)
322 *ret_handle = (void*)length;
328 * @addr: memory address returned by mono_file_map ()
329 * @handle: handle of memory map
331 * Remove the memory mapping at the address @addr.
332 * @handle must be the value returned in ret_handle by mono_file_map ().
334 * Returns: 0 on success.
337 mono_file_unmap (void *addr, void *handle)
339 return munmap (addr, (size_t)handle);
344 * @addr: memory address
345 * @length: size of memory area
346 * @flags: new protection flags
348 * Change the protection for the memory area at @addr for @length bytes
349 * to matche the supplied @flags.
350 * If @flags includes MON_MMAP_DISCARD the pages are discarded from memory
351 * and the area is cleared to zero.
352 * @addr must be aligned to the page size.
353 * @length must be a multiple of the page size.
355 * Returns: 0 on success.
358 mono_mprotect (void *addr, size_t length, int flags)
360 int prot = prot_from_flags (flags);
362 if (flags & MONO_MMAP_DISCARD) {
363 /* on non-linux the pages are not guaranteed to be zeroed (*bsd, osx at least) */
365 if (madvise (addr, length, MADV_DONTNEED))
366 memset (addr, 0, length);
368 memset (addr, 0, length);
369 madvise (addr, length, MADV_DONTNEED);
370 madvise (addr, length, MADV_FREE);
373 return mprotect (addr, length, prot);
377 mono_shared_area_instances_slow (void **array, int count, gboolean cleanup)
382 gpointer *processes = mono_process_list (&num);
383 for (i = 0; i < num; ++i) {
384 data = mono_shared_area_for_pid (processes [i]);
387 mono_shared_area_unload (data);
390 array [j++] = processes [i];
400 mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
404 int curpid = getpid ();
405 GDir *dir = g_dir_open ("/dev/shm/", 0, NULL);
407 return mono_shared_area_instances_slow (array, count, cleanup);
408 while ((name = g_dir_read_name (dir))) {
411 if (strncmp (name, "mono.", 5))
413 pid = strtol (name + 5, &nend, 10);
414 if (pid <= 0 || nend == name + 5 || *nend)
418 array [i++] = GINT_TO_POINTER (pid);
422 if (curpid != pid && kill (pid, SIGCONT) == -1 && errno == ESRCH) {
424 g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
433 mono_shared_area (void)
437 /* we should allow the user to configure the size */
438 int size = mono_pagesize ();
443 /* perform cleanup of segments left over from dead processes */
444 mono_shared_area_instances_helper (NULL, 0, TRUE);
446 g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
448 fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
449 if (fd == -1 && errno == EEXIST) {
452 fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
454 /* in case of failure we try to return a memory area anyway,
455 * even if it means the data can't be read by other processes
458 return malloc_shared_area (pid);
459 if (ftruncate (fd, size) != 0) {
463 res = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
464 if (res == MAP_FAILED) {
467 return malloc_shared_area (pid);
469 /* we don't need the file descriptor anymore */
474 header->stats_start = sizeof (SAreaHeader);
475 header->stats_end = sizeof (SAreaHeader);
477 atexit (mono_shared_area_remove);
482 mono_shared_area_remove (void)
485 g_snprintf (buf, sizeof (buf), "/mono.%d", getpid ());
487 if (malloced_shared_area)
488 g_free (malloced_shared_area);
492 mono_shared_area_for_pid (void *pid)
495 /* we should allow the user to configure the size */
496 int size = mono_pagesize ();
500 g_snprintf (buf, sizeof (buf), "/mono.%d", GPOINTER_TO_INT (pid));
502 fd = shm_open (buf, O_RDONLY, S_IRUSR|S_IRGRP);
505 res = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
506 if (res == MAP_FAILED) {
510 /* FIXME: validate the area */
511 /* we don't need the file descriptor anymore */
517 mono_shared_area_unload (void *area)
519 /* FIXME: currently we load only a page */
520 munmap (area, mono_pagesize ());
524 mono_shared_area_instances (void **array, int count)
526 return mono_shared_area_instances_helper (array, count, FALSE);
531 /* dummy malloc-based implementation */
539 mono_valloc (void *addr, size_t length, int flags)
541 return malloc (length);
545 mono_vfree (void *addr, size_t length)
552 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
556 void *ptr = malloc (length);
559 cur_offset = lseek (fd, 0, SEEK_CUR);
560 if (lseek (fd, offset, SEEK_SET) != offset) {
564 bytes_read = read (fd, ptr, length);
565 lseek (fd, cur_offset, SEEK_SET);
571 mono_file_unmap (void *addr, void *handle)
578 mono_mprotect (void *addr, size_t length, int flags)
580 if (flags & MONO_MMAP_DISCARD) {
581 memset (addr, 0, length);
587 mono_shared_area (void)
589 return malloc_shared_area (getpid ());
593 mono_shared_area_remove (void)
595 if (malloced_shared_area)
596 g_free (malloced_shared_area);
597 malloced_shared_area = NULL;
601 mono_shared_area_for_pid (void *pid)
607 mono_shared_area_unload (void *area)
612 mono_shared_area_instances (void **array, int count)