086dbe90c8
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26914 a95241bf-73f2-0310-859d-f6bbb57e9c96
154 lines
4.3 KiB
C++
154 lines
4.3 KiB
C++
/*
|
|
* Copyright (c) 2004, Marcus Overhagen
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include <string.h>
|
|
|
|
#include <Locker.h>
|
|
|
|
#include "ChunkCache.h"
|
|
#include "debug.h"
|
|
|
|
|
|
ChunkCache::ChunkCache()
|
|
{
|
|
fLocker = new BLocker("media chunk cache locker");
|
|
|
|
// fEmptyChunkCount must be one less than the real chunk count,
|
|
// because the buffer returned by GetNextChunk must be preserved
|
|
// until the next call of that function, and must not be overwritten.
|
|
fEmptyChunkCount = CHUNK_COUNT - 1;
|
|
fReadyChunkCount = 0;
|
|
fNeedsRefill = 1;
|
|
|
|
fGetWaitSem = create_sem(0, "media chunk cache sem");
|
|
|
|
fNextPut = &fChunkInfos[0];
|
|
fNextGet = &fChunkInfos[0];
|
|
|
|
for (int i = 0; i < CHUNK_COUNT; i++) {
|
|
fChunkInfos[i].next = (i == CHUNK_COUNT -1) ? &fChunkInfos[0] : &fChunkInfos[i + 1];
|
|
fChunkInfos[i].buffer = NULL;
|
|
fChunkInfos[i].sizeUsed = 0;
|
|
fChunkInfos[i].sizeMax = 0;
|
|
fChunkInfos[i].err = B_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
ChunkCache::~ChunkCache()
|
|
{
|
|
delete_sem(fGetWaitSem);
|
|
delete fLocker;
|
|
for (int i = 0; i < CHUNK_COUNT; i++) {
|
|
free(fChunkInfos[i].buffer);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ChunkCache::MakeEmpty()
|
|
{
|
|
fLocker->Lock();
|
|
fEmptyChunkCount = CHUNK_COUNT - 1;
|
|
fReadyChunkCount = 0;
|
|
fNextPut = &fChunkInfos[0];
|
|
fNextGet = &fChunkInfos[0];
|
|
atomic_or(&fNeedsRefill, 1);
|
|
fLocker->Unlock();
|
|
}
|
|
|
|
|
|
bool
|
|
ChunkCache::NeedsRefill()
|
|
{
|
|
return atomic_or(&fNeedsRefill, 0);
|
|
}
|
|
|
|
|
|
status_t
|
|
ChunkCache::GetNextChunk(const void **chunkBuffer, size_t *chunkSize, media_header *mediaHeader)
|
|
{
|
|
uint8 retry_count = 0;
|
|
|
|
// printf("ChunkCache::GetNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextGet, fEmptyChunkCount, fReadyChunkCount);
|
|
retry:
|
|
acquire_sem(fGetWaitSem);
|
|
|
|
fLocker->Lock();
|
|
if (fReadyChunkCount == 0) {
|
|
fLocker->Unlock();
|
|
printf("ChunkCache::GetNextChunk: %p retrying\n", fNextGet);
|
|
// Limit to 5 retries
|
|
retry_count++;
|
|
if (retry_count > 4) {
|
|
return B_ERROR;
|
|
}
|
|
goto retry;
|
|
}
|
|
fEmptyChunkCount++;
|
|
fReadyChunkCount--;
|
|
atomic_or(&fNeedsRefill, 1);
|
|
fLocker->Unlock();
|
|
|
|
*chunkBuffer = fNextGet->buffer;
|
|
*chunkSize = fNextGet->sizeUsed;
|
|
*mediaHeader = fNextGet->mediaHeader;
|
|
status_t err = fNextGet->err;
|
|
fNextGet = fNextGet->next;
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
void
|
|
ChunkCache::PutNextChunk(const void *chunkBuffer, size_t chunkSize, const media_header &mediaHeader, status_t err)
|
|
{
|
|
// printf("ChunkCache::PutNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextPut, fEmptyChunkCount, fReadyChunkCount);
|
|
|
|
if (err == B_OK) {
|
|
if (fNextPut->sizeMax < chunkSize) {
|
|
// printf("ChunkCache::PutNextChunk: %p resizing from %ld to %ld\n", fNextPut, fNextPut->sizeMax, chunkSize);
|
|
free(fNextPut->buffer);
|
|
fNextPut->buffer = malloc((chunkSize + 1024) & ~1023);
|
|
fNextPut->sizeMax = chunkSize;
|
|
}
|
|
memcpy(fNextPut->buffer, chunkBuffer, chunkSize);
|
|
fNextPut->sizeUsed = chunkSize;
|
|
}
|
|
|
|
fNextPut->mediaHeader = mediaHeader;
|
|
fNextPut->err = err;
|
|
|
|
fNextPut = fNextPut->next;
|
|
|
|
fLocker->Lock();
|
|
fEmptyChunkCount--;
|
|
fReadyChunkCount++;
|
|
if (fEmptyChunkCount == 0)
|
|
atomic_and(&fNeedsRefill, 0);
|
|
fLocker->Unlock();
|
|
|
|
release_sem(fGetWaitSem);
|
|
}
|