29 #include <QDebug> |
29 #include <QDebug> |
30 #include <QSharedMemory> |
30 #include <QSharedMemory> |
31 |
31 |
32 // this identifier is used to check, if the multisegment allocator is already |
32 // this identifier is used to check, if the multisegment allocator is already |
33 // initialized in given shared chunk |
33 // initialized in given shared chunk |
34 static const unsigned int INITIALIZED_MULTISEGMENTALLOCATOR_IDENTIFIER = 0x4D554C54; //'MULT' |
34 static const quint32 INITIALIZED_MULTISEGMENTALLOCATOR_IDENTIFIER = 0x4D554C54; //'MULT' |
35 |
35 |
36 // chunk sizes |
36 // chunk sizes |
37 // every size is aligned to 8 |
37 // every size is aligned to 8 |
38 static const int ChunkSizes[AMOUNT_OF_DIFFERENT_CHUNK_SIZES] = {8, 16, 24, 32, 48, 64, 120, 224}; |
38 static const int ChunkSizes[AMOUNT_OF_DIFFERENT_CHUNK_SIZES] = {8, 16, 24, 32, 48, 64, 120, 224}; |
39 |
39 |
92 |
92 |
93 // every chunk list have space for 512 chunks |
93 // every chunk list have space for 512 chunks |
94 ChunkListHeader *listHeader; |
94 ChunkListHeader *listHeader; |
95 for (int i = 0; i < AMOUNT_OF_DIFFERENT_CHUNK_SIZES; i++) { |
95 for (int i = 0; i < AMOUNT_OF_DIFFERENT_CHUNK_SIZES; i++) { |
96 header->offsetsToChunkLists[i] = mainAllocator->alloc(sizeof(ChunkListHeader) |
96 header->offsetsToChunkLists[i] = mainAllocator->alloc(sizeof(ChunkListHeader) |
97 + (sizeof(int) + ChunkSizes[i]) |
97 + (sizeof(qptrdiff) + ChunkSizes[i]) |
98 * CHUNKS_IN_ONE_LIST); |
98 * CHUNKS_IN_ONE_LIST); |
99 header->offsetsToFreeChunkLists[i] = header->offsetsToChunkLists[i]; |
99 header->offsetsToFreeChunkLists[i] = header->offsetsToChunkLists[i]; |
100 listHeader = address<ChunkListHeader>(header->offsetsToChunkLists[i]); |
100 listHeader = address<ChunkListHeader>(header->offsetsToChunkLists[i]); |
101 listHeader->chunkListIndex = i; |
101 listHeader->chunkListIndex = i; |
102 listHeader->freedChunkCursor = -1; |
102 listHeader->freedChunkCursor = -1; |
136 // size should already be between 1...max. chunk size - no need to check |
136 // size should already be between 1...max. chunk size - no need to check |
137 |
137 |
138 // first find out correct list of chunks |
138 // first find out correct list of chunks |
139 int i = indexTable[size]; |
139 int i = indexTable[size]; |
140 qptrdiff dataOffset = -1; |
140 qptrdiff dataOffset = -1; |
141 int *metaData = 0; |
141 qptrdiff *metaData = 0; |
142 // this should always point to list with free chunks |
142 // this should always point to list with free chunks |
143 ChunkListHeader *listHeader = address<ChunkListHeader>(header->offsetsToFreeChunkLists[i]); |
143 ChunkListHeader *listHeader = address<ChunkListHeader>(header->offsetsToFreeChunkLists[i]); |
144 |
144 |
145 if (listHeader->freedChunkCursor >= 0) { // freedChunkCursor points to freed chunk |
145 if (listHeader->freedChunkCursor >= 0) { // freedChunkCursor points to freed chunk |
146 dataOffset = listHeader->freedChunkCursor + sizeof(int); |
146 dataOffset = listHeader->freedChunkCursor + sizeof(qptrdiff); |
147 metaData = address<int>(listHeader->freedChunkCursor); |
147 metaData = address<qptrdiff>(listHeader->freedChunkCursor); |
148 listHeader->freedChunkCursor = *metaData; // point to next freed chunk |
148 listHeader->freedChunkCursor = *metaData; // points to next freed chunk |
149 } else { // no chunks freed -> allocate in order |
149 } else { // no chunks freed -> allocate in order |
150 dataOffset = listHeader->allocCursor + sizeof(int); |
150 dataOffset = listHeader->allocCursor + sizeof(qptrdiff); |
151 metaData = address<int>(listHeader->allocCursor); |
151 metaData = address<qptrdiff>(listHeader->allocCursor); |
152 // we will never allocate from full list, so allocCursor is always valid |
152 // we will never allocate from full list, so allocCursor is always valid |
153 listHeader->allocCursor += ChunkSizes[listHeader->chunkListIndex] + sizeof(int); |
153 listHeader->allocCursor += ChunkSizes[listHeader->chunkListIndex] + sizeof(qptrdiff); |
154 } |
154 } |
155 |
155 |
156 // for allocated chunks metadata is: |
156 // for allocated chunks metadata is the offset to this list's header |
157 // 00xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx, |
157 // for freed chunks, metadata points to next free chunk (or -1 if no more freed chunks) |
158 // where xx... = offset to this list's header (max. 1 GB) |
158 *metaData = header->offsetsToFreeChunkLists[i]; |
159 *metaData = header->offsetsToFreeChunkLists[i] /* & 0x3FFFFFFF */; |
|
160 listHeader->allocatedChunks++; |
159 listHeader->allocatedChunks++; |
161 if (listHeader->allocatedChunks == CHUNKS_IN_ONE_LIST) { // list full |
160 if (listHeader->allocatedChunks == CHUNKS_IN_ONE_LIST) { // list full |
162 if (!setFreeList(listHeader->chunkListIndex)) { |
161 if (!setFreeList(listHeader->chunkListIndex)) { |
163 // there is no list(s) with free chunks, so add new list |
162 // there is no list(s) with free chunks, so add new list |
164 addList(listHeader->chunkListIndex, |
163 addList(listHeader->chunkListIndex, |
165 mainAllocator->alloc((sizeof(ChunkListHeader) + sizeof(int) |
164 mainAllocator->alloc(sizeof(ChunkListHeader) + (sizeof(qptrdiff) |
166 + ChunkSizes[listHeader->chunkListIndex]) |
165 + ChunkSizes[listHeader->chunkListIndex]) |
167 * CHUNKS_IN_ONE_LIST)); |
166 * CHUNKS_IN_ONE_LIST)); |
168 } |
167 } |
169 } |
168 } |
170 |
169 |
175 * free the offset |
174 * free the offset |
176 */ |
175 */ |
177 void HbMultiSegmentAllocator::free(qptrdiff offset) |
176 void HbMultiSegmentAllocator::free(qptrdiff offset) |
178 { |
177 { |
179 // metadata has offset to list's header |
178 // metadata has offset to list's header |
180 int *metaData = address<int>(offset - sizeof(int)); |
179 qptrdiff *metaData = address<qptrdiff>(offset - sizeof(qptrdiff)); |
181 int listHeaderOffset = *metaData; |
180 qptrdiff listHeaderOffset = *metaData; |
182 ChunkListHeader *listHeader = address<ChunkListHeader>(listHeaderOffset); |
181 ChunkListHeader *listHeader = address<ChunkListHeader>(listHeaderOffset); |
183 listHeader->allocatedChunks--; |
182 listHeader->allocatedChunks--; |
184 if (listHeader->allocatedChunks == 0) { |
183 if (listHeader->allocatedChunks == 0) { |
185 // if there are multiple lists, this list could be released |
184 // if there are multiple lists, this list could be released |
186 ChunkListHeader *previous = 0; |
185 ChunkListHeader *previous = 0; |
211 addList(listHeader->chunkListIndex, listHeaderOffset); |
210 addList(listHeader->chunkListIndex, listHeaderOffset); |
212 } |
211 } |
213 } else { |
212 } else { |
214 // only list can't be freed |
213 // only list can't be freed |
215 *metaData = listHeader->freedChunkCursor; |
214 *metaData = listHeader->freedChunkCursor; |
216 listHeader->freedChunkCursor = offset - sizeof(int); |
215 listHeader->freedChunkCursor = offset - sizeof(qptrdiff); |
217 } |
216 } |
218 } else { |
217 } else { |
219 // this list is not yet empty |
218 // this list is not yet empty |
220 *metaData = listHeader->freedChunkCursor; |
219 *metaData = listHeader->freedChunkCursor; |
221 listHeader->freedChunkCursor = offset - sizeof(int); |
220 listHeader->freedChunkCursor = offset - sizeof(qptrdiff); |
222 } |
221 } |
223 } |
222 } |
224 |
223 |
225 /** |
224 /** |
226 * HbMultiSegmentAllocator::allocatedSize |
225 * HbMultiSegmentAllocator::allocatedSize |
228 * Used for reallocation. |
227 * Used for reallocation. |
229 * Returns actual allocated size for given offset. |
228 * Returns actual allocated size for given offset. |
230 */ |
229 */ |
231 int HbMultiSegmentAllocator::allocatedSize(qptrdiff offset) |
230 int HbMultiSegmentAllocator::allocatedSize(qptrdiff offset) |
232 { |
231 { |
233 int *metaData = address<int>(offset - sizeof(int)); |
232 qptrdiff *metaData = address<qptrdiff>(offset - sizeof(qptrdiff)); |
234 ChunkListHeader *listHeader = address<ChunkListHeader>(*metaData); |
233 ChunkListHeader *listHeader = address<ChunkListHeader>(*metaData); |
235 // not actual size in alloc(), but the size of chunk, where this data is stored |
234 // not actual size in alloc(), but the size of chunk, where this data is stored |
236 return ChunkSizes[listHeader->chunkListIndex]; |
235 return ChunkSizes[listHeader->chunkListIndex]; |
237 } |
236 } |
238 |
237 |
262 * return false. Otherwise sets free list and returns true. |
261 * return false. Otherwise sets free list and returns true. |
263 */ |
262 */ |
264 bool HbMultiSegmentAllocator::setFreeList(int index) |
263 bool HbMultiSegmentAllocator::setFreeList(int index) |
265 { |
264 { |
266 ChunkListHeader *listHeader; |
265 ChunkListHeader *listHeader; |
267 listHeader = address<ChunkListHeader>(header->offsetsToChunkLists[index]); |
266 qptrdiff offset = header->offsetsToChunkLists[index]; |
|
267 listHeader = address<ChunkListHeader>(offset); |
268 bool retVal = false; |
268 bool retVal = false; |
269 for (;;) { |
269 for (;;) { |
270 if (listHeader->allocatedChunks < CHUNKS_IN_ONE_LIST) { |
270 if (listHeader->allocatedChunks < CHUNKS_IN_ONE_LIST) { |
271 qptrdiff offset = static_cast<int>(reinterpret_cast<char*>(listHeader) |
|
272 - reinterpret_cast<char*>(chunk->data())); |
|
273 header->offsetsToFreeChunkLists[index] = offset; |
271 header->offsetsToFreeChunkLists[index] = offset; |
274 retVal = true; |
272 retVal = true; |
275 break; |
273 break; |
276 } |
274 } |
277 if (listHeader->nextListOffset == -1) { |
275 if (listHeader->nextListOffset == -1) { |
278 break; |
276 break; |
279 } |
277 } |
280 listHeader = address<ChunkListHeader>(listHeader->nextListOffset); |
278 offset = listHeader->nextListOffset; |
|
279 listHeader = address<ChunkListHeader>(offset); |
281 } |
280 } |
282 return retVal; |
281 return retVal; |
283 } |
282 } |
284 |
283 |
285 #ifdef HB_THEME_SERVER_MEMORY_REPORT |
284 #ifdef HB_THEME_SERVER_MEMORY_REPORT |