1/*
2 *  Copyright (c) 2011 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_GENERIC_H_
12#define WEBRTC_MODULES_AUDIO_CONFERENCE_MIXER_SOURCE_MEMORY_POOL_GENERIC_H_
13
14#include <assert.h>
15#include <list>
16
17#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
18#include "webrtc/typedefs.h"
19
20namespace webrtc {
21template<class MemoryType>
22class MemoryPoolImpl
23{
24public:
25    // MemoryPool functions.
26    int32_t PopMemory(MemoryType*&  memory);
27    int32_t PushMemory(MemoryType*& memory);
28
29    MemoryPoolImpl(int32_t initialPoolSize);
30    ~MemoryPoolImpl();
31
32    // Atomic functions
33    int32_t Terminate();
34    bool Initialize();
35private:
36    // Non-atomic function.
37    int32_t CreateMemory(uint32_t amountToCreate);
38
39    CriticalSectionWrapper* _crit;
40
41    bool _terminate;
42
43    std::list<MemoryType*> _memoryPool;
44
45    uint32_t _initialPoolSize;
46    uint32_t _createdMemory;
47    uint32_t _outstandingMemory;
48};
49
50template<class MemoryType>
51MemoryPoolImpl<MemoryType>::MemoryPoolImpl(int32_t initialPoolSize)
52    : _crit(CriticalSectionWrapper::CreateCriticalSection()),
53      _terminate(false),
54      _initialPoolSize(initialPoolSize),
55      _createdMemory(0),
56      _outstandingMemory(0)
57{
58}
59
60template<class MemoryType>
61MemoryPoolImpl<MemoryType>::~MemoryPoolImpl()
62{
63    // Trigger assert if there is outstanding memory.
64    assert(_createdMemory == 0);
65    assert(_outstandingMemory == 0);
66    delete _crit;
67}
68
69template<class MemoryType>
70int32_t MemoryPoolImpl<MemoryType>::PopMemory(MemoryType*& memory)
71{
72    CriticalSectionScoped cs(_crit);
73    if(_terminate)
74    {
75        memory = NULL;
76        return -1;
77    }
78    if (_memoryPool.empty()) {
79        // _memoryPool empty create new memory.
80        CreateMemory(_initialPoolSize);
81        if(_memoryPool.empty())
82        {
83            memory = NULL;
84            return -1;
85        }
86    }
87    memory = _memoryPool.front();
88    _memoryPool.pop_front();
89    _outstandingMemory++;
90    return 0;
91}
92
93template<class MemoryType>
94int32_t MemoryPoolImpl<MemoryType>::PushMemory(MemoryType*& memory)
95{
96    if(memory == NULL)
97    {
98        return -1;
99    }
100    CriticalSectionScoped cs(_crit);
101    _outstandingMemory--;
102    if(_memoryPool.size() > (_initialPoolSize << 1))
103    {
104        // Reclaim memory if less than half of the pool is unused.
105        _createdMemory--;
106        delete memory;
107        memory = NULL;
108        return 0;
109    }
110    _memoryPool.push_back(memory);
111    memory = NULL;
112    return 0;
113}
114
115template<class MemoryType>
116bool MemoryPoolImpl<MemoryType>::Initialize()
117{
118    CriticalSectionScoped cs(_crit);
119    return CreateMemory(_initialPoolSize) == 0;
120}
121
122template<class MemoryType>
123int32_t MemoryPoolImpl<MemoryType>::Terminate()
124{
125    CriticalSectionScoped cs(_crit);
126    assert(_createdMemory == _outstandingMemory + _memoryPool.size());
127
128    _terminate = true;
129    // Reclaim all memory.
130    while(_createdMemory > 0)
131    {
132        MemoryType* memory = _memoryPool.front();
133        _memoryPool.pop_front();
134        delete memory;
135        _createdMemory--;
136    }
137    return 0;
138}
139
140template<class MemoryType>
141int32_t MemoryPoolImpl<MemoryType>::CreateMemory(
142    uint32_t amountToCreate)
143{
144    for(uint32_t i = 0; i < amountToCreate; i++)
145    {
146        MemoryType* memory = new MemoryType();
147        if(memory == NULL)
148        {
149            return -1;
150        }
151        _memoryPool.push_back(memory);
152        _createdMemory++;
153    }
154    return 0;
155}
156}  // namespace webrtc
157
158#endif // WEBRTC_MODULES_AUDIO_CONFERENCE_MIXER_SOURCE_MEMORY_POOL_GENERIC_H_
159