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 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 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 51 BlockBufferPoolImpl::Init() 52 { 53 return B_OK; 54 } 55 56 57 PoolBuffer* 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 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 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* 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