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