1 /* -----------------------------------------------------------------------------
2 * $Id: MBlock.c,v 1.10 1999/03/03 19:04:56 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
64 /* doesn't matter, we use a reserve/commit algorithm */
67 #error Dont know where to get memory from on this architecture
68 /* ToDo: memory locations on other architectures */
71 lnat mblocks_allocated = 0;
83 static caddr_t next_request = (caddr_t)ASK_FOR_MEM_AT;
85 lnat size = MBLOCK_SIZE * n;
87 #ifdef solaris2_TARGET_OS
89 int fd = open("/dev/zero",O_RDONLY);
90 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
91 MAP_FIXED | MAP_PRIVATE, fd, 0);
95 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
96 MAP_ANON | MAP_PRIVATE, -1, 0);
99 if (ret == (void *)-1) {
100 if (errno == ENOMEM) {
101 barf("getMBlock: out of memory");
103 barf("GetMBlock: mmap failed");
107 if (((W_)ret & MBLOCK_MASK) != 0) {
108 barf("GetMBlock: misaligned block returned");
111 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
113 next_request += size;
115 mblocks_allocated += n;
123 On Win32 platforms we make use of the two-phased virtual memory API
124 to allocate mega blocks. We proceed as follows:
126 Reserve a large chunk of VM (128M at the time), but don't supply a
127 base address that's aligned on a MB boundary. Instead we round up to the
128 nearest from the chunk of VM we're given back from the OS (at the
129 moment we just leave the 'slop' at the beginning of the reserved
130 chunk unused - ToDo: reuse it .)
132 Reserving memory doesn't allocate physical storage (not even in the
133 page file), this is done by committing pages (or mega-blocks in
138 char* base_non_committed = (char*)0;
140 /* Reserve VM 128M at the time to try to minimise the slop cost. */
141 #define SIZE_RESERVED_POOL ( 128 * 1024 * 1024 )
143 /* This predicate should be inlined, really. */
145 is_heap_alloced(const void* x)
147 return (((char*)(x) >= base_non_committed) &&
148 ((char*)(x) <= (base_non_committed + 128 * 1024 * 1024)));
154 static char* base_mblocks = (char*)0;
155 static char* next_request = (char*)0;
156 void* ret = (void*)0;
158 lnat size = MBLOCK_SIZE * n;
160 if ( (base_non_committed == 0) ||
161 (next_request + size > base_non_committed + SIZE_RESERVED_POOL) ) {
162 base_non_committed = VirtualAlloc ( NULL
167 if ( base_non_committed == 0 ) {
169 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
173 /* The returned pointer is not aligned on a mega-block boundary. Make it. */
174 base_mblocks = (char*)((unsigned)base_non_committed & (unsigned)0xfff00000) + 0x100000;
176 fprintf(stderr, "Dropping %d bytes off of 128M chunk\n",
177 (unsigned)base_mblocks - (unsigned)base_non_committed);
180 if ( ((char*)base_mblocks + size) > ((char*)base_non_committed + SIZE_RESERVED_POOL) ) {
182 fprintf(stderr, "oops, committed too small a region to start with.");
186 next_request = base_mblocks;
190 /* Commit the mega block(s) to phys mem */
191 if ( ret != (void*)-1 ) {
192 ret = VirtualAlloc(next_request, size, MEM_COMMIT, PAGE_READWRITE);
195 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
201 if (((W_)ret & MBLOCK_MASK) != 0) {
202 barf("GetMBlock: misaligned block returned");
205 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
207 next_request = (char*)next_request + size;
209 mblocks_allocated += n;
214 /* Hand back the physical memory that is allocated to a mega-block.
215 ToDo: chain the released mega block onto some list so that
216 getMBlocks() can get at it.
222 freeMBlock(void* p, nat n)
226 rc = VirtualFree(p, n * MBLOCK_SIZE , MEM_DECOMMIT );
230 fprintf(stderr, "freeMBlocks: VirtualFree failed with: %d\n", GetLastError());