[project @ 1999-01-18 09:20:08 by sof]
[ghc-hetmet.git] / ghc / rts / MBlock.c
1 /* -----------------------------------------------------------------------------
2  * $Id: MBlock.c,v 1.5 1999/01/18 09:20:08 sof Exp $
3  *
4  * MegaBlock Allocator Interface.  This file contains all the dirty
5  * architecture-dependent hackery required to get a chunk of aligned
6  * memory from the operating system.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #define NON_POSIX_SOURCE
11
12 #include "Rts.h"
13 #include "RtsUtils.h"
14 #include "RtsFlags.h"
15 #include "MBlock.h"
16 #include "BlockAlloc.h"
17
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
21
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25
26 #ifdef HAVE_SYS_MMAN_H
27 #include <sys/mman.h>
28 #endif
29
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
33
34 #if cygwin32_TARGET_OS
35 #include <windows.h>
36 #endif
37
38 #if freebsd2_TARGET_OS || freebsd3_TARGET_OS
39 /* Executable is loaded from      0x0
40  * Shared libraries are loaded at 0x2000000
41  * Stack is at the top of the address space.  The kernel probably owns
42  * 0x8000000 onwards, so we'll pick 0x5000000.
43  */
44 #define ASK_FOR_MEM_AT 0x50000000
45
46 #elif linux_TARGET_OS
47 /* Any ideas?
48  */
49 #define ASK_FOR_MEM_AT 0x50000000
50
51 #elif solaris2_TARGET_OS
52 /* guess */
53 #define ASK_FOR_MEM_AT 0x50000000
54
55 #else
56 #error Dont know where to get memory from on this architecture
57 /* ToDo: memory locations on other architectures */
58 #endif
59
60 lnat mblocks_allocated = 0;
61
62 void *
63 getMBlock(void)
64 {
65   return getMBlocks(1);
66 }
67
68 #ifndef _WIN32
69
70 void *
71 getMBlocks(nat n)
72 {
73   static caddr_t next_request = (caddr_t)ASK_FOR_MEM_AT;
74   caddr_t ret;
75   lnat size = MBLOCK_SIZE * n;
76  
77 #ifdef solaris2_TARGET_OS
78   { 
79       int fd = open("/dev/zero",O_RDONLY);
80       ret = mmap(next_request, size, PROT_READ | PROT_WRITE, 
81                  MAP_FIXED | MAP_PRIVATE, fd, 0);
82       close(fd);
83   }
84 #else
85   ret = mmap(next_request, size, PROT_READ | PROT_WRITE, 
86              MAP_ANON | MAP_PRIVATE, -1, 0);
87 #endif
88   
89   if (ret == (void *)-1) {
90     if (errno == ENOMEM) {
91       barf("getMBlock: out of memory");
92     } else {
93       barf("GetMBlock: mmap failed");
94     }
95   }
96
97   if (((W_)ret & MBLOCK_MASK) != 0) {
98     barf("GetMBlock: misaligned block returned");
99   }
100
101   IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
102
103   next_request += size;
104
105   mblocks_allocated += n;
106   
107   return ret;
108 }
109
110 #else /* _WIN32 */
111
112 /*
113  On Win32 platforms we make use of the two-phased virtual memory API
114  to allocate mega blocks. We proceed as follows:
115
116  Reserve a large chunk of VM (128M at the time), but don't supply a 
117  base address that's aligned on a MB boundary. Instead we round up to the
118  nearest from the chunk of VM we're given back from the OS (at the
119  moment we just leave the 'slop' at the beginning of the reserved
120  chunk unused - ToDo: reuse it .)
121
122  Reserving memory doesn't allocate physical storage (not even in the
123  page file), this is done by committing pages (or mega-blocks in
124  our case).
125
126 */
127
128 void *
129 getMBlocks(nat n)
130 {
131   static char* base_non_committed = (char*)0;
132   static char* base_mblocks       = (char*)0;
133   static char* next_request       = (char*)0;
134   void* ret                       = (void*)0;
135
136   lnat size = MBLOCK_SIZE * n;
137
138   /* Reserve VM 128M at the time to try to minimise the slop cost. */
139 #define SIZE_RESERVED_POOL  ( 128 * 1024 * 1024 )
140
141   if ( (base_non_committed == 0) || 
142        (next_request + size > base_non_committed + SIZE_RESERVED_POOL) ) {
143     base_non_committed = VirtualAlloc ( NULL
144                                       , SIZE_RESERVED_POOL
145                                       , MEM_RESERVE
146                                       , PAGE_READWRITE
147                                       );
148     if ( base_non_committed == 0 ) {
149 # ifdef DEBUG
150          fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
151 # endif
152          ret=(void*)-1;
153     } else {
154     /* The returned pointer is not aligned on a mega-block boundary. Make it. */
155        base_mblocks = (char*)((unsigned)base_non_committed & (unsigned)0xfff00000) + 0x100000;
156 # if 0
157        fprintf(stderr, "Dropping %d bytes off of 128M chunk\n", 
158                        (unsigned)base_mblocks - (unsigned)base_non_committed);
159 # endif
160
161        if ( ((char*)base_mblocks + size) > ((char*)base_non_committed + SIZE_RESERVED_POOL) ) {
162 # ifdef DEBUG
163           fprintf(stderr, "oops, committed too small a region to start with.");
164 # endif
165           ret=(void*)-1;
166        } else {
167           next_request = base_mblocks;
168        }
169     }
170   }
171   /* Commit the mega block(s) to phys mem */
172   if ( ret != (void*)-1 ) {
173      ret = VirtualAlloc(next_request, size, MEM_COMMIT, PAGE_READWRITE);
174      if (ret == NULL) {
175 # ifdef DEBUG
176         fprintf(stderr, "getMBlocks: VirtualAlloc failed with: %d\n", GetLastError());
177 # endif
178         ret=(void*)-1;
179      }
180   }
181
182   if (((W_)ret & MBLOCK_MASK) != 0) {
183     barf("GetMBlock: misaligned block returned");
184   }
185
186   IF_DEBUG(gc,fprintf(stderr,"Allocated %d megablock(s) at %x\n",n,(nat)ret));
187
188   next_request = (char*)next_request + size;
189
190   mblocks_allocated += n;
191   
192   return ret;
193 }
194
195 /* Hand back the physical memory that is allocated to a mega-block. 
196    ToDo: chain the released mega block onto some list so that
197          getMBlocks() can get at it.
198
199    Currently unused.
200 */
201 #if 0
202 void
203 freeMBlock(void* p, nat n)
204 {
205   BOOL rc;
206
207   rc = VirtualFree(p, n * MBLOCK_SIZE , MEM_DECOMMIT );
208   
209   if (rc == FALSE) {
210 # ifdef DEBUG
211      fprintf(stderr, "freeMBlocks: VirtualFree failed with: %d\n", GetLastError());
212 # endif
213   }
214
215 }
216 #endif
217
218 #endif