1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_MODULES_AUDIO_CONFERENCE_MIXER_SOURCE_MEMORY_POOL_WINDOWS_H_ 12 #define WEBRTC_MODULES_AUDIO_CONFERENCE_MIXER_SOURCE_MEMORY_POOL_WINDOWS_H_ 13 14 #include <assert.h> 15 #include <windows.h> 16 17 #include "webrtc/system_wrappers/include/aligned_malloc.h" 18 #include "webrtc/system_wrappers/include/atomic32.h" 19 #include "webrtc/typedefs.h" 20 21 namespace webrtc { 22 template<class MemoryType> struct MemoryPoolItem; 23 24 template<class MemoryType> 25 struct MemoryPoolItemPayload 26 { MemoryPoolItemPayloadMemoryPoolItemPayload27 MemoryPoolItemPayload() 28 : memoryType(), 29 base(NULL) 30 { 31 } 32 MemoryType memoryType; 33 MemoryPoolItem<MemoryType>* base; 34 }; 35 36 template<class MemoryType> 37 struct MemoryPoolItem 38 { 39 // Atomic single linked list entry header. 40 SLIST_ENTRY itemEntry; 41 // Atomic single linked list payload. 42 MemoryPoolItemPayload<MemoryType>* payload; 43 }; 44 45 template<class MemoryType> 46 class MemoryPoolImpl 47 { 48 public: 49 // MemoryPool functions. 50 int32_t PopMemory(MemoryType*& memory); 51 int32_t PushMemory(MemoryType*& memory); 52 53 MemoryPoolImpl(int32_t /*initialPoolSize*/); 54 ~MemoryPoolImpl(); 55 56 // Atomic functions. 57 int32_t Terminate(); 58 bool Initialize(); 59 private: 60 // Non-atomic function. 61 MemoryPoolItem<MemoryType>* CreateMemory(); 62 63 // Windows implementation of single linked atomic list, documented here: 64 // http://msdn.microsoft.com/en-us/library/ms686962(VS.85).aspx 65 66 // Atomic single linked list head. 67 PSLIST_HEADER _pListHead; 68 69 Atomic32 _createdMemory; 70 Atomic32 _outstandingMemory; 71 }; 72 73 template<class MemoryType> MemoryPoolImpl(int32_t)74MemoryPoolImpl<MemoryType>::MemoryPoolImpl( 75 int32_t /*initialPoolSize*/) 76 : _pListHead(NULL), 77 _createdMemory(0), 78 _outstandingMemory(0) 79 { 80 } 81 82 template<class MemoryType> ~MemoryPoolImpl()83MemoryPoolImpl<MemoryType>::~MemoryPoolImpl() 84 { 85 Terminate(); 86 if(_pListHead != NULL) 87 { 88 AlignedFree(reinterpret_cast<void*>(_pListHead)); 89 _pListHead = NULL; 90 } 91 // Trigger assert if there is outstanding memory. 92 assert(_createdMemory.Value() == 0); 93 assert(_outstandingMemory.Value() == 0); 94 } 95 96 template<class MemoryType> PopMemory(MemoryType * & memory)97int32_t MemoryPoolImpl<MemoryType>::PopMemory(MemoryType*& memory) 98 { 99 PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead); 100 if(pListEntry == NULL) 101 { 102 MemoryPoolItem<MemoryType>* item = CreateMemory(); 103 if(item == NULL) 104 { 105 return -1; 106 } 107 pListEntry = &(item->itemEntry); 108 } 109 ++_outstandingMemory; 110 memory = &((MemoryPoolItem<MemoryType>*)pListEntry)->payload->memoryType; 111 return 0; 112 } 113 114 template<class MemoryType> PushMemory(MemoryType * & memory)115int32_t MemoryPoolImpl<MemoryType>::PushMemory(MemoryType*& memory) 116 { 117 if(memory == NULL) 118 { 119 return -1; 120 } 121 122 MemoryPoolItem<MemoryType>* item = 123 ((MemoryPoolItemPayload<MemoryType>*)memory)->base; 124 125 const int32_t usedItems = --_outstandingMemory; 126 const int32_t totalItems = _createdMemory.Value(); 127 const int32_t freeItems = totalItems - usedItems; 128 if(freeItems < 0) 129 { 130 assert(false); 131 delete item->payload; 132 AlignedFree(item); 133 return -1; 134 } 135 if(freeItems >= totalItems>>1) 136 { 137 delete item->payload; 138 AlignedFree(item); 139 --_createdMemory; 140 return 0; 141 } 142 InterlockedPushEntrySList(_pListHead,&(item->itemEntry)); 143 return 0; 144 } 145 146 template<class MemoryType> Initialize()147bool MemoryPoolImpl<MemoryType>::Initialize() 148 { 149 _pListHead = (PSLIST_HEADER)AlignedMalloc(sizeof(SLIST_HEADER), 150 MEMORY_ALLOCATION_ALIGNMENT); 151 if(_pListHead == NULL) 152 { 153 return false; 154 } 155 InitializeSListHead(_pListHead); 156 return true; 157 } 158 159 template<class MemoryType> Terminate()160int32_t MemoryPoolImpl<MemoryType>::Terminate() 161 { 162 int32_t itemsFreed = 0; 163 PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead); 164 while(pListEntry != NULL) 165 { 166 MemoryPoolItem<MemoryType>* item = ((MemoryPoolItem<MemoryType>*)pListEntry); 167 delete item->payload; 168 AlignedFree(item); 169 --_createdMemory; 170 itemsFreed++; 171 pListEntry = InterlockedPopEntrySList(_pListHead); 172 } 173 return itemsFreed; 174 } 175 176 template<class MemoryType> CreateMemory()177MemoryPoolItem<MemoryType>* MemoryPoolImpl<MemoryType>::CreateMemory() 178 { 179 MemoryPoolItem<MemoryType>* returnValue = (MemoryPoolItem<MemoryType>*) 180 AlignedMalloc(sizeof(MemoryPoolItem<MemoryType>), 181 MEMORY_ALLOCATION_ALIGNMENT); 182 if(returnValue == NULL) 183 { 184 return NULL; 185 } 186 187 returnValue->payload = new MemoryPoolItemPayload<MemoryType>(); 188 if(returnValue->payload == NULL) 189 { 190 delete returnValue; 191 return NULL; 192 } 193 returnValue->payload->base = returnValue; 194 ++_createdMemory; 195 return returnValue; 196 } 197 } // namespace webrtc 198 199 #endif // WEBRTC_MODULES_AUDIO_CONFERENCE_MIXER_SOURCE_MEMORY_POOL_WINDOWS_H_ 200