xref: /haiku/src/kits/media/ChunkCache.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2  * Copyright (c) 2004, Marcus Overhagen
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23  * OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include <string.h>
26 
27 #include <Locker.h>
28 
29 #include "ChunkCache.h"
30 #include "debug.h"
31 
32 
33 ChunkCache::ChunkCache()
34 {
35 	fLocker = new BLocker("media chunk cache locker");
36 
37 	// fEmptyChunkCount must be one less than the real chunk count,
38 	// because the buffer returned by GetNextChunk must be preserved
39 	// until the next call of that function, and must not be overwritten.
40 	fEmptyChunkCount = CHUNK_COUNT - 1;
41 	fReadyChunkCount = 0;
42 	fNeedsRefill = 1;
43 
44 	fGetWaitSem = create_sem(0, "media chunk cache sem");
45 
46 	fNextPut = &fChunkInfos[0];
47 	fNextGet = &fChunkInfos[0];
48 
49 	for (int i = 0; i < CHUNK_COUNT; i++) {
50 		fChunkInfos[i].next = (i == CHUNK_COUNT -1) ? &fChunkInfos[0] : &fChunkInfos[i + 1];
51 		fChunkInfos[i].buffer = NULL;
52 		fChunkInfos[i].sizeUsed = 0;
53 		fChunkInfos[i].sizeMax = 0;
54 		fChunkInfos[i].err = B_ERROR;
55 	}
56 }
57 
58 
59 ChunkCache::~ChunkCache()
60 {
61 	delete_sem(fGetWaitSem);
62 	delete fLocker;
63 	for (int i = 0; i < CHUNK_COUNT; i++) {
64 		free(fChunkInfos[i].buffer);
65 	}
66 }
67 
68 
69 void
70 ChunkCache::MakeEmpty()
71 {
72 	fLocker->Lock();
73 	fEmptyChunkCount = CHUNK_COUNT - 1;
74 	fReadyChunkCount = 0;
75 	fNextPut = &fChunkInfos[0];
76 	fNextGet = &fChunkInfos[0];
77 	atomic_or(&fNeedsRefill, 1);
78 	fLocker->Unlock();
79 }
80 
81 
82 bool
83 ChunkCache::NeedsRefill()
84 {
85 	return atomic_or(&fNeedsRefill, 0);
86 }
87 
88 
89 status_t
90 ChunkCache::GetNextChunk(const void **chunkBuffer, size_t *chunkSize, media_header *mediaHeader)
91 {
92 //	printf("ChunkCache::GetNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextGet, fEmptyChunkCount, fReadyChunkCount);
93 retry:
94 	acquire_sem(fGetWaitSem);
95 
96 	fLocker->Lock();
97 	if (fReadyChunkCount == 0) {
98 		fLocker->Unlock();
99 		printf("ChunkCache::GetNextChunk: %p retrying\n", fNextGet);
100 		goto retry;
101 	}
102 	fEmptyChunkCount++;
103 	fReadyChunkCount--;
104 	atomic_or(&fNeedsRefill, 1);
105 	fLocker->Unlock();
106 
107 	*chunkBuffer = fNextGet->buffer;
108 	*chunkSize = fNextGet->sizeUsed;
109 	*mediaHeader = fNextGet->mediaHeader;
110 	status_t err = fNextGet->err;
111 	fNextGet = fNextGet->next;
112 
113 	return err;
114 }
115 
116 
117 void
118 ChunkCache::PutNextChunk(const void *chunkBuffer, size_t chunkSize, const media_header &mediaHeader, status_t err)
119 {
120 //	printf("ChunkCache::PutNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextPut, fEmptyChunkCount, fReadyChunkCount);
121 
122 	if (err == B_OK) {
123 		if (fNextPut->sizeMax < chunkSize) {
124 //			printf("ChunkCache::PutNextChunk: %p resizing from %ld to %ld\n", fNextPut, fNextPut->sizeMax, chunkSize);
125 			free(fNextPut->buffer);
126 			fNextPut->buffer = malloc((chunkSize + 1024) & ~1023);
127 			fNextPut->sizeMax = chunkSize;
128 		}
129 		memcpy(fNextPut->buffer, chunkBuffer, chunkSize);
130 		fNextPut->sizeUsed = chunkSize;
131 	}
132 
133 	fNextPut->mediaHeader = mediaHeader;
134 	fNextPut->err = err;
135 
136 	fNextPut = fNextPut->next;
137 
138 	fLocker->Lock();
139 	fEmptyChunkCount--;
140 	fReadyChunkCount++;
141 	if (fEmptyChunkCount == 0)
142 		atomic_and(&fNeedsRefill, 0);
143 	fLocker->Unlock();
144 
145 	release_sem(fGetWaitSem);
146 }
147