This commit is contained in:
2026-03-29 14:01:52 +03:00
commit 0611279128
210 changed files with 60454 additions and 0 deletions

209
buffer.c Normal file
View File

@@ -0,0 +1,209 @@
/*
* Copyright 2008-2013 Various Authors
* Copyright 2004 Timo Hirvonen
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "buffer.h"
#include "xmalloc.h"
#include "locking.h"
#include "debug.h"
/*
* chunk can be accessed by either consumer OR producer, not both at same time
* -> no need to lock
*/
struct chunk {
char data[CHUNK_SIZE];
/* index to data, first filled byte */
unsigned int l;
/* index to data, last filled byte + 1
*
* there are h - l bytes available (filled)
*/
unsigned int h : 31;
/* if chunk is marked filled it can only be accessed by consumer
* otherwise only producer is allowed to access the chunk
*/
unsigned int filled : 1;
};
unsigned int buffer_nr_chunks;
static pthread_mutex_t buffer_mutex = CMUS_MUTEX_INITIALIZER;
static struct chunk *buffer_chunks = NULL;
static unsigned int buffer_ridx;
static unsigned int buffer_widx;
void buffer_init(void)
{
free(buffer_chunks);
buffer_chunks = xnew(struct chunk, buffer_nr_chunks);
buffer_reset();
}
void buffer_free(void)
{
free(buffer_chunks);
}
/*
* @pos: returned pointer to available data
*
* Returns number of bytes available at @pos
*
* After reading bytes mark them consumed calling buffer_consume().
*/
int buffer_get_rpos(char **pos)
{
struct chunk *c;
int size = 0;
cmus_mutex_lock(&buffer_mutex);
c = &buffer_chunks[buffer_ridx];
if (c->filled) {
size = c->h - c->l;
*pos = c->data + c->l;
}
cmus_mutex_unlock(&buffer_mutex);
return size;
}
/*
* @pos: pointer to buffer position where data can be written
*
* Returns number of bytes can be written to @pos. If the return value is
* non-zero it is guaranteed to be >= 1024.
*
* After writing bytes mark them filled calling buffer_fill().
*/
int buffer_get_wpos(char **pos)
{
struct chunk *c;
int size = 0;
cmus_mutex_lock(&buffer_mutex);
c = &buffer_chunks[buffer_widx];
if (!c->filled) {
size = CHUNK_SIZE - c->h;
*pos = c->data + c->h;
}
cmus_mutex_unlock(&buffer_mutex);
return size;
}
void buffer_consume(int count)
{
struct chunk *c;
BUG_ON(count < 0);
cmus_mutex_lock(&buffer_mutex);
c = &buffer_chunks[buffer_ridx];
BUG_ON(!c->filled);
c->l += count;
if (c->l == c->h) {
c->l = 0;
c->h = 0;
c->filled = 0;
buffer_ridx++;
buffer_ridx %= buffer_nr_chunks;
}
cmus_mutex_unlock(&buffer_mutex);
}
/* chunk is marked filled if free bytes < 1024 or count == 0 */
int buffer_fill(int count)
{
struct chunk *c;
int filled = 0;
cmus_mutex_lock(&buffer_mutex);
c = &buffer_chunks[buffer_widx];
BUG_ON(c->filled);
c->h += count;
if (CHUNK_SIZE - c->h < 1024 || (count == 0 && c->h > 0)) {
c->filled = 1;
buffer_widx++;
buffer_widx %= buffer_nr_chunks;
filled = 1;
}
cmus_mutex_unlock(&buffer_mutex);
return filled;
}
void buffer_reset(void)
{
int i;
cmus_mutex_lock(&buffer_mutex);
buffer_ridx = 0;
buffer_widx = 0;
for (i = 0; i < buffer_nr_chunks; i++) {
buffer_chunks[i].l = 0;
buffer_chunks[i].h = 0;
buffer_chunks[i].filled = 0;
}
cmus_mutex_unlock(&buffer_mutex);
}
int buffer_get_filled_chunks(void)
{
int c;
cmus_mutex_lock(&buffer_mutex);
if (buffer_ridx < buffer_widx) {
/*
* |__##########____|
* r w
*
* |############____|
* r w
*/
c = buffer_widx - buffer_ridx;
} else if (buffer_ridx > buffer_widx) {
/*
* |#######______###|
* w r
*
* |_____________###|
* w r
*/
c = buffer_nr_chunks - buffer_ridx + buffer_widx;
} else {
/*
* |################|
* r
* w
*
* |________________|
* r
* w
*/
if (buffer_chunks[buffer_ridx].filled) {
c = buffer_nr_chunks;
} else {
c = 0;
}
}
cmus_mutex_unlock(&buffer_mutex);
return c;
}