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