Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
view vmalloc.c @ 50:8f7141a9272e
Added VMS__malloc and probes, and major re-factoring to separate mallocs
| author | Me |
|---|---|
| date | Sat, 30 Oct 2010 20:54:36 -0700 |
| parents | |
| children | 42dd44df1bb0 |
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>
12 #include "VMS.h"
14 /*Helper function
15 *Insert a newly generated free chunk into the first spot on the free list.
16 * The chunk is cast as a MallocProlog, so the various pointers in it are
17 * accessed with C's help -- and the size of the prolog is easily added to
18 * the pointer when a chunk is returned to the app -- so C handles changes
19 * in pointer sizes among machines.
20 *
21 *The list head is a normal MallocProlog struct -- identified by its
22 * prevChunkInFreeList being NULL -- the only one.
23 *
24 *The end of the list is identified by next chunk being NULL, as usual.
25 */
26 void inline
27 add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
28 {
29 chunk->nextChunkInFreeList = listHead->nextChunkInFreeList;
30 if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
31 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
32 chunk->prevChunkInFreeList = listHead;
33 listHead->nextChunkInFreeList = chunk;
34 }
37 /*This is sequential code, meant to only be called from the Master, not from
38 * any slave VPs.
39 *Search down list, checking size by the nextHigherInMem pointer, to find
40 * first chunk bigger than size needed.
41 *Shave off the extra and make it into a new free-list element, hook it in
42 * then return the address of the found element plus size of prolog.
43 *
44 *Will find a
45 */
46 void *
47 VMS__malloc( int32 sizeRequested )
48 { MallocProlog *foundElem = NULL, *currElem, *newElem;
49 int32 amountExtra, foundElemIsTopOfHeap, sizeConsumed,sizeOfFound;
51 //step up the size to be aligned at 16-byte boundary, prob better ways
52 sizeRequested = ((sizeRequested + 16) >> 4) << 4;
53 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
55 while( currElem != NULL )
56 { //check if size of currElem is big enough
57 sizeOfFound=(int32)((char*)currElem->nextHigherInMem -(char*)currElem);
58 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
59 if( amountExtra > 0 )
60 { //found it, get out of loop
61 foundElem = currElem;
62 currElem = NULL;
63 }
64 else
65 currElem = currElem->nextChunkInFreeList;
66 }
68 if( foundElem == NULL )
69 { PRINT_ERROR("\nmalloc failed\n")
70 return NULL; //indicates malloc failed
71 }
72 //Using a kludge to identify the element that is the top chunk in the
73 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
74 // save addr of start of heap in head's nextLowerInMem
75 //Will handle top of Heap specially
76 foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
77 _VMSMasterEnv->freeListHead->nextHigherInMem;
79 //before shave off and try to insert new elem, remove found elem
80 //note, foundElem will never be the head, so always has valid prevChunk
81 foundElem->prevChunkInFreeList->nextChunkInFreeList =
82 foundElem->nextChunkInFreeList;
83 if( foundElem->nextChunkInFreeList != NULL )
84 { foundElem->nextChunkInFreeList->prevChunkInFreeList =
85 foundElem->prevChunkInFreeList;
86 }
87 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
89 //if enough, turn extra into new elem & insert it
90 if( amountExtra > 64 )
91 { //make new elem by adding to addr of curr elem then casting
92 sizeConsumed = sizeof(MallocProlog) + sizeRequested;
93 newElem = (MallocProlog *)( (char *)foundElem + sizeConsumed );
94 newElem->nextHigherInMem = foundElem->nextHigherInMem;
95 newElem->nextLowerInMem = foundElem;
96 foundElem->nextHigherInMem = newElem;
98 if( ! foundElemIsTopOfHeap )
99 { //there is no next higher for top of heap, so can't write to it
100 newElem->nextHigherInMem->nextLowerInMem = newElem;
101 }
102 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
103 }
104 else
105 {
106 sizeConsumed = sizeOfFound;
107 }
108 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
110 //skip over the prolog by adding its size to the pointer return
111 return (void *)((char *)foundElem + sizeof(MallocProlog));
112 }
115 /*This is sequential code -- only to be called from the Master
116 * When free, subtract the size of prolog from pointer, then cast it to a
117 * MallocProlog. Then check the nextLower and nextHigher chunks to see if
118 * one or both are also free, and coalesce if so, and if neither free, then
119 * add this one to free-list.
120 */
121 void
122 VMS__free( void *ptrToFree )
123 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
124 int32 lowerExistsAndIsFree, higherExistsAndIsFree, sizeOfElem;
126 if( ptrToFree < _VMSMasterEnv->freeListHead->nextLowerInMem ||
127 ptrToFree > _VMSMasterEnv->freeListHead->nextHigherInMem )
128 { //outside the range of data owned by VMS's malloc, so do nothing
129 return;
130 }
131 //subtract size of prolog to get pointer to prolog, then cast
132 elemToFree = (MallocProlog *)((char *)ptrToFree - sizeof(MallocProlog));
133 sizeOfElem =(int32)((char*)elemToFree->nextHigherInMem-(char*)elemToFree);
134 _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
136 nextLowerElem = elemToFree->nextLowerInMem;
137 nextHigherElem = elemToFree->nextHigherInMem;
139 if( nextHigherElem == NULL )
140 higherExistsAndIsFree = FALSE;
141 else //okay exists, now check if in the free-list by checking back ptr
142 higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
144 if( nextLowerElem == NULL )
145 lowerExistsAndIsFree = FALSE;
146 else //okay, it exists, now check if it's free
147 lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
150 //now, know what exists and what's free
151 if( lowerExistsAndIsFree )
152 { if( higherExistsAndIsFree )
153 { //both exist and are free, so coalesce all three
154 //First, remove higher from free-list
155 nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
156 nextHigherElem->nextChunkInFreeList;
157 if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
158 nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
159 nextHigherElem->prevChunkInFreeList;
160 //Now, fix-up sequence-in-mem list -- by side-effect, this also
161 // changes size of the lower elem, which is still in free-list
162 nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
163 if( nextHigherElem->nextHigherInMem !=
164 _VMSMasterEnv->freeListHead->nextHigherInMem )
165 nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
166 //notice didn't do anything to elemToFree -- it simply is no
167 // longer reachable from any of the lists. Wonder if could be a
168 // security leak because left valid addresses in it,
169 // but don't care for now.
170 }
171 else
172 { //lower is the only of the two that exists and is free,
173 //In this case, no adjustment to free-list, just change mem-list.
174 // By side-effect, changes size of the lower elem
175 nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
176 if( elemToFree->nextHigherInMem !=
177 _VMSMasterEnv->freeListHead->nextHigherInMem )
178 elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
179 }
180 }
181 else
182 { //lower either doesn't exist or isn't free, so check higher
183 if( higherExistsAndIsFree )
184 { //higher exists and is the only of the two free
185 //First, in free-list, replace higher elem with the one to free
186 elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
187 elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
188 elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
189 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
190 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
191 //Now chg mem-list. By side-effect, changes size of elemToFree
192 elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
193 if( elemToFree->nextHigherInMem !=
194 _VMSMasterEnv->freeListHead->nextHigherInMem )
195 elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
196 }
197 else
198 { //neither lower nor higher is availabe to coalesce so add to list
199 // this makes prev chunk ptr non-null, which indicates it's free
200 elemToFree->nextChunkInFreeList =
201 _VMSMasterEnv->freeListHead->nextChunkInFreeList;
202 _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
203 if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
204 elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
205 elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
206 }
207 }
209 }
212 /*Designed to be called from the main thread outside of VMS, during init
213 */
214 MallocProlog *
215 VMS__create_free_list()
216 { MallocProlog *freeListHead, *firstChunk;
218 //Note, this is running in the main thread -- all increases in malloc
219 // mem and all frees of it must be done in this thread, with the
220 // thread's original stack available
221 freeListHead = malloc( sizeof(MallocProlog) );
222 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
223 if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
225 freeListHead->prevChunkInFreeList = NULL;
226 //Use this addr to free the heap when cleanup
227 freeListHead->nextLowerInMem = firstChunk;
228 //to identify top-of-heap elem, compare this addr to elem's next higher
229 freeListHead->nextHigherInMem = (char *)firstChunk +
230 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
231 freeListHead->nextChunkInFreeList = firstChunk;
233 firstChunk->nextChunkInFreeList = NULL;
234 firstChunk->prevChunkInFreeList = freeListHead;
235 //next Higher has to be set to top of chunk, so can calc size in malloc
236 firstChunk->nextHigherInMem = (char *)firstChunk +
237 MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
238 firstChunk->nextLowerInMem = NULL; //identifies as bott of heap
240 return freeListHead;
241 }
244 /*Designed to be called from the main thread outside of VMS, during cleanup
245 */
246 void
247 VMS_ext__free_free_list( MallocProlog *freeListHead )
248 {
249 //stashed a ptr to the one and only bug chunk malloc'd from OS in the
250 // free list head's next lower in mem pointer
251 free( freeListHead->nextLowerInMem );
253 //don't free the head -- it'll be in an array eventually -- free whole
254 // array when all the free lists linked from it have already been freed
255 }
