Merge pull request #3547 from cmp-/remove-obsolete-stack-checks-win32
[mono.git] / mono / utils / mono-mmap.c
1 /*
2  * mono-mmap.c: Support for mapping code into the process address space
3  *
4  * Author:
5  *   Mono Team (mono-list@lists.ximian.com)
6  *
7  * Copyright 2001-2008 Novell, Inc.
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10
11 #include "config.h"
12
13 #ifdef HOST_WIN32
14 #include <windows.h>
15 #include <io.h>
16 #else
17 #include <sys/types.h>
18 #if HAVE_SYS_STAT_H
19 #include <sys/stat.h>
20 #endif
21 #if HAVE_SYS_MMAN_H
22 #include <sys/mman.h>
23 #endif
24 #ifdef HAVE_SIGNAL_H
25 #include <signal.h>
26 #endif
27 #include <fcntl.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #endif
33
34 #include "mono-mmap.h"
35 #include "mono-mmap-internals.h"
36 #include "mono-proclib.h"
37 #include <mono/utils/mono-threads.h>
38 #include <mono/utils/atomic.h>
39 #include <mono/utils/mono-counters.h>
40
41
42 #define BEGIN_CRITICAL_SECTION do { \
43         MonoThreadInfo *__info = mono_thread_info_current_unchecked (); \
44         if (__info) __info->inside_critical_region = TRUE;      \
45
46 #define END_CRITICAL_SECTION \
47         if (__info) __info->inside_critical_region = FALSE;     \
48 } while (0)     \
49
50 #ifndef MAP_ANONYMOUS
51 #define MAP_ANONYMOUS MAP_ANON
52 #endif
53
54 #ifndef MAP_32BIT
55 #define MAP_32BIT 0
56 #endif
57
58 typedef struct {
59         int size;
60         int pid;
61         int reserved;
62         short stats_start;
63         short stats_end;
64 } SAreaHeader;
65
66 static void* malloced_shared_area = NULL;
67
68 static void*
69 malloc_shared_area (int pid)
70 {
71         int size = mono_pagesize ();
72         SAreaHeader *sarea = (SAreaHeader *) g_malloc0 (size);
73         sarea->size = size;
74         sarea->pid = pid;
75         sarea->stats_start = sizeof (SAreaHeader);
76         sarea->stats_end = sizeof (SAreaHeader);
77
78         return sarea;
79 }
80
81 static char*
82 aligned_address (char *mem, size_t size, size_t alignment)
83 {
84         char *aligned = (char*)((size_t)(mem + (alignment - 1)) & ~(alignment - 1));
85         g_assert (aligned >= mem && aligned + size <= mem + size + alignment && !((size_t)aligned & (alignment - 1)));
86         return aligned;
87 }
88
89 static volatile size_t allocation_count [MONO_MEM_ACCOUNT_MAX];
90
91 static void
92 account_mem (MonoMemAccountType type, ssize_t size)
93 {
94 #if SIZEOF_VOID_P == 4
95         InterlockedAdd ((volatile gint32*)&allocation_count [type], (gint32)size);
96 #else
97         InterlockedAdd64 ((volatile gint64*)&allocation_count [type], (gint64)size);
98 #endif
99 }
100
101 const char*
102 mono_mem_account_type_name (MonoMemAccountType type)
103 {
104         static const char *names[] = {
105                 "code",
106                 "hazard pointers",
107                 "domain",
108                 "SGen internal",
109                 "SGen nursery",
110                 "SGen LOS",
111                 "SGen mark&sweep",
112                 "SGen card table",
113                 "SGen shadow card table",
114                 "SGen debugging",
115                 "SGen binary protocol",
116                 "exceptions",
117                 "profiler",
118                 "other"
119         };
120
121         return names [type];
122 }
123
124 void
125 mono_mem_account_register_counters (void)
126 {
127         for (int i = 0; i < MONO_MEM_ACCOUNT_MAX; ++i) {
128                 const char *prefix = "Valloc ";
129                 const char *name = mono_mem_account_type_name (i);
130                 char descr [128];
131                 g_assert (strlen (prefix) + strlen (name) < sizeof (descr));
132                 sprintf (descr, "%s%s", prefix, name);
133                 mono_counters_register (descr, MONO_COUNTER_WORD | MONO_COUNTER_RUNTIME | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE, (void*)&allocation_count [i]);
134         }
135 }
136
137 #ifdef HOST_WIN32
138
139 int
140 mono_pagesize (void)
141 {
142         SYSTEM_INFO info;
143         static int saved_pagesize = 0;
144         if (saved_pagesize)
145                 return saved_pagesize;
146         GetSystemInfo (&info);
147         saved_pagesize = info.dwAllocationGranularity;
148         return saved_pagesize;
149 }
150
151 static int
152 prot_from_flags (int flags)
153 {
154         int prot = flags & (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
155         switch (prot) {
156         case 0: prot = PAGE_NOACCESS; break;
157         case MONO_MMAP_READ: prot = PAGE_READONLY; break;
158         case MONO_MMAP_READ|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READ; break;
159         case MONO_MMAP_READ|MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
160         case MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
161         case MONO_MMAP_WRITE: prot = PAGE_READWRITE; break;
162         case MONO_MMAP_WRITE|MONO_MMAP_EXEC: prot = PAGE_EXECUTE_READWRITE; break;
163         case MONO_MMAP_EXEC: prot = PAGE_EXECUTE; break;
164         default:
165                 g_assert_not_reached ();
166         }
167         return prot;
168 }
169
170 void*
171 mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
172 {
173         void *ptr;
174         int mflags = MEM_RESERVE|MEM_COMMIT;
175         int prot = prot_from_flags (flags);
176         /* translate the flags */
177
178         ptr = VirtualAlloc (addr, length, mflags, prot);
179
180         account_mem (type, (ssize_t)length);
181
182         return ptr;
183 }
184
185 void*
186 mono_valloc_aligned (size_t length, size_t alignment, int flags, MonoMemAccountType type)
187 {
188         int prot = prot_from_flags (flags);
189         char *mem = VirtualAlloc (NULL, length + alignment, MEM_RESERVE, prot);
190         char *aligned;
191
192         if (!mem)
193                 return NULL;
194
195         aligned = aligned_address (mem, length, alignment);
196
197         aligned = VirtualAlloc (aligned, length, MEM_COMMIT, prot);
198         g_assert (aligned);
199
200         account_mem (type, (ssize_t)length);
201
202         return aligned;
203 }
204
205 #define HAVE_VALLOC_ALIGNED
206
207 int
208 mono_vfree (void *addr, size_t length, MonoMemAccountType type)
209 {
210         MEMORY_BASIC_INFORMATION mbi;
211         SIZE_T query_result = VirtualQuery (addr, &mbi, sizeof (mbi));
212         BOOL res;
213
214         g_assert (query_result);
215
216         res = VirtualFree (mbi.AllocationBase, 0, MEM_RELEASE);
217
218         g_assert (res);
219
220         account_mem (type, -(ssize_t)length);
221
222         return 0;
223 }
224
225 void*
226 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
227 {
228         void *ptr;
229         int mflags = 0;
230         HANDLE file, mapping;
231         int prot = prot_from_flags (flags);
232         /* translate the flags */
233         /*if (flags & MONO_MMAP_PRIVATE)
234                 mflags |= MAP_PRIVATE;
235         if (flags & MONO_MMAP_SHARED)
236                 mflags |= MAP_SHARED;
237         if (flags & MONO_MMAP_ANON)
238                 mflags |= MAP_ANONYMOUS;
239         if (flags & MONO_MMAP_FIXED)
240                 mflags |= MAP_FIXED;
241         if (flags & MONO_MMAP_32BIT)
242                 mflags |= MAP_32BIT;*/
243
244         mflags = FILE_MAP_READ;
245         if (flags & MONO_MMAP_WRITE)
246                 mflags = FILE_MAP_COPY;
247
248         file = (HANDLE) _get_osfhandle (fd);
249         mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
250         if (mapping == NULL)
251                 return NULL;
252         ptr = MapViewOfFile (mapping, mflags, 0, offset, length);
253         if (ptr == NULL) {
254                 CloseHandle (mapping);
255                 return NULL;
256         }
257         *ret_handle = (void*)mapping;
258         return ptr;
259 }
260
261 int
262 mono_file_unmap (void *addr, void *handle)
263 {
264         UnmapViewOfFile (addr);
265         CloseHandle ((HANDLE)handle);
266         return 0;
267 }
268
269 int
270 mono_mprotect (void *addr, size_t length, int flags)
271 {
272         DWORD oldprot;
273         int prot = prot_from_flags (flags);
274
275         if (flags & MONO_MMAP_DISCARD) {
276                 VirtualFree (addr, length, MEM_DECOMMIT);
277                 VirtualAlloc (addr, length, MEM_COMMIT, prot);
278                 return 0;
279         }
280         return VirtualProtect (addr, length, prot, &oldprot) == 0;
281 }
282
283 void*
284 mono_shared_area (void)
285 {
286         if (!malloced_shared_area)
287                 malloced_shared_area = malloc_shared_area (0);
288         /* get the pid here */
289         return malloced_shared_area;
290 }
291
292 void
293 mono_shared_area_remove (void)
294 {
295         if (malloced_shared_area)
296                 g_free (malloced_shared_area);
297         malloced_shared_area = NULL;
298 }
299
300 void*
301 mono_shared_area_for_pid (void *pid)
302 {
303         return NULL;
304 }
305
306 void
307 mono_shared_area_unload (void *area)
308 {
309 }
310
311 int
312 mono_shared_area_instances (void **array, int count)
313 {
314         return 0;
315 }
316
317 #else
318 #if defined(HAVE_MMAP)
319
320 /**
321  * mono_pagesize:
322  * Get the page size in use on the system. Addresses and sizes in the
323  * mono_mmap(), mono_munmap() and mono_mprotect() calls must be pagesize
324  * aligned.
325  *
326  * Returns: the page size in bytes.
327  */
328 int
329 mono_pagesize (void)
330 {
331         static int saved_pagesize = 0;
332         if (saved_pagesize)
333                 return saved_pagesize;
334         saved_pagesize = getpagesize ();
335         return saved_pagesize;
336 }
337
338 static int
339 prot_from_flags (int flags)
340 {
341         int prot = PROT_NONE;
342         /* translate the protection bits */
343         if (flags & MONO_MMAP_READ)
344                 prot |= PROT_READ;
345         if (flags & MONO_MMAP_WRITE)
346                 prot |= PROT_WRITE;
347         if (flags & MONO_MMAP_EXEC)
348                 prot |= PROT_EXEC;
349         return prot;
350 }
351
352 /**
353  * mono_valloc:
354  * @addr: memory address
355  * @length: memory area size
356  * @flags: protection flags
357  *
358  * Allocates @length bytes of virtual memory with the @flags
359  * protection. @addr can be a preferred memory address or a
360  * mandatory one if MONO_MMAP_FIXED is set in @flags.
361  * @addr must be pagesize aligned and can be NULL.
362  * @length must be a multiple of pagesize.
363  *
364  * Returns: NULL on failure, the address of the memory area otherwise
365  */
366 void*
367 mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
368 {
369         void *ptr;
370         int mflags = 0;
371         int prot = prot_from_flags (flags);
372         /* translate the flags */
373         if (flags & MONO_MMAP_FIXED)
374                 mflags |= MAP_FIXED;
375         if (flags & MONO_MMAP_32BIT)
376                 mflags |= MAP_32BIT;
377
378         mflags |= MAP_ANONYMOUS;
379         mflags |= MAP_PRIVATE;
380
381         BEGIN_CRITICAL_SECTION;
382         ptr = mmap (addr, length, prot, mflags, -1, 0);
383         if (ptr == MAP_FAILED) {
384                 int fd = open ("/dev/zero", O_RDONLY);
385                 if (fd != -1) {
386                         ptr = mmap (addr, length, prot, mflags, fd, 0);
387                         close (fd);
388                 }
389         }
390         END_CRITICAL_SECTION;
391
392         if (ptr == MAP_FAILED)
393                 return NULL;
394
395         account_mem (type, (ssize_t)length);
396
397         return ptr;
398 }
399
400 /**
401  * mono_vfree:
402  * @addr: memory address returned by mono_valloc ()
403  * @length: size of memory area
404  *
405  * Remove the memory mapping at the address @addr.
406  *
407  * Returns: 0 on success.
408  */
409 int
410 mono_vfree (void *addr, size_t length, MonoMemAccountType type)
411 {
412         int res;
413         BEGIN_CRITICAL_SECTION;
414         res = munmap (addr, length);
415         END_CRITICAL_SECTION;
416
417         account_mem (type, -(ssize_t)length);
418
419         return res;
420 }
421
422 /**
423  * mono_file_map:
424  * @length: size of data to map
425  * @flags: protection flags
426  * @fd: file descriptor
427  * @offset: offset in the file
428  * @ret_handle: pointer to storage for returning a handle for the map
429  *
430  * Map the area of the file pointed to by the file descriptor @fd, at offset
431  * @offset and of size @length in memory according to the protection flags
432  * @flags.
433  * @offset and @length must be multiples of the page size.
434  * @ret_handle must point to a void*: this value must be used when unmapping
435  * the memory area using mono_file_unmap ().
436  *
437  */
438 void*
439 mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
440 {
441         void *ptr;
442         int mflags = 0;
443         int prot = prot_from_flags (flags);
444         /* translate the flags */
445         if (flags & MONO_MMAP_PRIVATE)
446                 mflags |= MAP_PRIVATE;
447         if (flags & MONO_MMAP_SHARED)
448                 mflags |= MAP_SHARED;
449         if (flags & MONO_MMAP_FIXED)
450                 mflags |= MAP_FIXED;
451         if (flags & MONO_MMAP_32BIT)
452                 mflags |= MAP_32BIT;
453
454         BEGIN_CRITICAL_SECTION;
455         ptr = mmap (0, length, prot, mflags, fd, offset);
456         END_CRITICAL_SECTION;
457         if (ptr == MAP_FAILED)
458                 return NULL;
459         *ret_handle = (void*)length;
460         return ptr;
461 }
462
463 /**
464  * mono_file_unmap:
465  * @addr: memory address returned by mono_file_map ()
466  * @handle: handle of memory map
467  *
468  * Remove the memory mapping at the address @addr.
469  * @handle must be the value returned in ret_handle by mono_file_map ().
470  *
471  * Returns: 0 on success.
472  */
473 int
474 mono_file_unmap (void *addr, void *handle)
475 {
476         int res;
477
478         BEGIN_CRITICAL_SECTION;
479         res = munmap (addr, (size_t)handle);
480         END_CRITICAL_SECTION;
481
482         return res;
483 }
484
485 /**
486  * mono_mprotect:
487  * @addr: memory address
488  * @length: size of memory area
489  * @flags: new protection flags
490  *
491  * Change the protection for the memory area at @addr for @length bytes
492  * to matche the supplied @flags.
493  * If @flags includes MON_MMAP_DISCARD the pages are discarded from memory
494  * and the area is cleared to zero.
495  * @addr must be aligned to the page size.
496  * @length must be a multiple of the page size.
497  *
498  * Returns: 0 on success.
499  */
500 #if defined(__native_client__)
501 int
502 mono_mprotect (void *addr, size_t length, int flags)
503 {
504         int prot = prot_from_flags (flags);
505         void *new_addr;
506
507         if (flags & MONO_MMAP_DISCARD) memset (addr, 0, length);
508
509         new_addr = mmap(addr, length, prot, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
510         if (new_addr == addr) return 0;
511         return -1;
512 }
513 #else
514 int
515 mono_mprotect (void *addr, size_t length, int flags)
516 {
517         int prot = prot_from_flags (flags);
518
519         if (flags & MONO_MMAP_DISCARD) {
520                 /* on non-linux the pages are not guaranteed to be zeroed (*bsd, osx at least) */
521 #ifdef __linux__
522                 if (madvise (addr, length, MADV_DONTNEED))
523                         memset (addr, 0, length);
524 #else
525                 memset (addr, 0, length);
526 #ifdef HAVE_MADVISE
527                 madvise (addr, length, MADV_DONTNEED);
528                 madvise (addr, length, MADV_FREE);
529 #else
530                 posix_madvise (addr, length, POSIX_MADV_DONTNEED);
531 #endif
532 #endif
533         }
534         return mprotect (addr, length, prot);
535 }
536 #endif // __native_client__
537
538 #else
539
540 /* dummy malloc-based implementation */
541 int
542 mono_pagesize (void)
543 {
544         return 4096;
545 }
546
547 void*
548 mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
549 {
550         return g_malloc (length);
551 }
552
553 void*
554 mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type)
555 {
556         g_assert_not_reached ();
557 }
558
559 #define HAVE_VALLOC_ALIGNED
560
561 int
562 mono_vfree (void *addr, size_t length, MonoMemAccountType type)
563 {
564         g_free (addr);
565         return 0;
566 }
567
568 int
569 mono_mprotect (void *addr, size_t length, int flags)
570 {
571         if (flags & MONO_MMAP_DISCARD) {
572                 memset (addr, 0, length);
573         }
574         return 0;
575 }
576
577 #endif // HAVE_MMAP
578
579 #if defined(HAVE_SHM_OPEN) && !defined (DISABLE_SHARED_PERFCOUNTERS)
580
581 static int use_shared_area;
582
583 static gboolean
584 shared_area_disabled (void)
585 {
586         if (!use_shared_area) {
587                 if (g_getenv ("MONO_DISABLE_SHARED_AREA"))
588                         use_shared_area = -1;
589                 else
590                         use_shared_area = 1;
591         }
592         return use_shared_area == -1;
593 }
594
595 static int
596 mono_shared_area_instances_slow (void **array, int count, gboolean cleanup)
597 {
598         int i, j = 0;
599         int num;
600         void *data;
601         gpointer *processes = mono_process_list (&num);
602         for (i = 0; i < num; ++i) {
603                 data = mono_shared_area_for_pid (processes [i]);
604                 if (!data)
605                         continue;
606                 mono_shared_area_unload (data);
607                 if (!cleanup) {
608                         if (j < count)
609                                 array [j++] = processes [i];
610                         else
611                                 break;
612                 }
613         }
614         g_free (processes);
615         return j;
616 }
617
618 static int
619 mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
620 {
621         const char *name;
622         int i = 0;
623         int curpid = getpid ();
624         GDir *dir = g_dir_open ("/dev/shm/", 0, NULL);
625         if (!dir)
626                 return mono_shared_area_instances_slow (array, count, cleanup);
627         while ((name = g_dir_read_name (dir))) {
628                 int pid;
629                 char *nend;
630                 if (strncmp (name, "mono.", 5))
631                         continue;
632                 pid = strtol (name + 5, &nend, 10);
633                 if (pid <= 0 || nend == name + 5 || *nend)
634                         continue;
635                 if (!cleanup) {
636                         if (i < count)
637                                 array [i++] = GINT_TO_POINTER (pid);
638                         else
639                                 break;
640                 }
641                 if (curpid != pid && kill (pid, 0) == -1 && (errno == ESRCH || errno == ENOMEM)) {
642                         char buf [128];
643                         g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
644                         shm_unlink (buf);
645                 }
646         }
647         g_dir_close (dir);
648         return i;
649 }
650
651 void*
652 mono_shared_area (void)
653 {
654         int fd;
655         int pid = getpid ();
656         /* we should allow the user to configure the size */
657         int size = mono_pagesize ();
658         char buf [128];
659         void *res;
660         SAreaHeader *header;
661
662         if (shared_area_disabled ()) {
663                 if (!malloced_shared_area)
664                         malloced_shared_area = malloc_shared_area (0);
665                 /* get the pid here */
666                 return malloced_shared_area;
667         }
668
669         /* perform cleanup of segments left over from dead processes */
670         mono_shared_area_instances_helper (NULL, 0, TRUE);
671
672         g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
673
674         fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
675         if (fd == -1 && errno == EEXIST) {
676                 /* leftover */
677                 shm_unlink (buf);
678                 fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
679         }
680         /* in case of failure we try to return a memory area anyway,
681          * even if it means the data can't be read by other processes
682          */
683         if (fd == -1)
684                 return malloc_shared_area (pid);
685         if (ftruncate (fd, size) != 0) {
686                 shm_unlink (buf);
687                 close (fd);
688         }
689         BEGIN_CRITICAL_SECTION;
690         res = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
691         END_CRITICAL_SECTION;
692
693         if (res == MAP_FAILED) {
694                 shm_unlink (buf);
695                 close (fd);
696                 return malloc_shared_area (pid);
697         }
698         /* we don't need the file descriptor anymore */
699         close (fd);
700         header = (SAreaHeader *) res;
701         header->size = size;
702         header->pid = pid;
703         header->stats_start = sizeof (SAreaHeader);
704         header->stats_end = sizeof (SAreaHeader);
705
706         mono_atexit (mono_shared_area_remove);
707         return res;
708 }
709
710 void
711 mono_shared_area_remove (void)
712 {
713         char buf [128];
714
715         if (shared_area_disabled ()) {
716                 if (malloced_shared_area)
717                         g_free (malloced_shared_area);
718                 return;
719         }
720
721         g_snprintf (buf, sizeof (buf), "/mono.%d", getpid ());
722         shm_unlink (buf);
723         if (malloced_shared_area)
724                 g_free (malloced_shared_area);
725 }
726
727 void*
728 mono_shared_area_for_pid (void *pid)
729 {
730         int fd;
731         /* we should allow the user to configure the size */
732         int size = mono_pagesize ();
733         char buf [128];
734         void *res;
735
736         if (shared_area_disabled ())
737                 return NULL;
738
739         g_snprintf (buf, sizeof (buf), "/mono.%d", GPOINTER_TO_INT (pid));
740
741         fd = shm_open (buf, O_RDONLY, S_IRUSR|S_IRGRP);
742         if (fd == -1)
743                 return NULL;
744         BEGIN_CRITICAL_SECTION;
745         res = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
746         END_CRITICAL_SECTION;
747
748         if (res == MAP_FAILED) {
749                 close (fd);
750                 return NULL;
751         }
752         /* FIXME: validate the area */
753         /* we don't need the file descriptor anymore */
754         close (fd);
755         return res;
756 }
757
758 void
759 mono_shared_area_unload  (void *area)
760 {
761         /* FIXME: currently we load only a page */
762         BEGIN_CRITICAL_SECTION;
763         munmap (area, mono_pagesize ());
764         END_CRITICAL_SECTION;
765 }
766
767 int
768 mono_shared_area_instances (void **array, int count)
769 {
770         return mono_shared_area_instances_helper (array, count, FALSE);
771 }
772 #else
773 void*
774 mono_shared_area (void)
775 {
776         if (!malloced_shared_area)
777                 malloced_shared_area = malloc_shared_area (getpid ());
778         /* get the pid here */
779         return malloced_shared_area;
780 }
781
782 void
783 mono_shared_area_remove (void)
784 {
785         if (malloced_shared_area)
786                 g_free (malloced_shared_area);
787         malloced_shared_area = NULL;
788 }
789
790 void*
791 mono_shared_area_for_pid (void *pid)
792 {
793         return NULL;
794 }
795
796 void
797 mono_shared_area_unload (void *area)
798 {
799 }
800
801 int
802 mono_shared_area_instances (void **array, int count)
803 {
804         return 0;
805 }
806
807 #endif // HAVE_SHM_OPEN
808
809 #endif // HOST_WIN32
810
811 #ifndef HAVE_VALLOC_ALIGNED
812 void*
813 mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type)
814 {
815         /* Allocate twice the memory to be able to put the block on an aligned address */
816         char *mem = (char *) mono_valloc (NULL, size + alignment, flags, type);
817         char *aligned;
818
819         if (!mem)
820                 return NULL;
821
822         aligned = aligned_address (mem, size, alignment);
823
824         if (aligned > mem)
825                 mono_vfree (mem, aligned - mem, type);
826         if (aligned + size < mem + size + alignment)
827                 mono_vfree (aligned + size, (mem + size + alignment) - (aligned + size), type);
828
829         return aligned;
830 }
831 #endif
832
833 int
834 mono_pages_not_faulted (void *addr, size_t size)
835 {
836 #ifdef HAVE_MINCORE
837         int i;
838         gint64 count;
839         int pagesize = mono_pagesize ();
840         int npages = (size + pagesize - 1) / pagesize;
841         char *faulted = (char *) g_malloc0 (sizeof (char*) * npages);
842
843         /*
844          * We cast `faulted` to void* because Linux wants an unsigned
845          * char* while BSD wants a char*.
846          */
847 #ifdef __linux__
848         if (mincore (addr, size, (unsigned char *)faulted) != 0) {
849 #else
850         if (mincore (addr, size, (char *)faulted) != 0) {
851 #endif
852                 count = -1;
853         } else {
854                 count = 0;
855                 for (i = 0; i < npages; ++i) {
856                         if (faulted [i] != 0)
857                                 ++count;
858                 }
859         }
860
861         g_free (faulted);
862
863         return count;
864 #else
865         return -1;
866 #endif
867 }