1 /* -----------------------------------------------------------------------------
2 * $Id: MBlock.c,v 1.12 1999/09/16 08:37:08 sof 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 || freebsd3_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
53 #define ASK_FOR_MEM_AT 0x50000000
55 #elif solaris2_TARGET_OS
57 #define ASK_FOR_MEM_AT 0x50000000
61 #define ASK_FOR_MEM_AT 0x50000000
65 #define ASK_FOR_MEM_AT 0x50000000
68 /* doesn't matter, we use a reserve/commit algorithm */
71 #error Dont know where to get memory from on this architecture
72 /* ToDo: memory locations on other architectures */
75 lnat mblocks_allocated = 0;
87 static caddr_t next_request = (caddr_t)ASK_FOR_MEM_AT;
89 lnat size = MBLOCK_SIZE * n;
91 #ifdef solaris2_TARGET_OS
93 int fd = open("/dev/zero",O_RDONLY);
94 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
95 MAP_FIXED | MAP_PRIVATE, fd, 0);
99 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
100 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
102 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
103 MAP_ANON | MAP_PRIVATE, -1, 0);
106 if (ret == (void *)-1) {
107 if (errno == ENOMEM) {
108 barf("getMBlock: out of memory");
110 barf("GetMBlock: mmap failed");
114 if (((W_)ret & MBLOCK_MASK) != 0) {
115 barf("GetMBlock: misaligned block returned");
118 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
120 next_request += size;
122 mblocks_allocated += n;
130 On Win32 platforms we make use of the two-phased virtual memory API
131 to allocate mega blocks. We proceed as follows:
133 Reserve a large chunk of VM (128M at the time), but don't supply a
134 base address that's aligned on a MB boundary. Instead we round up to the
135 nearest from the chunk of VM we're given back from the OS (at the
136 moment we just leave the 'slop' at the beginning of the reserved
137 chunk unused - ToDo: reuse it .)
139 Reserving memory doesn't allocate physical storage (not even in the
140 page file), this is done by committing pages (or mega-blocks in
145 char* base_non_committed = (char*)0;
147 /* Reserve VM 128M at the time to try to minimise the slop cost. */
148 #define SIZE_RESERVED_POOL ( 128 * 1024 * 1024 )
150 /* This predicate should be inlined, really. */
152 is_heap_alloced(const void* x)
154 return (((char*)(x) >= base_non_committed) &&
155 ((char*)(x) <= (base_non_committed + 128 * 1024 * 1024)));
161 static char* base_mblocks = (char*)0;
162 static char* next_request = (char*)0;
163 void* ret = (void*)0;
165 lnat size = MBLOCK_SIZE * n;
167 if ( (base_non_committed == 0) ||
168 (next_request + size > base_non_committed + SIZE_RESERVED_POOL) ) {
169 base_non_committed = VirtualAlloc ( NULL
174 if ( base_non_committed == 0 ) {
176 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
180 /* The returned pointer is not aligned on a mega-block boundary. Make it. */
181 base_mblocks = (char*)((unsigned long)base_non_committed & (unsigned long)0xfff00000) + MBLOCK_SIZE;
183 fprintf(stderr, "Dropping %d bytes off of 128M chunk\n",
184 (unsigned)base_mblocks - (unsigned)base_non_committed);
187 if ( ((char*)base_mblocks + size) > ((char*)base_non_committed + SIZE_RESERVED_POOL) ) {
189 fprintf(stderr, "oops, committed too small a region to start with.");
193 next_request = base_mblocks;
197 /* Commit the mega block(s) to phys mem */
198 if ( ret != (void*)-1 ) {
199 ret = VirtualAlloc(next_request, size, MEM_COMMIT, PAGE_READWRITE);
202 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
208 if (((W_)ret & MBLOCK_MASK) != 0) {
209 barf("GetMBlock: misaligned block returned");
212 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
214 next_request = (char*)next_request + size;
216 mblocks_allocated += n;
221 /* Hand back the physical memory that is allocated to a mega-block.
222 ToDo: chain the released mega block onto some list so that
223 getMBlocks() can get at it.
229 freeMBlock(void* p, nat n)
233 rc = VirtualFree(p, n * MBLOCK_SIZE , MEM_DECOMMIT );
237 fprintf(stderr, "freeMBlocks: VirtualFree failed with: %d\n", GetLastError());