| rev |
line source |
|
seanhalle@208
|
1 /*
|
|
seanhalle@208
|
2 * Copyright 2009 OpenSourceCodeStewardshipFoundation.org
|
|
seanhalle@208
|
3 * Licensed under GNU General Public License version 2
|
|
seanhalle@208
|
4 *
|
|
seanhalle@208
|
5 * Author: seanhalle@yahoo.com
|
|
seanhalle@208
|
6 *
|
|
seanhalle@208
|
7 * Created on November 14, 2009, 9:07 PM
|
|
seanhalle@208
|
8 */
|
|
seanhalle@208
|
9
|
|
seanhalle@208
|
10 #include <malloc.h>
|
|
seanhalle@208
|
11 #include <inttypes.h>
|
|
seanhalle@208
|
12 #include <stdlib.h>
|
|
seanhalle@208
|
13 #include <stdio.h>
|
|
seanhalle@208
|
14
|
|
seanhalle@208
|
15 #include "VMS.h"
|
|
seanhalle@208
|
16 #include "C_Libraries/Histogram/Histogram.h"
|
|
seanhalle@208
|
17
|
|
seanhalle@208
|
18 /*Helper function
|
|
seanhalle@208
|
19 *Insert a newly generated free chunk into the first spot on the free list.
|
|
seanhalle@208
|
20 * The chunk is cast as a MallocProlog, so the various pointers in it are
|
|
seanhalle@208
|
21 * accessed with C's help -- and the size of the prolog is easily added to
|
|
seanhalle@208
|
22 * the pointer when a chunk is returned to the app -- so C handles changes
|
|
seanhalle@208
|
23 * in pointer sizes among machines.
|
|
seanhalle@208
|
24 *
|
|
seanhalle@208
|
25 *The list head is a normal MallocProlog struct -- identified by its
|
|
seanhalle@208
|
26 * prevChunkInFreeList being NULL -- the only one.
|
|
seanhalle@208
|
27 *
|
|
seanhalle@208
|
28 *The end of the list is identified by next chunk being NULL, as usual.
|
|
seanhalle@208
|
29 */
|
|
seanhalle@208
|
30 void inline
|
|
seanhalle@208
|
31 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
|
|
seanhalle@208
|
32 {
|
|
seanhalle@208
|
33 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList;
|
|
seanhalle@208
|
34 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
|
|
seanhalle@208
|
35 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
|
|
seanhalle@208
|
36 chunk->prevChunkInFreeList = listHead;
|
|
seanhalle@208
|
37 listHead->nextChunkInFreeList = chunk;
|
|
seanhalle@208
|
38 }
|
|
seanhalle@208
|
39
|
|
seanhalle@208
|
40
|
|
seanhalle@208
|
41 /*This is sequential code, meant to only be called from the Master, not from
|
|
seanhalle@208
|
42 * any slave VPs.
|
|
seanhalle@208
|
43 *Search down list, checking size by the nextHigherInMem pointer, to find
|
|
seanhalle@208
|
44 * first chunk bigger than size needed.
|
|
seanhalle@208
|
45 *Shave off the extra and make it into a new free-list element, hook it in
|
|
seanhalle@208
|
46 * then return the address of the found element plus size of prolog.
|
|
seanhalle@208
|
47 *
|
|
seanhalle@208
|
48 */
|
|
seanhalle@208
|
49 void *VMS_int__malloc( size_t sizeRequested )
|
|
seanhalle@208
|
50 { MallocProlog *foundElem = NULL, *currElem, *newElem;
|
|
seanhalle@208
|
51 ssize_t amountExtra, sizeConsumed,sizeOfFound;
|
|
seanhalle@208
|
52 uint32 foundElemIsTopOfHeap;
|
|
seanhalle@208
|
53
|
|
seanhalle@208
|
54 //============================= MEASUREMENT STUFF ========================
|
|
seanhalle@208
|
55 #ifdef MEAS__TIME_MALLOC
|
|
seanhalle@208
|
56 int32 startStamp, endStamp;
|
|
seanhalle@208
|
57 saveLowTimeStampCountInto( startStamp );
|
|
seanhalle@208
|
58 #endif
|
|
seanhalle@208
|
59 //========================================================================
|
|
seanhalle@208
|
60
|
|
seanhalle@208
|
61 //step up the size to be aligned at 16-byte boundary, prob better ways
|
|
seanhalle@208
|
62 sizeRequested = (sizeRequested + 16) & ~15;
|
|
seanhalle@208
|
63 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
|
|
seanhalle@208
|
64
|
|
seanhalle@208
|
65 while( currElem != NULL )
|
|
seanhalle@208
|
66 { //check if size of currElem is big enough
|
|
seanhalle@208
|
67 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
|
|
seanhalle@208
|
68 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
|
|
seanhalle@208
|
69 if( amountExtra > 0 )
|
|
seanhalle@208
|
70 { //found it, get out of loop
|
|
seanhalle@208
|
71 foundElem = currElem;
|
|
seanhalle@208
|
72 currElem = NULL;
|
|
seanhalle@208
|
73 }
|
|
seanhalle@208
|
74 else
|
|
seanhalle@208
|
75 currElem = currElem->nextChunkInFreeList;
|
|
seanhalle@208
|
76 }
|
|
seanhalle@208
|
77
|
|
seanhalle@208
|
78 if( foundElem == NULL )
|
|
seanhalle@208
|
79 { ERROR("\nmalloc failed\n")
|
|
seanhalle@208
|
80 return (void *)NULL; //indicates malloc failed
|
|
seanhalle@208
|
81 }
|
|
seanhalle@208
|
82 //Using a kludge to identify the element that is the top chunk in the
|
|
seanhalle@208
|
83 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
|
|
seanhalle@208
|
84 // save addr of start of heap in head's nextLowerInMem
|
|
seanhalle@208
|
85 //Will handle top of Heap specially
|
|
seanhalle@208
|
86 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
|
|
seanhalle@208
|
87 _VMSMasterEnv->freeListHead->nextHigherInMem;
|
|
seanhalle@208
|
88
|
|
seanhalle@208
|
89 //before shave off and try to insert new elem, remove found elem
|
|
seanhalle@208
|
90 //note, foundElem will never be the head, so always has valid prevChunk
|
|
seanhalle@208
|
91 foundElem->prevChunkInFreeList->nextChunkInFreeList =
|
|
seanhalle@208
|
92 foundElem->nextChunkInFreeList;
|
|
seanhalle@208
|
93 if( foundElem->nextChunkInFreeList != NULL )
|
|
seanhalle@208
|
94 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
|
|
seanhalle@208
|
95 foundElem->prevChunkInFreeList;
|
|
seanhalle@208
|
96 }
|
|
seanhalle@208
|
97 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
|
|
seanhalle@208
|
98
|
|
seanhalle@208
|
99 //if enough, turn extra into new elem & insert it
|
|
seanhalle@208
|
100 if( amountExtra > 64 )
|
|
seanhalle@208
|
101 { //make new elem by adding to addr of curr elem then casting
|
|
seanhalle@208
|
102 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
|
|
seanhalle@208
|
103 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed );
|
|
seanhalle@208
|
104 newElem->nextLowerInMem = foundElem; //This is evil (but why?)
|
|
seanhalle@208
|
105 newElem->nextHigherInMem = foundElem->nextHigherInMem; //This is evil (but why?)
|
|
seanhalle@208
|
106 foundElem->nextHigherInMem = newElem;
|
|
seanhalle@208
|
107 if( ! foundElemIsTopOfHeap )
|
|
seanhalle@208
|
108 { //there is no next higher for top of heap, so can't write to it
|
|
seanhalle@208
|
109 newElem->nextHigherInMem->nextLowerInMem = newElem;
|
|
seanhalle@208
|
110 }
|
|
seanhalle@208
|
111 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
|
|
seanhalle@208
|
112 }
|
|
seanhalle@208
|
113 else
|
|
seanhalle@208
|
114 {
|
|
seanhalle@208
|
115 sizeConsumed = sizeOfFound;
|
|
seanhalle@208
|
116 }
|
|
seanhalle@208
|
117 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
|
|
seanhalle@208
|
118
|
|
seanhalle@208
|
119 //============================= MEASUREMENT STUFF ========================
|
|
seanhalle@208
|
120 #ifdef MEAS__TIME_MALLOC
|
|
seanhalle@208
|
121 saveLowTimeStampCountInto( endStamp );
|
|
seanhalle@208
|
122 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
|
|
seanhalle@208
|
123 #endif
|
|
seanhalle@208
|
124 //========================================================================
|
|
seanhalle@208
|
125
|
|
seanhalle@208
|
126 //skip over the prolog by adding its size to the pointer return
|
|
seanhalle@208
|
127 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog));
|
|
seanhalle@208
|
128 }
|
|
seanhalle@208
|
129
|
|
seanhalle@208
|
130 /*This is sequential code, meant to only be called from the Master, not from
|
|
seanhalle@208
|
131 * any slave VPs.
|
|
seanhalle@208
|
132 *Search down list, checking size by the nextHigherInMem pointer, to find
|
|
seanhalle@208
|
133 * first chunk bigger than size needed.
|
|
seanhalle@208
|
134 *Shave off the extra and make it into a new free-list element, hook it in
|
|
seanhalle@208
|
135 * then return the address of the found element plus size of prolog.
|
|
seanhalle@208
|
136 *
|
|
seanhalle@208
|
137 * The difference to the regular malloc is, that all the allocated chunks are
|
|
seanhalle@208
|
138 * aligned and padded to the size of a CACHE_LINE_SZ. Thus creating a new chunk
|
|
seanhalle@208
|
139 * before the aligned chunk.
|
|
seanhalle@208
|
140 */
|
|
seanhalle@208
|
141 void *VMS_int__malloc_aligned( size_t sizeRequested )
|
|
seanhalle@208
|
142 { MallocProlog *foundElem = NULL, *currElem, *newElem;
|
|
seanhalle@208
|
143 ssize_t amountExtra, sizeConsumed,sizeOfFound,prevAmount;
|
|
seanhalle@208
|
144 uint32 foundElemIsTopOfHeap;
|
|
seanhalle@208
|
145
|
|
seanhalle@208
|
146 //============================= MEASUREMENT STUFF ========================
|
|
seanhalle@208
|
147 #ifdef MEAS__TIME_MALLOC
|
|
seanhalle@208
|
148 uint32 startStamp, endStamp;
|
|
seanhalle@208
|
149 saveLowTimeStampCountInto( startStamp );
|
|
seanhalle@208
|
150 #endif
|
|
seanhalle@208
|
151 //========================================================================
|
|
seanhalle@208
|
152
|
|
seanhalle@208
|
153 //step up the size to be multiple of the cache line size
|
|
seanhalle@208
|
154 sizeRequested = (sizeRequested + CACHE_LINE_SZ) & ~(CACHE_LINE_SZ-1);
|
|
seanhalle@208
|
155 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
|
|
seanhalle@208
|
156
|
|
seanhalle@208
|
157 while( currElem != NULL )
|
|
seanhalle@208
|
158 { //check if size of currElem is big enough
|
|
seanhalle@208
|
159 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
|
|
seanhalle@208
|
160 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
|
|
seanhalle@208
|
161 if( amountExtra > 0 )
|
|
seanhalle@208
|
162 {
|
|
seanhalle@208
|
163 //look if the found element is already aligned
|
|
seanhalle@208
|
164 if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE_SZ-1)) == 0){
|
|
seanhalle@208
|
165 //found it, get out of loop
|
|
seanhalle@208
|
166 foundElem = currElem;
|
|
seanhalle@208
|
167 break;
|
|
seanhalle@208
|
168 }else{
|
|
seanhalle@208
|
169 //find first aligned address and check if it's still big enough
|
|
seanhalle@208
|
170 //check also if the space before the aligned address is big enough
|
|
seanhalle@208
|
171 //for a new element
|
|
seanhalle@208
|
172 void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE_SZ) & ~((uintptr_t)(CACHE_LINE_SZ-1)));
|
|
seanhalle@208
|
173 prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem;
|
|
seanhalle@208
|
174 sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog);
|
|
seanhalle@208
|
175 amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog);
|
|
seanhalle@208
|
176 if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){
|
|
seanhalle@208
|
177 //found suitable element
|
|
seanhalle@208
|
178 //create new previous element and exit loop
|
|
seanhalle@208
|
179 MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1;
|
|
seanhalle@208
|
180
|
|
seanhalle@208
|
181 //insert new element into free list
|
|
seanhalle@208
|
182 if(currElem->nextChunkInFreeList != NULL)
|
|
seanhalle@208
|
183 currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem;
|
|
seanhalle@208
|
184 newAlignedElem->prevChunkInFreeList = currElem;
|
|
seanhalle@208
|
185 newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList;
|
|
seanhalle@208
|
186 currElem->nextChunkInFreeList = newAlignedElem;
|
|
seanhalle@208
|
187
|
|
seanhalle@208
|
188 //set higherInMem and lowerInMem
|
|
seanhalle@208
|
189 newAlignedElem->nextHigherInMem = currElem->nextHigherInMem;
|
|
seanhalle@208
|
190 foundElemIsTopOfHeap = currElem->nextHigherInMem ==
|
|
seanhalle@208
|
191 _VMSMasterEnv->freeListHead->nextHigherInMem;
|
|
seanhalle@208
|
192 if(!foundElemIsTopOfHeap)
|
|
seanhalle@208
|
193 currElem->nextHigherInMem->nextLowerInMem = newAlignedElem;
|
|
seanhalle@208
|
194 currElem->nextHigherInMem = newAlignedElem;
|
|
seanhalle@208
|
195 newAlignedElem->nextLowerInMem = currElem;
|
|
seanhalle@208
|
196
|
|
seanhalle@208
|
197 //Found new element leaving loop
|
|
seanhalle@208
|
198 foundElem = newAlignedElem;
|
|
seanhalle@208
|
199 break;
|
|
seanhalle@208
|
200 }
|
|
seanhalle@208
|
201 }
|
|
seanhalle@208
|
202
|
|
seanhalle@208
|
203 }
|
|
seanhalle@208
|
204 currElem = currElem->nextChunkInFreeList;
|
|
seanhalle@208
|
205 }
|
|
seanhalle@208
|
206
|
|
seanhalle@208
|
207 if( foundElem == NULL )
|
|
seanhalle@208
|
208 { ERROR("\nmalloc failed\n")
|
|
seanhalle@208
|
209 return (void *)NULL; //indicates malloc failed
|
|
seanhalle@208
|
210 }
|
|
seanhalle@208
|
211 //Using a kludge to identify the element that is the top chunk in the
|
|
seanhalle@208
|
212 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
|
|
seanhalle@208
|
213 // save addr of start of heap in head's nextLowerInMem
|
|
seanhalle@208
|
214 //Will handle top of Heap specially
|
|
seanhalle@208
|
215 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
|
|
seanhalle@208
|
216 _VMSMasterEnv->freeListHead->nextHigherInMem;
|
|
seanhalle@208
|
217
|
|
seanhalle@208
|
218 //before shave off and try to insert new elem, remove found elem
|
|
seanhalle@208
|
219 //note, foundElem will never be the head, so always has valid prevChunk
|
|
seanhalle@208
|
220 foundElem->prevChunkInFreeList->nextChunkInFreeList =
|
|
seanhalle@208
|
221 foundElem->nextChunkInFreeList;
|
|
seanhalle@208
|
222 if( foundElem->nextChunkInFreeList != NULL )
|
|
seanhalle@208
|
223 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
|
|
seanhalle@208
|
224 foundElem->prevChunkInFreeList;
|
|
seanhalle@208
|
225 }
|
|
seanhalle@208
|
226 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
|
|
seanhalle@208
|
227
|
|
seanhalle@208
|
228 //if enough, turn extra into new elem & insert it
|
|
seanhalle@208
|
229 if( amountExtra > 64 )
|
|
seanhalle@208
|
230 { //make new elem by adding to addr of curr elem then casting
|
|
seanhalle@208
|
231 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
|
|
seanhalle@208
|
232 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed );
|
|
seanhalle@208
|
233 newElem->nextHigherInMem = foundElem->nextHigherInMem;
|
|
seanhalle@208
|
234 newElem->nextLowerInMem = foundElem;
|
|
seanhalle@208
|
235 foundElem->nextHigherInMem = newElem;
|
|
seanhalle@208
|
236
|
|
seanhalle@208
|
237 if( ! foundElemIsTopOfHeap )
|
|
seanhalle@208
|
238 { //there is no next higher for top of heap, so can't write to it
|
|
seanhalle@208
|
239 newElem->nextHigherInMem->nextLowerInMem = newElem;
|
|
seanhalle@208
|
240 }
|
|
seanhalle@208
|
241 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
|
|
seanhalle@208
|
242 }
|
|
seanhalle@208
|
243 else
|
|
seanhalle@208
|
244 {
|
|
seanhalle@208
|
245 sizeConsumed = sizeOfFound;
|
|
seanhalle@208
|
246 }
|
|
seanhalle@208
|
247 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
|
|
seanhalle@208
|
248
|
|
seanhalle@208
|
249 //============================= MEASUREMENT STUFF ========================
|
|
seanhalle@208
|
250 #ifdef MEAS__TIME_MALLOC
|
|
seanhalle@208
|
251 saveLowTimeStampCountInto( endStamp );
|
|
seanhalle@208
|
252 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
|
|
seanhalle@208
|
253 #endif
|
|
seanhalle@208
|
254 //========================================================================
|
|
seanhalle@208
|
255
|
|
seanhalle@208
|
256 //skip over the prolog by adding its size to the pointer return
|
|
seanhalle@208
|
257 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog));
|
|
seanhalle@208
|
258 }
|
|
seanhalle@208
|
259
|
|
seanhalle@208
|
260
|
|
seanhalle@208
|
261 /*This is sequential code -- only to be called from the Master
|
|
seanhalle@208
|
262 * When free, subtract the size of prolog from pointer, then cast it to a
|
|
seanhalle@208
|
263 * MallocProlog. Then check the nextLower and nextHigher chunks to see if
|
|
seanhalle@208
|
264 * one or both are also free, and coalesce if so, and if neither free, then
|
|
seanhalle@208
|
265 * add this one to free-list.
|
|
seanhalle@208
|
266 */
|
|
seanhalle@208
|
267 void
|
|
seanhalle@208
|
268 VMS_int__free( void *ptrToFree )
|
|
seanhalle@208
|
269 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
|
|
seanhalle@208
|
270 size_t sizeOfElem;
|
|
seanhalle@208
|
271 uint32 lowerExistsAndIsFree, higherExistsAndIsFree;
|
|
seanhalle@208
|
272
|
|
seanhalle@208
|
273 //============================= MEASUREMENT STUFF ========================
|
|
seanhalle@208
|
274 #ifdef MEAS__TIME_MALLOC
|
|
seanhalle@208
|
275 int32 startStamp, endStamp;
|
|
seanhalle@208
|
276 saveLowTimeStampCountInto( startStamp );
|
|
seanhalle@208
|
277 #endif
|
|
seanhalle@208
|
278 //========================================================================
|
|
seanhalle@208
|
279
|
|
seanhalle@208
|
280 if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem ||
|
|
seanhalle@208
|
281 ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem )
|
|
seanhalle@208
|
282 { //outside the range of data owned by VMS's malloc, so do nothing
|
|
seanhalle@208
|
283 return;
|
|
seanhalle@208
|
284 }
|
|
seanhalle@208
|
285 //subtract size of prolog to get pointer to prolog, then cast
|
|
seanhalle@208
|
286 elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog));
|
|
seanhalle@208
|
287 sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree);
|
|
seanhalle@208
|
288
|
|
seanhalle@208
|
289 if( elemToFree->prevChunkInFreeList != NULL )
|
|
seanhalle@208
|
290 { printf( "error: freeing same element twice!" ); exit(1);
|
|
seanhalle@208
|
291 }
|
|
seanhalle@208
|
292
|
|
seanhalle@208
|
293 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
|
|
seanhalle@208
|
294
|
|
seanhalle@208
|
295 nextLowerElem = elemToFree->nextLowerInMem;
|
|
seanhalle@208
|
296 nextHigherElem = elemToFree->nextHigherInMem;
|
|
seanhalle@208
|
297
|
|
seanhalle@208
|
298 if( nextHigherElem == NULL )
|
|
seanhalle@208
|
299 higherExistsAndIsFree = FALSE;
|
|
seanhalle@208
|
300 else //okay exists, now check if in the free-list by checking back ptr
|
|
seanhalle@208
|
301 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
|
|
seanhalle@208
|
302
|
|
seanhalle@208
|
303 if( nextLowerElem == NULL )
|
|
seanhalle@208
|
304 lowerExistsAndIsFree = FALSE;
|
|
seanhalle@208
|
305 else //okay, it exists, now check if it's free
|
|
seanhalle@208
|
306 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
|
|
seanhalle@208
|
307
|
|
seanhalle@208
|
308
|
|
seanhalle@208
|
309 //now, know what exists and what's free
|
|
seanhalle@208
|
310 if( lowerExistsAndIsFree )
|
|
seanhalle@208
|
311 { if( higherExistsAndIsFree )
|
|
seanhalle@208
|
312 { //both exist and are free, so coalesce all three
|
|
seanhalle@208
|
313 //First, remove higher from free-list
|
|
seanhalle@208
|
314 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
|
|
seanhalle@208
|
315 nextHigherElem->nextChunkInFreeList;
|
|
seanhalle@208
|
316 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
|
|
seanhalle@208
|
317 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
|
|
seanhalle@208
|
318 nextHigherElem->prevChunkInFreeList;
|
|
seanhalle@208
|
319 //Now, fix-up sequence-in-mem list -- by side-effect, this also
|
|
seanhalle@208
|
320 // changes size of the lower elem, which is still in free-list
|
|
seanhalle@208
|
321 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
|
|
seanhalle@208
|
322 if( nextHigherElem->nextHigherInMem !=
|
|
seanhalle@208
|
323 _VMSMasterEnv->freeListHead->nextHigherInMem )
|
|
seanhalle@208
|
324 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
|
|
seanhalle@208
|
325 //notice didn't do anything to elemToFree -- it simply is no
|
|
seanhalle@208
|
326 // longer reachable from any of the lists. Wonder if could be a
|
|
seanhalle@208
|
327 // security leak because left valid addresses in it,
|
|
seanhalle@208
|
328 // but don't care for now.
|
|
seanhalle@208
|
329 }
|
|
seanhalle@208
|
330 else
|
|
seanhalle@208
|
331 { //lower is the only of the two that exists and is free,
|
|
seanhalle@208
|
332 //In this case, no adjustment to free-list, just change mem-list.
|
|
seanhalle@208
|
333 // By side-effect, changes size of the lower elem
|
|
seanhalle@208
|
334 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
|
|
seanhalle@208
|
335 if( elemToFree->nextHigherInMem !=
|
|
seanhalle@208
|
336 _VMSMasterEnv->freeListHead->nextHigherInMem )
|
|
seanhalle@208
|
337 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
|
|
seanhalle@208
|
338 }
|
|
seanhalle@208
|
339 }
|
|
seanhalle@208
|
340 else
|
|
seanhalle@208
|
341 { //lower either doesn't exist or isn't free, so check higher
|
|
seanhalle@208
|
342 if( higherExistsAndIsFree )
|
|
seanhalle@208
|
343 { //higher exists and is the only of the two free
|
|
seanhalle@208
|
344 //First, in free-list, replace higher elem with the one to free
|
|
seanhalle@208
|
345 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
|
|
seanhalle@208
|
346 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
|
|
seanhalle@208
|
347 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
|
|
seanhalle@208
|
348 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
|
|
seanhalle@208
|
349 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
|
|
seanhalle@208
|
350 //Now chg mem-list. By side-effect, changes size of elemToFree
|
|
seanhalle@208
|
351 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
|
|
seanhalle@208
|
352 if( elemToFree->nextHigherInMem !=
|
|
seanhalle@208
|
353 _VMSMasterEnv->freeListHead->nextHigherInMem )
|
|
seanhalle@208
|
354 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
|
|
seanhalle@208
|
355 }
|
|
seanhalle@208
|
356 else
|
|
seanhalle@208
|
357 { //neither lower nor higher is availabe to coalesce so add to list
|
|
seanhalle@208
|
358 // this makes prev chunk ptr non-null, which indicates it's free
|
|
seanhalle@208
|
359 elemToFree->nextChunkInFreeList =
|
|
seanhalle@208
|
360 _VMSMasterEnv->freeListHead->nextChunkInFreeList;
|
|
seanhalle@208
|
361 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
|
|
seanhalle@208
|
362 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
|
|
seanhalle@208
|
363 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
|
|
seanhalle@208
|
364 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
|
|
seanhalle@208
|
365 }
|
|
seanhalle@208
|
366 }
|
|
seanhalle@208
|
367 //============================= MEASUREMENT STUFF ========================
|
|
seanhalle@208
|
368 #ifdef MEAS__TIME_MALLOC
|
|
seanhalle@208
|
369 saveLowTimeStampCountInto( endStamp );
|
|
seanhalle@208
|
370 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist );
|
|
seanhalle@208
|
371 #endif
|
|
seanhalle@208
|
372 //========================================================================
|
|
seanhalle@208
|
373
|
|
seanhalle@208
|
374 }
|
|
seanhalle@208
|
375
|
|
seanhalle@208
|
376
|
|
seanhalle@208
|
377 /*Allocates memory from the external system -- higher overhead
|
|
seanhalle@208
|
378 *
|
|
seanhalle@208
|
379 *Because of Linux's malloc throwing bizarre random faults when malloc is
|
|
seanhalle@208
|
380 * used inside a VMS virtual processor, have to pass this as a request and
|
|
seanhalle@208
|
381 * have the core loop do it when it gets around to it -- will look for these
|
|
seanhalle@208
|
382 * chores leftover from the previous animation of masterVP the next time it
|
|
seanhalle@208
|
383 * goes to animate the masterVP -- so it takes two separate masterVP
|
|
seanhalle@208
|
384 * animations, separated by work, to complete an external malloc or
|
|
seanhalle@208
|
385 * external free request.
|
|
seanhalle@208
|
386 *
|
|
seanhalle@208
|
387 *Thinking core loop accepts signals -- just looks if signal-location is
|
|
seanhalle@208
|
388 * empty or not --
|
|
seanhalle@208
|
389 */
|
|
seanhalle@208
|
390 void *
|
|
seanhalle@208
|
391 VMS__malloc_in_ext( size_t sizeRequested )
|
|
seanhalle@208
|
392 {
|
|
seanhalle@208
|
393 /*
|
|
seanhalle@208
|
394 //This is running in the master, so no chance for multiple cores to be
|
|
seanhalle@208
|
395 // competing for the core's flag.
|
|
seanhalle@208
|
396 if( *(_VMSMasterEnv->coreLoopSignalAddr[ 0 ]) != 0 )
|
|
seanhalle@208
|
397 { //something has already signalled to core loop, so save the signal
|
|
seanhalle@208
|
398 // and look, next time master animated, to see if can send it.
|
|
seanhalle@208
|
399 //Note, the addr to put a signal is in the coreloop's frame, so just
|
|
seanhalle@208
|
400 // checks it each time through -- make it volatile to avoid GCC
|
|
seanhalle@208
|
401 // optimizations -- it's a coreloop local var that only changes
|
|
seanhalle@208
|
402 // after jumping away. The signal includes the addr to send the
|
|
seanhalle@208
|
403 //return to -- even if just empty return completion-signal
|
|
seanhalle@208
|
404 //
|
|
seanhalle@208
|
405 //save the signal in some queue that the master looks at each time
|
|
seanhalle@208
|
406 // it starts up -- one loc says if empty for fast common case --
|
|
seanhalle@208
|
407 //something like that -- want to hide this inside this call -- but
|
|
seanhalle@208
|
408 // think this has to come as a request -- req handler gives procr
|
|
seanhalle@208
|
409 // back to master loop, which gives it back to req handler at point
|
|
seanhalle@208
|
410 // it sees that core loop has sent return signal. Something like
|
|
seanhalle@208
|
411 // that.
|
|
seanhalle@208
|
412 saveTheSignal
|
|
seanhalle@208
|
413
|
|
seanhalle@208
|
414 }
|
|
seanhalle@208
|
415 coreSigData->type = malloc;
|
|
seanhalle@208
|
416 coreSigData->sizeToMalloc = sizeRequested;
|
|
seanhalle@208
|
417 coreSigData->locToSignalCompletion = &figureOut;
|
|
seanhalle@208
|
418 _VMSMasterEnv->coreLoopSignals[ 0 ] = coreSigData;
|
|
seanhalle@208
|
419 */
|
|
seanhalle@208
|
420 //just risk system-stack faults until get this figured out
|
|
seanhalle@208
|
421 return malloc( sizeRequested );
|
|
seanhalle@208
|
422 }
|
|
seanhalle@208
|
423
|
|
seanhalle@208
|
424
|
|
seanhalle@208
|
425 /*Frees memory that was allocated in the external system -- higher overhead
|
|
seanhalle@208
|
426 *
|
|
seanhalle@208
|
427 *As noted in external malloc comment, this is clunky 'cause the free has
|
|
seanhalle@208
|
428 * to be called in the core loop.
|
|
seanhalle@208
|
429 */
|
|
seanhalle@208
|
430 void
|
|
seanhalle@208
|
431 VMS__free_in_ext( void *ptrToFree )
|
|
seanhalle@208
|
432 {
|
|
seanhalle@208
|
433 //just risk system-stack faults until get this figured out
|
|
seanhalle@208
|
434 free( ptrToFree );
|
|
seanhalle@208
|
435
|
|
seanhalle@208
|
436 //TODO: fix this -- so
|
|
seanhalle@208
|
437 }
|
|
seanhalle@208
|
438
|
|
seanhalle@208
|
439
|
|
seanhalle@208
|
440 /*Designed to be called from the main thread outside of VMS, during init
|
|
seanhalle@208
|
441 */
|
|
seanhalle@208
|
442 MallocProlog *
|
|
seanhalle@208
|
443 VMS_ext__create_free_list()
|
|
seanhalle@208
|
444 { MallocProlog *freeListHead, *firstChunk;
|
|
seanhalle@208
|
445
|
|
seanhalle@208
|
446 //Note, this is running in the main thread -- all increases in malloc
|
|
seanhalle@208
|
447 // mem and all frees of it must be done in this thread, with the
|
|
seanhalle@208
|
448 // thread's original stack available
|
|
seanhalle@208
|
449 freeListHead = malloc( sizeof(MallocProlog) );
|
|
seanhalle@208
|
450 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
|
|
seanhalle@208
|
451 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
|
|
seanhalle@208
|
452
|
|
seanhalle@208
|
453 //Touch memory to avoid page faults
|
|
seanhalle@208
|
454 void *ptr,*endPtr;
|
|
seanhalle@208
|
455 endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
|
|
seanhalle@208
|
456 for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE)
|
|
seanhalle@208
|
457 {
|
|
seanhalle@208
|
458 *(char*)ptr = 0;
|
|
seanhalle@208
|
459 }
|
|
seanhalle@208
|
460
|
|
seanhalle@208
|
461 freeListHead->prevChunkInFreeList = NULL;
|
|
seanhalle@208
|
462 //Use this addr to free the heap when cleanup
|
|
seanhalle@208
|
463 freeListHead->nextLowerInMem = firstChunk;
|
|
seanhalle@208
|
464 //to identify top-of-heap elem, compare this addr to elem's next higher
|
|
seanhalle@208
|
465 freeListHead->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
|
|
seanhalle@208
|
466 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
|
|
seanhalle@208
|
467 freeListHead->nextChunkInFreeList = firstChunk;
|
|
seanhalle@208
|
468
|
|
seanhalle@208
|
469 firstChunk->nextChunkInFreeList = NULL;
|
|
seanhalle@208
|
470 firstChunk->prevChunkInFreeList = freeListHead;
|
|
seanhalle@208
|
471 //next Higher has to be set to top of chunk, so can calc size in malloc
|
|
seanhalle@208
|
472 firstChunk->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
|
|
seanhalle@208
|
473 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
|
|
seanhalle@208
|
474 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap
|
|
seanhalle@208
|
475
|
|
seanhalle@208
|
476 _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
|
|
seanhalle@208
|
477
|
|
seanhalle@208
|
478 return freeListHead;
|
|
seanhalle@208
|
479 }
|
|
seanhalle@208
|
480
|
|
seanhalle@208
|
481
|
|
seanhalle@208
|
482 /*Designed to be called from the main thread outside of VMS, during cleanup
|
|
seanhalle@208
|
483 */
|
|
seanhalle@208
|
484 void
|
|
seanhalle@208
|
485 VMS_ext__free_free_list( MallocProlog *freeListHead )
|
|
seanhalle@208
|
486 {
|
|
seanhalle@208
|
487 //stashed a ptr to the one and only bug chunk malloc'd from OS in the
|
|
seanhalle@208
|
488 // free list head's next lower in mem pointer
|
|
seanhalle@208
|
489 free( freeListHead->nextLowerInMem );
|
|
seanhalle@208
|
490
|
|
seanhalle@208
|
491 //don't free the head -- it'll be in an array eventually -- free whole
|
|
seanhalle@208
|
492 // array when all the free lists linked from it have already been freed
|
|
seanhalle@208
|
493 }
|
|
seanhalle@208
|
494
|