1 /* -----------------------------------------------------------------------------
2 * $Id: MBlock.c,v 1.9 1999/02/05 16:02:44 simonm 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 #ifdef HAVE_SYS_MMAN_H
40 #if freebsd2_TARGET_OS || freebsd3_TARGET_OS
41 /* Executable is loaded from 0x0
42 * Shared libraries are loaded at 0x2000000
43 * Stack is at the top of the address space. The kernel probably owns
44 * 0x8000000 onwards, so we'll pick 0x5000000.
46 #define ASK_FOR_MEM_AT 0x50000000
51 #define ASK_FOR_MEM_AT 0x50000000
53 #elif solaris2_TARGET_OS
55 #define ASK_FOR_MEM_AT 0x50000000
59 #define ASK_FOR_MEM_AT 0x50000000
62 /* doesn't matter, we use a reserve/commit algorithm */
65 #error Dont know where to get memory from on this architecture
66 /* ToDo: memory locations on other architectures */
69 lnat mblocks_allocated = 0;
81 static caddr_t next_request = (caddr_t)ASK_FOR_MEM_AT;
83 lnat size = MBLOCK_SIZE * n;
85 #ifdef solaris2_TARGET_OS
87 int fd = open("/dev/zero",O_RDONLY);
88 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
89 MAP_FIXED | MAP_PRIVATE, fd, 0);
93 ret = mmap(next_request, size, PROT_READ | PROT_WRITE,
94 MAP_ANON | MAP_PRIVATE, -1, 0);
97 if (ret == (void *)-1) {
98 if (errno == ENOMEM) {
99 barf("getMBlock: out of memory");
101 barf("GetMBlock: mmap failed");
105 if (((W_)ret & MBLOCK_MASK) != 0) {
106 barf("GetMBlock: misaligned block returned");
109 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
111 next_request += size;
113 mblocks_allocated += n;
121 On Win32 platforms we make use of the two-phased virtual memory API
122 to allocate mega blocks. We proceed as follows:
124 Reserve a large chunk of VM (128M at the time), but don't supply a
125 base address that's aligned on a MB boundary. Instead we round up to the
126 nearest from the chunk of VM we're given back from the OS (at the
127 moment we just leave the 'slop' at the beginning of the reserved
128 chunk unused - ToDo: reuse it .)
130 Reserving memory doesn't allocate physical storage (not even in the
131 page file), this is done by committing pages (or mega-blocks in
139 static char* base_non_committed = (char*)0;
140 static char* base_mblocks = (char*)0;
141 static char* next_request = (char*)0;
142 void* ret = (void*)0;
144 lnat size = MBLOCK_SIZE * n;
146 /* Reserve VM 128M at the time to try to minimise the slop cost. */
147 #define SIZE_RESERVED_POOL ( 128 * 1024 * 1024 )
149 if ( (base_non_committed == 0) ||
150 (next_request + size > base_non_committed + SIZE_RESERVED_POOL) ) {
151 base_non_committed = VirtualAlloc ( NULL
156 if ( base_non_committed == 0 ) {
158 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
162 /* The returned pointer is not aligned on a mega-block boundary. Make it. */
163 base_mblocks = (char*)((unsigned)base_non_committed & (unsigned)0xfff00000) + 0x100000;
165 fprintf(stderr, "Dropping %d bytes off of 128M chunk\n",
166 (unsigned)base_mblocks - (unsigned)base_non_committed);
169 if ( ((char*)base_mblocks + size) > ((char*)base_non_committed + SIZE_RESERVED_POOL) ) {
171 fprintf(stderr, "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);
184 fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
190 if (((W_)ret & MBLOCK_MASK) != 0) {
191 barf("GetMBlock: misaligned block returned");
194 IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
196 next_request = (char*)next_request + size;
198 mblocks_allocated += n;
203 /* Hand back the physical memory that is allocated to a mega-block.
204 ToDo: chain the released mega block onto some list so that
205 getMBlocks() can get at it.
211 freeMBlock(void* p, nat n)
215 rc = VirtualFree(p, n * MBLOCK_SIZE , MEM_DECOMMIT );
219 fprintf(stderr, "freeMBlocks: VirtualFree failed with: %d\n", GetLastError());