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/interface/aligned_malloc.h"
18#include "webrtc/system_wrappers/interface/atomic32.h"
19#include "webrtc/typedefs.h"
20
21namespace webrtc {
22template<class MemoryType> struct MemoryPoolItem;
23
24template<class MemoryType>
25struct MemoryPoolItemPayload
26{
27    MemoryPoolItemPayload()
28        : memoryType(),
29          base(NULL)
30    {
31    }
32    MemoryType                  memoryType;
33    MemoryPoolItem<MemoryType>* base;
34};
35
36template<class MemoryType>
37struct 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
45template<class MemoryType>
46class MemoryPoolImpl
47{
48public:
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();
59private:
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
73template<class MemoryType>
74MemoryPoolImpl<MemoryType>::MemoryPoolImpl(
75    int32_t /*initialPoolSize*/)
76    : _pListHead(NULL),
77      _createdMemory(0),
78      _outstandingMemory(0)
79{
80}
81
82template<class MemoryType>
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
96template<class MemoryType>
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
114template<class MemoryType>
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
146template<class MemoryType>
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
159template<class MemoryType>
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
176template<class MemoryType>
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