1 /* -----------------------------------------------------------------------------
2 * $Id: MBlock.c,v 1.29 2002/07/17 09:21:50 simonmar Exp $
4 * (c) The GHC Team 1998-1999
6 * MegaBlock Allocator Interface. This file contains all the dirty
7 * architecture-dependent hackery required to get a chunk of aligned
8 * memory from the operating system.
10 * ---------------------------------------------------------------------------*/
12 /* This is non-posix compliant. */
13 /* #include "PosixSource.h" */
19 #include "BlockAlloc.h"
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
29 #ifndef mingw32_TARGET_OS
30 # ifdef HAVE_SYS_MMAN_H
31 # include <sys/mman.h>
45 lnat mblocks_allocated = 0;
53 #if !defined(mingw32_TARGET_OS) && !defined(cygwin32_TARGET_OS)
57 static caddr_t next_request = (caddr_t)HEAP_BASE;
59 lnat size = MBLOCK_SIZE * n;
61 #ifdef solaris2_TARGET_OS
63 int fd = open("/dev/zero",O_RDONLY);
64 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
65 MAP_FIXED | MAP_PRIVATE, fd, 0);
69 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
70 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
71 #elif darwin_TARGET_OS
72 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
73 MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
75 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
76 MAP_ANON | MAP_PRIVATE, -1, 0);
79 if (ret == (void *)-1) {
80 if (errno == ENOMEM) {
81 barf("getMBlock: out of memory (blocks requested: %d)", n);
83 barf("GetMBlock: mmap failed");
87 if (((W_)ret & MBLOCK_MASK) != 0) {
88 barf("GetMBlock: misaligned block %p returned when allocating %d megablock(s) at %p", ret, n, next_request);
91 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %p\n",n,ret));
95 mblocks_allocated += n;
100 #else /* defined(mingw32_TARGET_OS) || defined(cygwin32_TARGET_OS) */
103 On Win32 platforms we make use of the two-phased virtual memory API
104 to allocate mega blocks. We proceed as follows:
106 Reserve a large chunk of VM (256M at the time, or what the user asked
107 for via the -M option), but don't supply a base address that's aligned on
108 a MB boundary. Instead we round up to the nearest mblock from the chunk of
109 VM we're handed back from the OS (at the moment we just leave the 'slop' at
110 the beginning of the reserved chunk unused - ToDo: reuse it .)
112 Reserving memory doesn't allocate physical storage (not even in the
113 page file), this is done later on by committing pages (or mega-blocks in
117 char* base_non_committed = (char*)0;
118 char* end_non_committed = (char*)0;
120 /* Default is to reserve 256M of VM to minimise the slop cost. */
121 #define SIZE_RESERVED_POOL ( 256 * 1024 * 1024 )
123 /* Number of bytes reserved */
124 static unsigned long size_reserved_pool = SIZE_RESERVED_POOL;
126 /* This predicate should be inlined, really. */
127 /* TODO: this only works for a single chunk */
129 is_heap_alloced(const void* x)
131 return (((char*)(x) >= base_non_committed) &&
132 ((char*)(x) <= end_non_committed));
138 static char* base_mblocks = (char*)0;
139 static char* next_request = (char*)0;
140 void* ret = (void*)0;
142 lnat size = MBLOCK_SIZE * n;
144 if ( (base_non_committed == 0) || (next_request + size > end_non_committed) ) {
145 if (base_non_committed) {
146 barf("RTS exhausted max heap size (%d bytes)\n", size_reserved_pool);
148 if (RtsFlags.GcFlags.maxHeapSize != 0) {
149 size_reserved_pool = BLOCK_SIZE * RtsFlags.GcFlags.maxHeapSize;
150 if (size_reserved_pool < MBLOCK_SIZE) {
151 size_reserved_pool = 2*MBLOCK_SIZE;
154 base_non_committed = VirtualAlloc ( NULL
159 if ( base_non_committed == 0 ) {
160 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %ld\n", GetLastError());
163 end_non_committed = (char*)base_non_committed + (unsigned long)size_reserved_pool;
164 /* The returned pointer is not aligned on a mega-block boundary. Make it. */
165 base_mblocks = (char*)((unsigned long)base_non_committed & (unsigned long)0xfff00000) + MBLOCK_SIZE;
167 fprintf(stderr, "getMBlocks: Dropping %d bytes off of 256M chunk\n",
168 (unsigned)base_mblocks - (unsigned)base_non_committed);
171 if ( ((char*)base_mblocks + size) > end_non_committed ) {
172 fprintf(stderr, "getMBlocks: oops, committed too small a region to start with.");
175 next_request = base_mblocks;
179 /* Commit the mega block(s) to phys mem */
180 if ( ret != (void*)-1 ) {
181 ret = VirtualAlloc(next_request, size, MEM_COMMIT, PAGE_READWRITE);
183 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %ld\n", GetLastError());
188 if (((W_)ret & MBLOCK_MASK) != 0) {
189 barf("getMBlocks: misaligned block returned");
192 if (ret == (void*)-1) {
193 barf("getMBlocks: unknown memory allocation failure on Win32.");
196 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at 0x%x\n",n,(nat)ret));
197 next_request = (char*)next_request + size;
199 mblocks_allocated += n;
204 /* Hand back the physical memory that is allocated to a mega-block.
205 ToDo: chain the released mega block onto some list so that
206 getMBlocks() can get at it.
212 freeMBlock(void* p, nat n)
216 rc = VirtualFree(p, n * MBLOCK_SIZE , MEM_DECOMMIT );
220 fprintf(stderr, "freeMBlocks: VirtualFree failed with: %d\n", GetLastError());