1 /* -----------------------------------------------------------------------------
3 * (c) The University of Glasgow 2006-2007
5 * OS-specific memory management
7 * ---------------------------------------------------------------------------*/
12 #include "RtsMessages.h"
18 /* alloc_rec keeps the info we need to have matching VirtualAlloc and
21 typedef struct alloc_rec_ {
22 char* base; /* non-aligned base address, directly from VirtualAlloc */
23 int size; /* Size in bytes */
24 struct alloc_rec_* next;
27 typedef struct block_rec_ {
28 char* base; /* base address, non-MBLOCK-aligned */
29 int size; /* size in bytes */
30 struct block_rec_* next;
33 static alloc_rec* allocs = NULL;
34 static block_rec* free_blocks = NULL;
47 rec = (alloc_rec*)stgMallocBytes(sizeof(alloc_rec),"getMBlocks: allocNew");
48 rec->size = (n+1)*MBLOCK_SIZE;
50 VirtualAlloc(NULL, rec->size, MEM_RESERVE, PAGE_READWRITE);
54 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
56 errorBelch("out of memory");
59 "getMBlocks: VirtualAlloc MEM_RESERVE %d blocks failed", n);
63 temp.base=0; temp.size=0; temp.next=allocs;
67 for(; it->next!=0 && it->next->base<rec->base; it=it->next) ;
78 insertFree(char* alloc_base, int alloc_size) {
83 temp.base=0; temp.size=0; temp.next=free_blocks;
86 for( ; it!=0 && it->base<alloc_base; prev=it, it=it->next) {}
88 if(it!=0 && alloc_base+alloc_size == it->base) {
89 if(prev->base + prev->size == alloc_base) { /* Merge it, alloc, prev */
90 prev->size += alloc_size + it->size;
91 prev->next = it->next;
93 } else { /* Merge it, alloc */
94 it->base = alloc_base;
95 it->size += alloc_size;
97 } else if(prev->base + prev->size == alloc_base) { /* Merge alloc, prev */
98 prev->size += alloc_size;
99 } else { /* Merge none */
101 rec = (block_rec*)stgMallocBytes(sizeof(block_rec),"getMBlocks: insertFree");
102 rec->base=alloc_base;
103 rec->size=alloc_size;
107 free_blocks=temp.next;
112 findFreeBlocks(nat n) {
120 required_size = n*MBLOCK_SIZE;
121 temp.next=free_blocks; temp.base=0; temp.size=0;
123 /* TODO: Don't just take first block, find smallest sufficient block */
124 for( ; it!=0 && it->size<required_size; prev=it, it=it->next ) {}
126 if( (((unsigned long)it->base) & MBLOCK_MASK) == 0) { /* MBlock aligned */
127 ret = (void*)it->base;
128 if(it->size==required_size) {
132 it->base += required_size;
133 it->size -=required_size;
139 need_base = (char*)(((unsigned long)it->base) & ((unsigned long)~MBLOCK_MASK)) + MBLOCK_SIZE;
140 next = (block_rec*)stgMallocBytes(
142 , "getMBlocks: findFreeBlocks: splitting");
143 new_size = need_base - it->base;
144 next->base = need_base +required_size;
145 next->size = it->size - (new_size+required_size);
147 next->next = it->next;
149 ret=(void*)need_base;
152 free_blocks=temp.next;
156 /* VirtualAlloc MEM_COMMIT can't cross boundaries of VirtualAlloc MEM_RESERVE,
157 so we might need to do many VirtualAlloc MEM_COMMITs. We simply walk the
158 (ordered) allocated blocks. */
160 commitBlocks(char* base, int size) {
163 for( ; it!=0 && (it->base+it->size)<=base; it=it->next ) {}
164 for( ; it!=0 && size>0; it=it->next ) {
167 size_delta = it->size - (base-it->base);
168 if(size_delta>size) size_delta=size;
169 temp = VirtualAlloc(base, size_delta, MEM_COMMIT, PAGE_READWRITE);
171 sysErrorBelch("getMBlocks: VirtualAlloc MEM_COMMIT failed");
172 stg_exit(EXIT_FAILURE);
180 osGetMBlocks(nat n) {
182 ret = findFreeBlocks(n);
186 /* We already belch in allocNew if it fails */
188 stg_exit(EXIT_FAILURE);
190 insertFree(alloc->base, alloc->size);
191 ret = findFreeBlocks(n);
196 /* (In)sanity tests */
197 if (((W_)ret & MBLOCK_MASK) != 0) {
198 barf("getMBlocks: misaligned block returned");
201 commitBlocks(ret, MBLOCK_SIZE*n);
208 osFreeAllMBlocks(void)
227 if(!VirtualFree((void*)it->base, 0, MEM_RELEASE)) {
228 sysErrorBelch("freeAllMBlocks: VirtualFree MEM_RELEASE failed");
229 stg_exit(EXIT_FAILURE);
238 lnat getPageSize (void)
240 static lnat pagesize = 0;
244 SYSTEM_INFO sSysInfo;
245 GetSystemInfo(&sSysInfo);
246 pagesize = sSysInfo.dwPageSize;
251 void setExecutable (void *p, lnat len, rtsBool exec)
253 DWORD dwOldProtect = 0;
254 if (VirtualProtect (p, len,
255 exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
258 sysErrorBelch("makeExecutable: failed to protect 0x%p; old protection: %lu\n",
259 p, (unsigned long)dwOldProtect);
260 stg_exit(EXIT_FAILURE);