1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include <package/hpkg/BlockBufferPoolImpl.h>
9
10 #include <algorithm>
11 #include <new>
12
13 #include <AutoLocker.h>
14
15 #include <package/hpkg/PoolBuffer.h>
16
17
18 namespace BPackageKit {
19
20 namespace BHPKG {
21
22 namespace BPrivate {
23
24
25 // #pragma mark - BlockBufferPoolImpl
26
27
BlockBufferPoolImpl(size_t blockSize,uint32 maxCachedBlocks,BBufferPoolLockable * lockable)28 BlockBufferPoolImpl::BlockBufferPoolImpl(size_t blockSize,
29 uint32 maxCachedBlocks, BBufferPoolLockable* lockable)
30 :
31 fBlockSize(blockSize),
32 fMaxCachedBlocks(maxCachedBlocks),
33 fAllocatedBlocks(0),
34 fLockable(lockable)
35 {
36 }
37
38
~BlockBufferPoolImpl()39 BlockBufferPoolImpl::~BlockBufferPoolImpl()
40 {
41 // delete all cached blocks
42 while (PoolBuffer* block = fCachedBuffers.RemoveHead())
43 delete block;
44
45 while (PoolBuffer* block = fUnusedBuffers.RemoveHead())
46 delete block;
47 }
48
49
50 status_t
Init()51 BlockBufferPoolImpl::Init()
52 {
53 return B_OK;
54 }
55
56
57 PoolBuffer*
GetBuffer(size_t size,PoolBuffer ** owner,bool * _newBuffer)58 BlockBufferPoolImpl::GetBuffer(size_t size, PoolBuffer** owner, bool* _newBuffer)
59 {
60 // for sizes greater than the block size, we always allocate a new buffer
61 if (size > fBlockSize)
62 return _AllocateBuffer(size, owner, _newBuffer);
63
64 AutoLocker<BBufferPoolLockable> locker(fLockable);
65
66 // if an owner is given and the buffer is still cached, return it
67 if (owner != NULL && *owner != NULL) {
68 PoolBuffer* buffer = *owner;
69 fCachedBuffers.Remove(buffer);
70
71 if (_newBuffer != NULL)
72 *_newBuffer = false;
73 return buffer;
74 }
75
76 // we need a new buffer -- try unused ones first
77 PoolBuffer* buffer = fUnusedBuffers.RemoveHead();
78 if (buffer != NULL) {
79 buffer->SetOwner(owner);
80
81 if (owner != NULL)
82 *owner = buffer;
83 if (_newBuffer != NULL)
84 *_newBuffer = true;
85 return buffer;
86 }
87
88 // if we have already hit the max block limit, steal a cached block
89 if (fAllocatedBlocks >= fMaxCachedBlocks) {
90 buffer = fCachedBuffers.RemoveHead();
91 if (buffer != NULL) {
92 buffer->SetCached(false);
93 *buffer->Owner() = NULL;
94 buffer->SetOwner(owner);
95
96 if (owner != NULL)
97 *owner = buffer;
98 if (_newBuffer != NULL)
99 *_newBuffer = true;
100 return buffer;
101 }
102 }
103
104 // allocate a new buffer
105 locker.Unlock();
106 return _AllocateBuffer(size, owner, _newBuffer);
107 }
108
109
110 void
PutBufferAndCache(PoolBuffer ** owner)111 BlockBufferPoolImpl::PutBufferAndCache(PoolBuffer** owner)
112 {
113 PoolBuffer* buffer = *owner;
114
115 // always delete buffers with non-standard size
116 if (buffer->Size() != fBlockSize) {
117 *owner = NULL;
118 delete buffer;
119 return;
120 }
121
122 AutoLocker<BBufferPoolLockable> locker(fLockable);
123
124 // queue the cached buffer
125 buffer->SetOwner(owner);
126 fCachedBuffers.Add(buffer);
127 buffer->SetCached(true);
128
129 if (fAllocatedBlocks > fMaxCachedBlocks) {
130 // We have exceeded the limit -- we need to free a buffer.
131 PoolBuffer* otherBuffer = fUnusedBuffers.RemoveHead();
132 if (otherBuffer == NULL) {
133 otherBuffer = fCachedBuffers.RemoveHead();
134 *otherBuffer->Owner() = NULL;
135 otherBuffer->SetCached(false);
136 }
137
138 delete otherBuffer;
139 }
140 }
141
142
143 void
PutBuffer(PoolBuffer ** owner)144 BlockBufferPoolImpl::PutBuffer(PoolBuffer** owner)
145 {
146 AutoLocker<BBufferPoolLockable> locker(fLockable);
147
148 PoolBuffer* buffer = *owner;
149
150 if (buffer == NULL)
151 return;
152
153 if (buffer->IsCached()) {
154 fCachedBuffers.Remove(buffer);
155 buffer->SetCached(false);
156 }
157
158 buffer->SetOwner(NULL);
159 *owner = NULL;
160
161 if (buffer->Size() == fBlockSize && fAllocatedBlocks < fMaxCachedBlocks)
162 fUnusedBuffers.Add(buffer);
163 else
164 delete buffer;
165 }
166
167
168 PoolBuffer*
_AllocateBuffer(size_t size,PoolBuffer ** owner,bool * _newBuffer)169 BlockBufferPoolImpl::_AllocateBuffer(size_t size, PoolBuffer** owner,
170 bool* _newBuffer)
171 {
172 PoolBuffer* buffer = new(std::nothrow) PoolBuffer(
173 std::max(size, fBlockSize));
174 if (buffer == NULL || buffer->Buffer() == NULL) {
175 delete buffer;
176 return NULL;
177 }
178
179 buffer->SetOwner(owner);
180
181 if (_newBuffer != NULL)
182 *_newBuffer = true;
183
184 AutoLocker<BBufferPoolLockable> locker(fLockable);
185 fAllocatedBlocks++;
186
187 if (owner != NULL)
188 *owner = buffer;
189
190 return buffer;
191 }
192
193
194 } // namespace BPrivate
195
196 } // namespace BHPKG
197
198 } // namespace BPackageKit
199