Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
view vmalloc.c @ 132:dbfc8382d546
distributed memory allocation interface - unfinished
| author | Merten Sach <msach@mailbox.tu-berlin.de> |
|---|---|
| date | Fri, 16 Sep 2011 14:25:49 +0200 |
| parents | 21c95d402fe6 |
| children | a9b72021f053 |
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 <inttypes.h>
12 #include <stdlib.h>
13 #include <stdio.h>
15 #include "ProcrContext.h"
16 #include "Histogram/Histogram.h"
18 /*Helper function
19 *Insert a newly generated free chunk into the first spot on the free list.
20 * The chunk is cast as a MallocProlog, so the various pointers in it are
21 * accessed with C's help -- and the size of the prolog is easily added to
22 * the pointer when a chunk is returned to the app -- so C handles changes
23 * in pointer sizes among machines.
24 *
25 *The list head is a normal MallocProlog struct -- identified by its
26 * prevChunkInFreeList being NULL -- the only one.
27 *
28 *The end of the list is identified by next chunk being NULL, as usual.
29 */
30 void inline
31 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
32 {
33 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList;
34 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
35 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
36 chunk->prevChunkInFreeList = listHead;
37 listHead->nextChunkInFreeList = chunk;
38 }
40 /*
41 * This function is called by code which is part of the master loop.
42 * This reads the animating coreID from the MasterEnv and calls the normal malloc
43 * in VMS__malloc_on_core
44 */
45 void *
46 VMS__malloc( size_t sizeRequested)
47 {
48 return VMS__malloc_on_core(sizeRequested, _VMSMasterEnv->currentMasterProcrID);
49 }
51 /*
52 * This is called by the plugin. This call to VMS_malloc_on_core is run on the
53 * slave VPs stack so there is no switch to the VMS runtime.
54 */
55 void *
56 VMS__malloc_in_lib(size_t sizeRequested, VirtProcr *VProcr)
57 {
58 return VMS__malloc_on_core(sizeRequested, VProcr->coreAnimatedBy);
59 }
61 /*
62 *Search down list, checking size by the nextHigherInMem pointer, to find
63 * first chunk bigger than size needed.
64 *Shave off the extra and make it into a new free-list element, hook it in
65 * then return the address of the found element plus size of prolog.
66 */
67 void *
68 VMS__malloc_on_core( size_t sizeRequested, int procrID)
69 { MallocProlog *foundElem = NULL, *currElem, *newElem;
70 MallocPrologAllocated *returnElem;
71 ssize_t amountExtra, sizeConsumed,sizeOfFound;
72 uint32 foundElemIsTopOfHeap;
74 //============================= MEASUREMENT STUFF ========================
75 #ifdef MEAS__TIME_MALLOC
76 int32 startStamp, endStamp;
77 saveLowTimeStampCountInto( startStamp );
78 #endif
79 //========================================================================
81 //step up the size to be aligned at 16-byte boundary, prob better ways
82 sizeRequested = (sizeRequested + 16) & ~15;
83 currElem = (_VMSMasterEnv->freeListHead[_VMSMasterEnv->currentMasterProcrID])
84 ->nextChunkInFreeList;
86 while( currElem != NULL )
87 { //check if size of currElem is big enough
88 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
89 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
90 if( amountExtra > 0 )
91 { //found it, get out of loop
92 foundElem = currElem;
93 currElem = NULL;
94 }
95 else
96 currElem = currElem->nextChunkInFreeList;
97 }
99 if( foundElem == NULL )
100 { ERROR("\nmalloc failed\n")
101 return (void *)NULL; //indicates malloc failed
102 }
103 //Using a kludge to identify the element that is the top chunk in the
104 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
105 // save addr of start of heap in head's nextLowerInMem
106 //Will handle top of Heap specially
107 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
108 _VMSMasterEnv->freeListHead->nextHigherInMem;
110 //before shave off and try to insert new elem, remove found elem
111 //note, foundElem will never be the head, so always has valid prevChunk
112 foundElem->prevChunkInFreeList->nextChunkInFreeList =
113 foundElem->nextChunkInFreeList;
114 if( foundElem->nextChunkInFreeList != NULL )
115 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
116 foundElem->prevChunkInFreeList;
117 }
118 returnElem = (MallocPrologAllocated*)foundElem;
119 returnElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
120 returnElem->procrID = procrID;
122 //if enough, turn extra into new elem & insert it
123 if( amountExtra > 64 )
124 { //make new elem by adding to addr of curr elem then casting
125 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
126 newElem = (MallocProlog *)( (uintptr_t)returnElem + sizeConsumed );
127 newElem->nextLowerInMem = returnElem; //This is evil (but why?)
128 newElem->nextHigherInMem = returnElem->nextHigherInMem; //This is evil (but why?)
129 returnElem->nextHigherInMem = newElem;
130 if( ! foundElemIsTopOfHeap )
131 { //there is no next higher for top of heap, so can't write to it
132 newElem->nextHigherInMem->nextLowerInMem = newElem;
133 }
134 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
135 }
136 else
137 {
138 sizeConsumed = sizeOfFound;
139 }
140 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
142 //============================= MEASUREMENT STUFF ========================
143 #ifdef MEAS__TIME_MALLOC
144 saveLowTimeStampCountInto( endStamp );
145 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
146 #endif
147 //========================================================================
149 //skip over the prolog by adding its size to the pointer return
150 return (void*)((uintptr_t)returnElem + sizeof(MallocProlog));
151 }
153 /*
154 * This free is called for a master loop. It decides whether the allocation of
155 * chunk was done on the same core. If it was it calls VMS__free_on_core
156 * otherwise it sends a message to the responsible core.
157 */
158 void
159 VMS__free(void *ptrToFree)
160 {
161 MallocPrologAllocated chunk = (MallocPrologAllocated*)ptrToFree - 1;
162 if(chunk->procrID == _VMSMasterEnv->currentMasterProcrID)
163 {
164 VMS__free_on_core(ptrToFree, _VMSMasterEnv->currentMasterProcrID);
165 }
166 else
167 {
168 //Request from other Core
169 }
170 }
172 /*
173 * This free is called for the plugins. It decides whether the allocation of
174 * chunk was done on the same core. If it was it calls VMS__free_on_core
175 * otherwise it sends a message to the responsible core.
176 */
177 void
178 VMS__free_in_lib(void *ptrToFree, VirtProcr *VProc)
179 {
180 MallocPrologAllocated chunk = (MallocPrologAllocated*)ptrToFree - 1;
181 if(chunk->procrID == VProc->coreAnimatedBy)
182 {
183 VMS__free_on_core(ptrToFree, VProc->coreAnimatedBy);
184 }
185 else
186 {
187 //Request from other Core
188 }
189 }
191 /*This is sequential code -- only to be called from the Master
192 * When free, subtract the size of prolog from pointer, then cast it to a
193 * MallocProlog. Then check the nextLower and nextHigher chunks to see if
194 * one or both are also free, and coalesce if so, and if neither free, then
195 * add this one to free-list.
196 */
197 void
198 VMS__free_on_core( void *ptrToFree, int procrID)
199 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
200 size_t sizeOfElem;
201 uint32 lowerExistsAndIsFree, higherExistsAndIsFree;
203 //============================= MEASUREMENT STUFF ========================
204 #ifdef MEAS__TIME_MALLOC
205 int32 startStamp, endStamp;
206 saveLowTimeStampCountInto( startStamp );
207 #endif
208 //========================================================================
210 if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem ||
211 ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem )
212 { //outside the range of data owned by VMS's malloc, so do nothing
213 return;
214 }
215 //subtract size of prolog to get pointer to prolog, then cast
216 elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog));
217 sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree);
219 if( elemToFree->prevChunkInFreeList != NULL )
220 { printf( "error: freeing same element twice!" ); exit(1);
221 }
223 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
225 nextLowerElem = elemToFree->nextLowerInMem;
226 nextHigherElem = elemToFree->nextHigherInMem;
228 if( nextHigherElem == NULL )
229 higherExistsAndIsFree = FALSE;
230 else //okay exists, now check if in the free-list by checking back ptr
231 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
233 if( nextLowerElem == NULL )
234 lowerExistsAndIsFree = FALSE;
235 else //okay, it exists, now check if it's free
236 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
239 //now, know what exists and what's free
240 if( lowerExistsAndIsFree )
241 { if( higherExistsAndIsFree )
242 { //both exist and are free, so coalesce all three
243 //First, remove higher from free-list
244 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
245 nextHigherElem->nextChunkInFreeList;
246 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
247 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
248 nextHigherElem->prevChunkInFreeList;
249 //Now, fix-up sequence-in-mem list -- by side-effect, this also
250 // changes size of the lower elem, which is still in free-list
251 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
252 if( nextHigherElem->nextHigherInMem !=
253 _VMSMasterEnv->freeListHead->nextHigherInMem )
254 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
255 //notice didn't do anything to elemToFree -- it simply is no
256 // longer reachable from any of the lists. Wonder if could be a
257 // security leak because left valid addresses in it,
258 // but don't care for now.
259 }
260 else
261 { //lower is the only of the two that exists and is free,
262 //In this case, no adjustment to free-list, just change mem-list.
263 // By side-effect, changes size of the lower elem
264 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
265 if( elemToFree->nextHigherInMem !=
266 _VMSMasterEnv->freeListHead->nextHigherInMem )
267 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
268 }
269 }
270 else
271 { //lower either doesn't exist or isn't free, so check higher
272 if( higherExistsAndIsFree )
273 { //higher exists and is the only of the two free
274 //First, in free-list, replace higher elem with the one to free
275 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
276 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
277 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
278 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
279 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
280 //Now chg mem-list. By side-effect, changes size of elemToFree
281 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
282 if( elemToFree->nextHigherInMem !=
283 _VMSMasterEnv->freeListHead->nextHigherInMem )
284 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
285 }
286 else
287 { //neither lower nor higher is availabe to coalesce so add to list
288 // this makes prev chunk ptr non-null, which indicates it's free
289 elemToFree->nextChunkInFreeList =
290 _VMSMasterEnv->freeListHead->nextChunkInFreeList;
291 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
292 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
293 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
294 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
295 }
296 }
297 //============================= MEASUREMENT STUFF ========================
298 #ifdef MEAS__TIME_MALLOC
299 saveLowTimeStampCountInto( endStamp );
300 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->freeTimeHist );
301 #endif
302 //========================================================================
304 }
307 /*Allocates memory from the external system -- higher overhead
308 *
309 *Because of Linux's malloc throwing bizarre random faults when malloc is
310 * used inside a VMS virtual processor, have to pass this as a request and
311 * have the core loop do it when it gets around to it -- will look for these
312 * chores leftover from the previous animation of masterVP the next time it
313 * goes to animate the masterVP -- so it takes two separate masterVP
314 * animations, separated by work, to complete an external malloc or
315 * external free request.
316 *
317 *Thinking core loop accepts signals -- just looks if signal-location is
318 * empty or not --
319 */
320 void *
321 VMS__malloc_in_ext( size_t sizeRequested )
322 {
323 /*
324 //This is running in the master, so no chance for multiple cores to be
325 // competing for the core's flag.
326 if( *(_VMSMasterEnv->coreLoopSignalAddr[ 0 ]) != 0 )
327 { //something has already signalled to core loop, so save the signal
328 // and look, next time master animated, to see if can send it.
329 //Note, the addr to put a signal is in the coreloop's frame, so just
330 // checks it each time through -- make it volatile to avoid GCC
331 // optimizations -- it's a coreloop local var that only changes
332 // after jumping away. The signal includes the addr to send the
333 //return to -- even if just empty return completion-signal
334 //
335 //save the signal in some queue that the master looks at each time
336 // it starts up -- one loc says if empty for fast common case --
337 //something like that -- want to hide this inside this call -- but
338 // think this has to come as a request -- req handler gives procr
339 // back to master loop, which gives it back to req handler at point
340 // it sees that core loop has sent return signal. Something like
341 // that.
342 saveTheSignal
344 }
345 coreSigData->type = malloc;
346 coreSigData->sizeToMalloc = sizeRequested;
347 coreSigData->locToSignalCompletion = &figureOut;
348 _VMSMasterEnv->coreLoopSignals[ 0 ] = coreSigData;
349 */
350 //just risk system-stack faults until get this figured out
351 return malloc( sizeRequested );
352 }
355 /*Frees memory that was allocated in the external system -- higher overhead
356 *
357 *As noted in external malloc comment, this is clunky 'cause the free has
358 * to be called in the core loop.
359 */
360 void
361 VMS__free_in_ext( void *ptrToFree )
362 {
363 //just risk system-stack faults until get this figured out
364 free( ptrToFree );
366 //TODO: fix this -- so
367 }
370 /*Designed to be called from the main thread outside of VMS, during init
371 */
372 MallocProlog *
373 VMS_ext__create_free_list()
374 { MallocProlog *freeListHead, *firstChunk;
376 //Note, this is running in the main thread -- all increases in malloc
377 // mem and all frees of it must be done in this thread, with the
378 // thread's original stack available
379 freeListHead = malloc( sizeof(MallocProlog) );
380 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
381 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
383 //Touch memory to avoid page faults
384 void *ptr,*endPtr;
385 endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
386 for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE)
387 {
388 *(char*)ptr = 0;
389 }
391 freeListHead->prevChunkInFreeList = NULL;
392 //Use this addr to free the heap when cleanup
393 freeListHead->nextLowerInMem = firstChunk;
394 //to identify top-of-heap elem, compare this addr to elem's next higher
395 freeListHead->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
396 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
397 freeListHead->nextChunkInFreeList = firstChunk;
399 firstChunk->nextChunkInFreeList = NULL;
400 firstChunk->prevChunkInFreeList = freeListHead;
401 //next Higher has to be set to top of chunk, so can calc size in malloc
402 firstChunk->nextHigherInMem = (void*)( (uintptr_t)firstChunk +
403 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
404 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap
406 _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
408 return freeListHead;
409 }
412 /*Designed to be called from the main thread outside of VMS, during cleanup
413 */
414 void
415 VMS_ext__free_free_list( MallocProlog *freeListHead )
416 {
417 //stashed a ptr to the one and only bug chunk malloc'd from OS in the
418 // free list head's next lower in mem pointer
419 free( freeListHead->nextLowerInMem );
421 //don't free the head -- it'll be in an array eventually -- free whole
422 // array when all the free lists linked from it have already been freed
423 }
