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