comparison vmalloc.c @ 101:ca154ebe2b6c

Basic malloc without small chunks
author Merten Sach <msach@mailbox.tu-berlin.de>
date Tue, 02 Aug 2011 15:44:28 +0200
parents 21c95d402fe6
children def70e32cf2c
comparison
equal deleted inserted replaced
12:a0b38c64a0b6 13:07daf0c09527
9 9
10 #include <malloc.h> 10 #include <malloc.h>
11 #include <inttypes.h> 11 #include <inttypes.h>
12 #include <stdlib.h> 12 #include <stdlib.h>
13 #include <stdio.h> 13 #include <stdio.h>
14 #include <string.h>
15 #include <math.h>
14 16
15 #include "VMS.h" 17 #include "VMS.h"
16 #include "Histogram/Histogram.h" 18 #include "Histogram/Histogram.h"
17 19
18 /*Helper function 20 /*
19 *Insert a newly generated free chunk into the first spot on the free list. 21 * This calculates the container which fits the given size.
20 * The chunk is cast as a MallocProlog, so the various pointers in it are 22 */
21 * accessed with C's help -- and the size of the prolog is easily added to 23 inline
22 * the pointer when a chunk is returned to the app -- so C handles changes 24 uint32 getContainer(size_t size)
23 * in pointer sizes among machines. 25 {
24 * 26 return floor((log10(size)-LOG128)/LOG54);
25 *The list head is a normal MallocProlog struct -- identified by its 27 }
26 * prevChunkInFreeList being NULL -- the only one. 28
27 * 29 /*
28 *The end of the list is identified by next chunk being NULL, as usual. 30 * This calculates the size of a given container
29 */ 31 */
30 void inline 32 inline
31 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead ) 33 size_t getContainerSize(uint32 idx)
32 { 34 {
33 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList; 35 return pow(CHUNK_INCREASE_RATE,idx)*LOWER_BOUND;
34 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list 36 }
35 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk; 37
36 chunk->prevChunkInFreeList = listHead; 38 /*
37 listHead->nextChunkInFreeList = chunk; 39 * Removes the first chunk of a freeList
38 } 40 * The chunk is removed but not set as free. There is no check if
39 41 * the free list is empty, so make sure this is not the case.
40 42 */
41 /*This is sequential code, meant to only be called from the Master, not from 43 inline
44 MallocProlog *removeChunk(MallocProlog** container)
45 {
46 MallocProlog *removedChunk = *container;
47 *container = removedChunk->nextChunkInFreeList;
48
49 if(removedChunk->nextChunkInFreeList)
50 removedChunk->nextChunkInFreeList->prevChunkInFreeList =
51 (MallocProlog*)container;
52
53 return removedChunk;
54 }
55
56 /*
57 * Removes a chunk from a free list.
58 */
59 inline
60 MallocProlog *extractChunk(MallocProlog* chunk)
61 {
62
63 }
64
65 /*
66 * Merges two chunks.
67 * Chunk A has to be before chunk B in memory.
68 */
69 inline
70 MallocProlog *mergeChunks(MallocProlog* chunkA, MallocProlog* chunkB)
71 {
72
73 }
74 /*
75 * Inserts a chunk into a free list.
76 */
77 inline
78 void insertChunk(MallocProlog* chunk, MallocProlog** container)
79 {
80 chunk->nextChunkInFreeList = *container;
81 chunk->prevChunkInFreeList = (MallocProlog*)container;
82 if(*container)
83 (*container)->prevChunkInFreeList = chunk;
84 *container = chunk;
85 }
86
87 /*
88 * Divides the chunk that a new chunk of newSize is created.
89 * There is no size check, so make sure the size value is valid.
90 */
91 inline
92 MallocProlog *divideChunk(MallocProlog* chunk, size_t newSize)
93 {
94 MallocProlog* newChunk = (MallocProlog*)((uintptr_t)chunk->nextHigherInMem -
95 newSize - sizeof(MallocProlog));
96
97 newChunk->nextLowerInMem = chunk;
98 newChunk->nextHigherInMem = chunk->nextHigherInMem;
99
100 chunk->nextHigherInMem = newChunk;
101 chunk->nextHigherInMem->nextLowerInMem = newChunk;
102
103 return newChunk;
104 }
105
106 inline
107 size_t getChunkSize(MallocProlog* chunk)
108 {
109 return (uintptr_t)chunk->nextHigherInMem -
110 (uintptr_t)chunk - sizeof(MallocProlog);
111 }
112
113 /*
114 * This is sequential code, meant to only be called from the Master, not from
42 * any slave VPs. 115 * any slave VPs.
43 *Search down list, checking size by the nextHigherInMem pointer, to find
44 * first chunk bigger than size needed.
45 *Shave off the extra and make it into a new free-list element, hook it in
46 * then return the address of the found element plus size of prolog.
47 *
48 *Will find a
49 */ 116 */
50 void *VMS__malloc( size_t sizeRequested ) 117 void *VMS__malloc( size_t sizeRequested )
51 { MallocProlog *foundElem = NULL, *currElem, *newElem; 118 {
52 ssize_t amountExtra, sizeConsumed,sizeOfFound;
53 uint32 foundElemIsTopOfHeap;
54
55 //============================= MEASUREMENT STUFF ======================== 119 //============================= MEASUREMENT STUFF ========================
56 #ifdef MEAS__TIME_MALLOC 120 #ifdef MEAS__TIME_MALLOC
57 int32 startStamp, endStamp; 121 int32 startStamp, endStamp;
58 saveLowTimeStampCountInto( startStamp ); 122 saveLowTimeStampCountInto( startStamp );
59 #endif 123 #endif
60 //======================================================================== 124 //========================================================================
61 125
62 //step up the size to be aligned at 16-byte boundary, prob better ways 126 MallocArrays* freeList = _VMSMasterEnv->freeLists;
63 sizeRequested = (sizeRequested + 16) & ~15; 127
64 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; 128 //Return a small chunk if the requested size is smaller than 128B
65 129 //TODO: for now set size to 129B
66 while( currElem != NULL ) 130 if(sizeRequested < 128)
67 { //check if size of currElem is big enough 131 sizeRequested = 129;
68 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); 132
69 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); 133 //Calculate the expected container. Start one higher to have a Chunk that's
70 if( amountExtra > 0 ) 134 //always big enough.
71 { //found it, get out of loop 135 uint32 targetContainerIdx = getContainer(sizeRequested);
72 foundElem = currElem; 136 uint32 containerIdx = targetContainerIdx + 1;
73 currElem = NULL; 137
138 MallocProlog* foundChunk;
139 if(freeList->bigChunks[containerIdx] == NULL)
140 {
141 while(freeList->bigChunks[containerIdx] == NULL)
142 {
143 containerIdx++;
144 if(containerIdx > freeList->containerCount)
145 {
146 printf("VMS malloc failed: low memory");
147 exit(1);
148 }
74 } 149 }
75 else 150
76 currElem = currElem->nextChunkInFreeList; 151 foundChunk = removeChunk(&freeList->bigChunks[containerIdx]);
77 } 152 //Found bigger Element, so we have to divide until it fits the
78 153 //requested size
79 if( foundElem == NULL ) 154 containerIdx--;
80 { ERROR("\nmalloc failed\n") 155 size_t containerSize = getContainerSize(containerIdx);
81 return (void *)NULL; //indicates malloc failed 156 size_t chunkSize = getChunkSize(foundChunk);
82 } 157
83 //Using a kludge to identify the element that is the top chunk in the 158 while(containerIdx > targetContainerIdx)
84 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and 159 {
85 // save addr of start of heap in head's nextLowerInMem 160 if(chunkSize > containerSize + sizeRequested + sizeof(MallocProlog))
86 //Will handle top of Heap specially 161 {
87 foundElemIsTopOfHeap = foundElem->nextHigherInMem == 162 MallocProlog *newChunk = divideChunk(foundChunk,containerSize);
88 _VMSMasterEnv->freeListHead->nextHigherInMem; 163 insertChunk(newChunk,&freeList->bigChunks[containerIdx]);
89 164 chunkSize = getChunkSize(foundChunk);
90 //before shave off and try to insert new elem, remove found elem 165 }
91 //note, foundElem will never be the head, so always has valid prevChunk 166 containerIdx--;
92 foundElem->prevChunkInFreeList->nextChunkInFreeList = 167 containerSize /= CHUNK_INCREASE_RATE;
93 foundElem->nextChunkInFreeList; 168 }
94 if( foundElem->nextChunkInFreeList != NULL ) 169 }
95 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
96 foundElem->prevChunkInFreeList;
97 }
98 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
99
100 //if enough, turn extra into new elem & insert it
101 if( amountExtra > 64 )
102 { //make new elem by adding to addr of curr elem then casting
103 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
104 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed );
105 newElem->nextLowerInMem = foundElem; //This is evil (but why?)
106 newElem->nextHigherInMem = foundElem->nextHigherInMem; //This is evil (but why?)
107 foundElem->nextHigherInMem = newElem;
108 if( ! foundElemIsTopOfHeap )
109 { //there is no next higher for top of heap, so can't write to it
110 newElem->nextHigherInMem->nextLowerInMem = newElem;
111 }
112 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
113 }
114 else 170 else
115 { 171 {
116 sizeConsumed = sizeOfFound; 172 foundChunk = removeChunk(&freeList->bigChunks[containerIdx]);
117 } 173 }
118 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; 174
119 175 //Mark as allocated
176 foundChunk->prevChunkInFreeList = NULL;
177
120 //============================= MEASUREMENT STUFF ======================== 178 //============================= MEASUREMENT STUFF ========================
121 #ifdef MEAS__TIME_MALLOC 179 #ifdef MEAS__TIME_MALLOC
122 saveLowTimeStampCountInto( endStamp ); 180 saveLowTimeStampCountInto( endStamp );
123 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); 181 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
124 #endif 182 #endif
125 //======================================================================== 183 //========================================================================
126 184
127 //skip over the prolog by adding its size to the pointer return 185 //skip over the prolog by adding its size to the pointer return
128 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); 186 return (void*)((uintptr_t)foundChunk + sizeof(MallocProlog));
129 } 187 }
130 188
131 /*This is sequential code, meant to only be called from the Master, not from 189 /*
190 * This is sequential code, meant to only be called from the Master, not from
132 * any slave VPs. 191 * any slave VPs.
133 *Search down list, checking size by the nextHigherInMem pointer, to find
134 * first chunk bigger than size needed.
135 *Shave off the extra and make it into a new free-list element, hook it in
136 * then return the address of the found element plus size of prolog.
137 *
138 * The difference to the regular malloc is, that all the allocated chunks are
139 * aligned and padded to the size of a CACHE_LINE. Thus creating a new chunk
140 * before the aligned chunk.
141 */
142 void *VMS__malloc_aligned( size_t sizeRequested )
143 { MallocProlog *foundElem = NULL, *currElem, *newElem;
144 ssize_t amountExtra, sizeConsumed,sizeOfFound,prevAmount;
145 uint32 foundElemIsTopOfHeap;
146
147 //============================= MEASUREMENT STUFF ========================
148 #ifdef MEAS__TIME_MALLOC
149 uint32 startStamp, endStamp;
150 saveLowTimeStampCountInto( startStamp );
151 #endif
152 //========================================================================
153
154 //step up the size to be multiple of the cache line size
155 sizeRequested = (sizeRequested + CACHE_LINE) & ~(CACHE_LINE-1);
156 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
157
158 while( currElem != NULL )
159 { //check if size of currElem is big enough
160 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
161 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
162 if( amountExtra > 0 )
163 {
164 //look if the found element is already aligned
165 if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE-1)) == 0){
166 //found it, get out of loop
167 foundElem = currElem;
168 break;
169 }else{
170 //find first aligned address and check if it's still big enough
171 //check also if the space before the aligned address is big enough
172 //for a new element
173 void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE) & ~((uintptr_t)(CACHE_LINE-1)));
174 prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem;
175 sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog);
176 amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog);
177 if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){
178 //found suitable element
179 //create new previous element and exit loop
180 MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1;
181
182 //insert new element into free list
183 if(currElem->nextChunkInFreeList != NULL)
184 currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem;
185 newAlignedElem->prevChunkInFreeList = currElem;
186 newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList;
187 currElem->nextChunkInFreeList = newAlignedElem;
188
189 //set higherInMem and lowerInMem
190 newAlignedElem->nextHigherInMem = currElem->nextHigherInMem;
191 foundElemIsTopOfHeap = currElem->nextHigherInMem ==
192 _VMSMasterEnv->freeListHead->nextHigherInMem;
193 if(!foundElemIsTopOfHeap)
194 currElem->nextHigherInMem->nextLowerInMem = newAlignedElem;
195 currElem->nextHigherInMem = newAlignedElem;
196 newAlignedElem->nextLowerInMem = currElem;
197
198 //Found new element leaving loop
199 foundElem = newAlignedElem;
200 break;
201 }
202 }
203
204 }
205 currElem = currElem->nextChunkInFreeList;
206 }
207
208 if( foundElem == NULL )
209 { ERROR("\nmalloc failed\n")
210 return (void *)NULL; //indicates malloc failed
211 }
212 //Using a kludge to identify the element that is the top chunk in the
213 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
214 // save addr of start of heap in head's nextLowerInMem
215 //Will handle top of Heap specially
216 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
217 _VMSMasterEnv->freeListHead->nextHigherInMem;
218
219 //before shave off and try to insert new elem, remove found elem
220 //note, foundElem will never be the head, so always has valid prevChunk
221 foundElem->prevChunkInFreeList->nextChunkInFreeList =
222 foundElem->nextChunkInFreeList;
223 if( foundElem->nextChunkInFreeList != NULL )
224 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
225 foundElem->prevChunkInFreeList;
226 }
227 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
228
229 //if enough, turn extra into new elem & insert it
230 if( amountExtra > 64 )
231 { //make new elem by adding to addr of curr elem then casting
232 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
233 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed );
234 newElem->nextHigherInMem = foundElem->nextHigherInMem;
235 newElem->nextLowerInMem = foundElem;
236 foundElem->nextHigherInMem = newElem;
237
238 if( ! foundElemIsTopOfHeap )
239 { //there is no next higher for top of heap, so can't write to it
240 newElem->nextHigherInMem->nextLowerInMem = newElem;
241 }
242 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
243 }
244 else
245 {
246 sizeConsumed = sizeOfFound;
247 }
248 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
249
250 //============================= MEASUREMENT STUFF ========================
251 #ifdef MEAS__TIME_MALLOC
252 saveLowTimeStampCountInto( endStamp );
253 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
254 #endif
255 //========================================================================
256
257 //skip over the prolog by adding its size to the pointer return
258 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog));
259 }
260
261
262 /*This is sequential code -- only to be called from the Master
263 * When free, subtract the size of prolog from pointer, then cast it to a
264 * MallocProlog. Then check the nextLower and nextHigher chunks to see if
265 * one or both are also free, and coalesce if so, and if neither free, then
266 * add this one to free-list.
267 */ 192 */
268 void 193 void
269 VMS__free( void *ptrToFree ) 194 VMS__free( void *ptrToFree )
270 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; 195 {
271 size_t sizeOfElem;
272 uint32 lowerExistsAndIsFree, higherExistsAndIsFree;
273 196
274 //============================= MEASUREMENT STUFF ======================== 197 //============================= MEASUREMENT STUFF ========================
275 #ifdef MEAS__TIME_MALLOC 198 #ifdef MEAS__TIME_MALLOC
276 int32 startStamp, endStamp; 199 int32 startStamp, endStamp;
277 saveLowTimeStampCountInto( startStamp ); 200 saveLowTimeStampCountInto( startStamp );
278 #endif 201 #endif
279 //======================================================================== 202 //========================================================================
280 203
281 if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem || 204 MallocArrays* freeList = _VMSMasterEnv->freeLists;
282 ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem ) 205 MallocProlog *chunkToFree = (MallocProlog*)ptrToFree - 1;
283 { //outside the range of data owned by VMS's malloc, so do nothing 206
284 return; 207 //Check for free neighbors
285 } 208 if(chunkToFree->nextLowerInMem)
286 //subtract size of prolog to get pointer to prolog, then cast 209 {
287 elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog)); 210 if(chunkToFree->nextLowerInMem->prevChunkInFreeList != NULL)
288 sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree); 211 {//Chunk is not allocated
289 212 mergeChunks()
290 if( elemToFree->prevChunkInFreeList != NULL )
291 { printf( "error: freeing same element twice!" ); exit(1);
292 }
293
294 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
295
296 nextLowerElem = elemToFree->nextLowerInMem;
297 nextHigherElem = elemToFree->nextHigherInMem;
298
299 if( nextHigherElem == NULL )
300 higherExistsAndIsFree = FALSE;
301 else //okay exists, now check if in the free-list by checking back ptr
302 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
303
304 if( nextLowerElem == NULL )
305 lowerExistsAndIsFree = FALSE;
306 else //okay, it exists, now check if it's free
307 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
308
309
310 //now, know what exists and what's free
311 if( lowerExistsAndIsFree )
312 { if( higherExistsAndIsFree )
313 { //both exist and are free, so coalesce all three
314 //First, remove higher from free-list
315 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
316 nextHigherElem->nextChunkInFreeList;
317 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
318 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
319 nextHigherElem->prevChunkInFreeList;
320 //Now, fix-up sequence-in-mem list -- by side-effect, this also
321 // changes size of the lower elem, which is still in free-list
322 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
323 if( nextHigherElem->nextHigherInMem !=
324 _VMSMasterEnv->freeListHead->nextHigherInMem )
325 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
326 //notice didn't do anything to elemToFree -- it simply is no
327 // longer reachable from any of the lists. Wonder if could be a
328 // security leak because left valid addresses in it,
329 // but don't care for now.
330 } 213 }
331 else 214 }
332 { //lower is the only of the two that exists and is free,
333 //In this case, no adjustment to free-list, just change mem-list.
334 // By side-effect, changes size of the lower elem
335 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
336 if( elemToFree->nextHigherInMem !=
337 _VMSMasterEnv->freeListHead->nextHigherInMem )
338 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
339 }
340 }
341 else
342 { //lower either doesn't exist or isn't free, so check higher
343 if( higherExistsAndIsFree )
344 { //higher exists and is the only of the two free
345 //First, in free-list, replace higher elem with the one to free
346 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
347 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
348 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
349 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
350 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
351 //Now chg mem-list. By side-effect, changes size of elemToFree
352 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
353 if( elemToFree->nextHigherInMem !=
354 _VMSMasterEnv->freeListHead->nextHigherInMem )
355 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
356 }
357 else
358 { //neither lower nor higher is availabe to coalesce so add to list
359 // this makes prev chunk ptr non-null, which indicates it's free
360 elemToFree->nextChunkInFreeList =
361 _VMSMasterEnv->freeListHead->nextChunkInFreeList;
362 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
363 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
364 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
365 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
366 }
367 }
368 //============================= MEASUREMENT STUFF ======================== 215 //============================= MEASUREMENT STUFF ========================
369 #ifdef MEAS__TIME_MALLOC 216 #ifdef MEAS__TIME_MALLOC
370 saveLowTimeStampCountInto( endStamp ); 217 saveLowTimeStampCountInto( endStamp );
371 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist ); 218 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist );
372 #endif 219 #endif
438 } 285 }
439 286
440 287
441 /*Designed to be called from the main thread outside of VMS, during init 288 /*Designed to be called from the main thread outside of VMS, during init
442 */ 289 */
443 MallocProlog * 290 MallocArrays *
444 VMS_ext__create_free_list() 291 VMS_ext__create_free_list()
445 { MallocProlog *freeListHead, *firstChunk; 292 {
446 293 //Initialize containers for small chunks and fill with zeros
447 //Note, this is running in the main thread -- all increases in malloc 294 _VMSMasterEnv->freeLists = (MallocArrays*)malloc( sizeof(MallocArrays) );
448 // mem and all frees of it must be done in this thread, with the 295 MallocArrays *freeLists = _VMSMasterEnv->freeLists;
449 // thread's original stack available 296
450 freeListHead = malloc( sizeof(MallocProlog) ); 297 freeLists->smallChunks =
451 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); 298 (MallocProlog**)malloc(SMALL_CHUNK_COUNT*sizeof(MallocProlog*));
299 memset((void*)freeLists->smallChunks,
300 0,SMALL_CHUNK_COUNT*sizeof(MallocProlog*));
301
302 //Calculate number of containers for big chunks
303 uint32 container = getContainer(MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE)+1;
304
305 freeLists->bigChunks = (MallocProlog**)malloc(container*sizeof(MallocProlog*));
306 memset((void*)freeLists->bigChunks,0,container*sizeof(MallocProlog*));
307 freeLists->containerCount = container;
308
309 //Create first element in lastContainer
310 MallocProlog *firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
452 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);} 311 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
453 312
454 //Touch memory to avoid page faults 313 firstChunk->nextLowerInMem = NULL;
455 void *ptr,*endPtr; 314 firstChunk->nextHigherInMem = (MallocProlog*)((uintptr_t)firstChunk +
456 endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE; 315 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE - sizeof(MallocProlog*));
457 for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE) 316 firstChunk->nextChunkInFreeList = NULL;
458 { 317 //previous element in the queue is the container
459 *(char*)ptr = 0; 318 firstChunk->prevChunkInFreeList = freeLists->bigChunks[container-1];
460 } 319
461 320 freeLists->bigChunks[container-1] = firstChunk;
462 freeListHead->prevChunkInFreeList = NULL; 321
463 //Use this addr to free the heap when cleanup 322 //Create dummy chunk to mark the top of stack this is of course
464 freeListHead->nextLowerInMem = firstChunk; 323 //never freed
465 //to identify top-of-heap elem, compare this addr to elem's next higher 324 MallocProlog *dummyChunk = firstChunk->nextHigherInMem;
466 freeListHead->nextHigherInMem = (void*)( (uintptr_t)firstChunk + 325 dummyChunk->nextHigherInMem = dummyChunk+1;
467 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE); 326 dummyChunk->nextLowerInMem = NULL;
468 freeListHead->nextChunkInFreeList = firstChunk; 327 dummyChunk->nextChunkInFreeList = NULL;
469 328 dummyChunk->prevChunkInFreeList = NULL;
470 firstChunk->nextChunkInFreeList = NULL; 329
471 firstChunk->prevChunkInFreeList = freeListHead; 330 return freeLists;
472 //next Higher has to be set to top of chunk, so can calc size in malloc
473 firstChunk->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
474 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
475 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap
476
477 _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
478
479 return freeListHead;
480 } 331 }
481 332
482 333
483 /*Designed to be called from the main thread outside of VMS, during cleanup 334 /*Designed to be called from the main thread outside of VMS, during cleanup
484 */ 335 */