Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
view vmalloc.c @ 146:a49f02980151
fixed: hist index error, zero devision
| author | Merten Sach <msach@mailbox.tu-berlin.de> |
|---|---|
| date | Thu, 12 May 2011 14:23:41 +0200 |
| parents | 13b22ffb8a2f |
| children | 9ddbb071142d |
line source
1 /*
2 * Copyright 2009 OpenSourceCodeStewardshipFoundation.org
3 * Licensed under GNU General Public License version 2
4 *
5 * Author: seanhalle@yahoo.com
6 *
7 * Created on November 14, 2009, 9:07 PM
8 */
10 #include <malloc.h>
11 #include <stdlib.h>
13 #include "VMS.h"
14 #include "Histogram/Histogram.h"
16 /*Helper function
17 *Insert a newly generated free chunk into the first spot on the free list.
18 * The chunk is cast as a MallocProlog, so the various pointers in it are
19 * accessed with C's help -- and the size of the prolog is easily added to
20 * the pointer when a chunk is returned to the app -- so C handles changes
21 * in pointer sizes among machines.
22 *
23 *The list head is a normal MallocProlog struct -- identified by its
24 * prevChunkInFreeList being NULL -- the only one.
25 *
26 *The end of the list is identified by next chunk being NULL, as usual.
27 */
28 void inline
29 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
30 {
31 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList;
32 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
33 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
34 chunk->prevChunkInFreeList = listHead;
35 listHead->nextChunkInFreeList = chunk;
36 }
39 /*This is sequential code, meant to only be called from the Master, not from
40 * any slave VPs.
41 *Search down list, checking size by the nextHigherInMem pointer, to find
42 * first chunk bigger than size needed.
43 *Shave off the extra and make it into a new free-list element, hook it in
44 * then return the address of the found element plus size of prolog.
45 *
46 *Will find a
47 */
48 void *
49 VMS__malloc( int32 sizeRequested )
50 { MallocProlog *foundElem = NULL, *currElem, *newElem;
51 int32 amountExtra, foundElemIsTopOfHeap, sizeConsumed,sizeOfFound;
53 //============================= MEASUREMENT STUFF ========================
54 #ifdef MEAS__TIME_MALLOC
55 int32 startStamp, endStamp;
56 saveLowTimeStampCountInto( startStamp );
57 #endif
58 //========================================================================
60 //step up the size to be aligned at 16-byte boundary, prob better ways
61 sizeRequested = ((sizeRequested + 16) >> 4) << 4;
62 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
64 while( currElem != NULL )
65 { //check if size of currElem is big enough
66 sizeOfFound=(int32)((char*)currElem->nextHigherInMem -(char*)currElem);
67 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
68 if( amountExtra > 0 )
69 { //found it, get out of loop
70 foundElem = currElem;
71 currElem = NULL;
72 }
73 else
74 currElem = currElem->nextChunkInFreeList;
75 }
77 if( foundElem == NULL )
78 { ERROR("\nmalloc failed\n")
79 return (void *)NULL; //indicates malloc failed
80 }
81 //Using a kludge to identify the element that is the top chunk in the
82 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
83 // save addr of start of heap in head's nextLowerInMem
84 //Will handle top of Heap specially
85 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
86 _VMSMasterEnv->freeListHead->nextHigherInMem;
88 //before shave off and try to insert new elem, remove found elem
89 //note, foundElem will never be the head, so always has valid prevChunk
90 foundElem->prevChunkInFreeList->nextChunkInFreeList =
91 foundElem->nextChunkInFreeList;
92 if( foundElem->nextChunkInFreeList != NULL )
93 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
94 foundElem->prevChunkInFreeList;
95 }
96 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
98 //if enough, turn extra into new elem & insert it
99 if( amountExtra > 64 )
100 { //make new elem by adding to addr of curr elem then casting
101 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
102 newElem = (MallocProlog *)( (char *)foundElem + sizeConsumed );
103 newElem->nextHigherInMem = foundElem->nextHigherInMem;
104 newElem->nextLowerInMem = foundElem;
105 foundElem->nextHigherInMem = newElem;
107 if( ! foundElemIsTopOfHeap )
108 { //there is no next higher for top of heap, so can't write to it
109 newElem->nextHigherInMem->nextLowerInMem = newElem;
110 }
111 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
112 }
113 else
114 {
115 sizeConsumed = sizeOfFound;
116 }
117 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
119 //============================= MEASUREMENT STUFF ========================
120 #ifdef MEAS__TIME_MALLOC
121 saveLowTimeStampCountInto( endStamp );
122 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
123 #endif
124 //========================================================================
126 //skip over the prolog by adding its size to the pointer return
127 return (void *)((char *)foundElem + sizeof(MallocProlog));
128 }
131 /*This is sequential code -- only to be called from the Master
132 * When free, subtract the size of prolog from pointer, then cast it to a
133 * MallocProlog. Then check the nextLower and nextHigher chunks to see if
134 * one or both are also free, and coalesce if so, and if neither free, then
135 * add this one to free-list.
136 */
137 void
138 VMS__free( void *ptrToFree )
139 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
140 int32 lowerExistsAndIsFree, higherExistsAndIsFree, sizeOfElem;
142 //============================= MEASUREMENT STUFF ========================
143 #ifdef MEAS__TIME_MALLOC
144 int32 startStamp, endStamp;
145 saveLowTimeStampCountInto( startStamp );
146 #endif
147 //========================================================================
149 if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem ||
150 ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem )
151 { //outside the range of data owned by VMS's malloc, so do nothing
152 return;
153 }
154 //subtract size of prolog to get pointer to prolog, then cast
155 elemToFree = (MallocProlog *)((char *)ptrToFree - sizeof(MallocProlog));
156 sizeOfElem =(int32)((char*)elemToFree->nextHigherInMem-(char*)elemToFree);
158 if( elemToFree->prevChunkInFreeList != NULL )
159 { printf( "error: freeing same element twice!" ); exit(1);
160 }
162 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
164 nextLowerElem = elemToFree->nextLowerInMem;
165 nextHigherElem = elemToFree->nextHigherInMem;
167 if( nextHigherElem == NULL )
168 higherExistsAndIsFree = FALSE;
169 else //okay exists, now check if in the free-list by checking back ptr
170 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
172 if( nextLowerElem == NULL )
173 lowerExistsAndIsFree = FALSE;
174 else //okay, it exists, now check if it's free
175 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
178 //now, know what exists and what's free
179 if( lowerExistsAndIsFree )
180 { if( higherExistsAndIsFree )
181 { //both exist and are free, so coalesce all three
182 //First, remove higher from free-list
183 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
184 nextHigherElem->nextChunkInFreeList;
185 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
186 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
187 nextHigherElem->prevChunkInFreeList;
188 //Now, fix-up sequence-in-mem list -- by side-effect, this also
189 // changes size of the lower elem, which is still in free-list
190 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
191 if( nextHigherElem->nextHigherInMem !=
192 _VMSMasterEnv->freeListHead->nextHigherInMem )
193 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
194 //notice didn't do anything to elemToFree -- it simply is no
195 // longer reachable from any of the lists. Wonder if could be a
196 // security leak because left valid addresses in it,
197 // but don't care for now.
198 }
199 else
200 { //lower is the only of the two that exists and is free,
201 //In this case, no adjustment to free-list, just change mem-list.
202 // By side-effect, changes size of the lower elem
203 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
204 if( elemToFree->nextHigherInMem !=
205 _VMSMasterEnv->freeListHead->nextHigherInMem )
206 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
207 }
208 }
209 else
210 { //lower either doesn't exist or isn't free, so check higher
211 if( higherExistsAndIsFree )
212 { //higher exists and is the only of the two free
213 //First, in free-list, replace higher elem with the one to free
214 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
215 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
216 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
217 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
218 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
219 //Now chg mem-list. By side-effect, changes size of elemToFree
220 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
221 if( elemToFree->nextHigherInMem !=
222 _VMSMasterEnv->freeListHead->nextHigherInMem )
223 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
224 }
225 else
226 { //neither lower nor higher is availabe to coalesce so add to list
227 // this makes prev chunk ptr non-null, which indicates it's free
228 elemToFree->nextChunkInFreeList =
229 _VMSMasterEnv->freeListHead->nextChunkInFreeList;
230 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
231 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
232 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
233 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
234 }
235 }
236 //============================= MEASUREMENT STUFF ========================
237 #ifdef MEAS__TIME_MALLOC
238 saveLowTimeStampCountInto( endStamp );
239 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist );
240 #endif
241 //========================================================================
243 }
246 /*Allocates memory from the external system -- higher overhead
247 *
248 *Because of Linux's malloc throwing bizarre random faults when malloc is
249 * used inside a VMS virtual processor, have to pass this as a request and
250 * have the core loop do it when it gets around to it -- will look for these
251 * chores leftover from the previous animation of masterVP the next time it
252 * goes to animate the masterVP -- so it takes two separate masterVP
253 * animations, separated by work, to complete an external malloc or
254 * external free request.
255 *
256 *Thinking core loop accepts signals -- just looks if signal-location is
257 * empty or not --
258 */
259 void *
260 VMS__malloc_in_ext( int32 sizeRequested )
261 {
262 /*
263 //This is running in the master, so no chance for multiple cores to be
264 // competing for the core's flag.
265 if( *(_VMSMasterEnv->coreLoopSignalAddr[ 0 ]) != 0 )
266 { //something has already signalled to core loop, so save the signal
267 // and look, next time master animated, to see if can send it.
268 //Note, the addr to put a signal is in the coreloop's frame, so just
269 // checks it each time through -- make it volatile to avoid GCC
270 // optimizations -- it's a coreloop local var that only changes
271 // after jumping away. The signal includes the addr to send the
272 //return to -- even if just empty return completion-signal
273 //
274 //save the signal in some queue that the master looks at each time
275 // it starts up -- one loc says if empty for fast common case --
276 //something like that -- want to hide this inside this call -- but
277 // think this has to come as a request -- req handler gives procr
278 // back to master loop, which gives it back to req handler at point
279 // it sees that core loop has sent return signal. Something like
280 // that.
281 saveTheSignal
283 }
284 coreSigData->type = malloc;
285 coreSigData->sizeToMalloc = sizeRequested;
286 coreSigData->locToSignalCompletion = &figureOut;
287 _VMSMasterEnv->coreLoopSignals[ 0 ] = coreSigData;
288 */
289 //just risk system-stack faults until get this figured out
290 return malloc( sizeRequested );
291 }
294 /*Frees memory that was allocated in the external system -- higher overhead
295 *
296 *As noted in external malloc comment, this is clunky 'cause the free has
297 * to be called in the core loop.
298 */
299 void
300 VMS__free_in_ext( void *ptrToFree )
301 {
302 //just risk system-stack faults until get this figured out
303 free( ptrToFree );
305 //TODO: fix this -- so
306 }
309 /*Designed to be called from the main thread outside of VMS, during init
310 */
311 MallocProlog *
312 VMS_ext__create_free_list()
313 { MallocProlog *freeListHead, *firstChunk;
315 //Note, this is running in the main thread -- all increases in malloc
316 // mem and all frees of it must be done in this thread, with the
317 // thread's original stack available
318 freeListHead = malloc( sizeof(MallocProlog) );
319 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
320 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
322 freeListHead->prevChunkInFreeList = NULL;
323 //Use this addr to free the heap when cleanup
324 freeListHead->nextLowerInMem = firstChunk;
325 //to identify top-of-heap elem, compare this addr to elem's next higher
326 freeListHead->nextHigherInMem = (void*)( (char*)firstChunk +
327 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
328 freeListHead->nextChunkInFreeList = firstChunk;
330 firstChunk->nextChunkInFreeList = NULL;
331 firstChunk->prevChunkInFreeList = freeListHead;
332 //next Higher has to be set to top of chunk, so can calc size in malloc
333 firstChunk->nextHigherInMem = (void*)( (char*)firstChunk +
334 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
335 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap
337 _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
339 return freeListHead;
340 }
343 /*Designed to be called from the main thread outside of VMS, during cleanup
344 */
345 void
346 VMS_ext__free_free_list( MallocProlog *freeListHead )
347 {
348 //stashed a ptr to the one and only bug chunk malloc'd from OS in the
349 // free list head's next lower in mem pointer
350 free( freeListHead->nextLowerInMem );
352 //don't free the head -- it'll be in an array eventually -- free whole
353 // array when all the free lists linked from it have already been freed
354 }
