1 /* -----------------------------------------------------------------------------
2 * $Id: MBlock.c,v 1.15 2000/04/03 15:24:21 rrt 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 #define NON_POSIX_SOURCE
18 #include "BlockAlloc.h"
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
28 #ifndef mingw32_TARGET_OS
29 # ifdef HAVE_SYS_MMAN_H
30 # include <sys/mman.h>
42 #if freebsd2_TARGET_OS || freebsd_TARGET_OS
43 /* Executable is loaded from 0x0
44 * Shared libraries are loaded at 0x2000000
45 * Stack is at the top of the address space. The kernel probably owns
46 * 0x8000000 onwards, so we'll pick 0x5000000.
48 #define ASK_FOR_MEM_AT 0x50000000
50 #elif netbsd_TARGET_OS
51 /* NetBSD i386 shared libs are at 0x40000000
53 #define ASK_FOR_MEM_AT 0x50000000
57 #define ASK_FOR_MEM_AT 0x50000000
59 #elif solaris2_TARGET_OS
61 #define ASK_FOR_MEM_AT 0x50000000
65 #define ASK_FOR_MEM_AT 0x50000000
69 #define ASK_FOR_MEM_AT 0x50000000
72 /* doesn't matter, we use a reserve/commit algorithm */
75 #error Dont know where to get memory from on this architecture
76 /* ToDo: memory locations on other architectures */
79 lnat mblocks_allocated = 0;
91 static caddr_t next_request = (caddr_t)ASK_FOR_MEM_AT;
93 lnat size = MBLOCK_SIZE * n;
95 #ifdef solaris2_TARGET_OS
97 int fd = open("/dev/zero",O_RDONLY);
98 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
99 MAP_FIXED | MAP_PRIVATE, fd, 0);
103 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
104 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
106 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
107 MAP_ANON | MAP_PRIVATE, -1, 0);
110 if (ret == (void *)-1) {
111 if (errno == ENOMEM) {
112 barf("getMBlock: out of memory");
114 barf("GetMBlock: mmap failed");
118 if (((W_)ret & MBLOCK_MASK) != 0) {
119 barf("GetMBlock: misaligned block returned");
122 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
124 next_request += size;
126 mblocks_allocated += n;
134 On Win32 platforms we make use of the two-phased virtual memory API
135 to allocate mega blocks. We proceed as follows:
137 Reserve a large chunk of VM (128M at the time), but don't supply a
138 base address that's aligned on a MB boundary. Instead we round up to the
139 nearest from the chunk of VM we're given back from the OS (at the
140 moment we just leave the 'slop' at the beginning of the reserved
141 chunk unused - ToDo: reuse it .)
143 Reserving memory doesn't allocate physical storage (not even in the
144 page file), this is done by committing pages (or mega-blocks in
149 char* base_non_committed = (char*)0;
151 /* Reserve VM 128M at the time to try to minimise the slop cost. */
152 #define SIZE_RESERVED_POOL ( 128 * 1024 * 1024 )
154 /* This predicate should be inlined, really. */
155 /* TODO: this only works for a single chunk */
157 is_heap_alloced(const void* x)
159 return (((char*)(x) >= base_non_committed) &&
160 ((char*)(x) <= (base_non_committed + SIZE_RESERVED_POOL)));
166 static char* base_mblocks = (char*)0;
167 static char* next_request = (char*)0;
168 void* ret = (void*)0;
170 lnat size = MBLOCK_SIZE * n;
172 if ( (base_non_committed == 0) ||
173 (next_request + size > base_non_committed + SIZE_RESERVED_POOL) ) {
174 base_non_committed = VirtualAlloc ( NULL
179 if ( base_non_committed == 0 ) {
181 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
185 /* The returned pointer is not aligned on a mega-block boundary. Make it. */
186 base_mblocks = (char*)((unsigned long)base_non_committed & (unsigned long)0xfff00000) + MBLOCK_SIZE;
188 fprintf(stderr, "Dropping %d bytes off of 128M chunk\n",
189 (unsigned)base_mblocks - (unsigned)base_non_committed);
192 if ( ((char*)base_mblocks + size) > ((char*)base_non_committed + SIZE_RESERVED_POOL) ) {
194 fprintf(stderr, "oops, committed too small a region to start with.");
198 next_request = base_mblocks;
202 /* Commit the mega block(s) to phys mem */
203 if ( ret != (void*)-1 ) {
204 ret = VirtualAlloc(next_request, size, MEM_COMMIT, PAGE_READWRITE);
207 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
213 if (((W_)ret & MBLOCK_MASK) != 0) {
214 barf("GetMBlock: misaligned block returned");
217 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
219 next_request = (char*)next_request + size;
221 mblocks_allocated += n;
226 /* Hand back the physical memory that is allocated to a mega-block.
227 ToDo: chain the released mega block onto some list so that
228 getMBlocks() can get at it.
234 freeMBlock(void* p, nat n)
238 rc = VirtualFree(p, n * MBLOCK_SIZE , MEM_DECOMMIT );
242 fprintf(stderr, "freeMBlocks: VirtualFree failed with: %d\n", GetLastError());