flac: Saner EOF handling
[cmus.git] / buffer.c
blob986aeac32c54c2e44e61c5006f6ce7a7a766f7c1
1 #include "buffer.h"
2 #include "xmalloc.h"
3 #include "locking.h"
4 #include "debug.h"
6 /*
7 * chunk can be accessed by either consumer OR producer, not both at same time
8 * -> no need to lock
9 */
10 struct chunk {
11 char data[CHUNK_SIZE];
13 /* index to data, first filled byte */
14 unsigned int l;
16 /* index to data, last filled byte + 1
18 * there are h - l bytes available (filled)
20 unsigned int h : 31;
22 /* if chunk is marked filled it can only be accessed by consumer
23 * otherwise only producer is allowed to access the chunk
25 unsigned int filled : 1;
28 unsigned int buffer_nr_chunks;
30 static pthread_mutex_t buffer_mutex = CMUS_MUTEX_INITIALIZER;
31 static struct chunk *buffer_chunks = NULL;
32 static unsigned int buffer_ridx;
33 static unsigned int buffer_widx;
35 void buffer_init(void)
37 free(buffer_chunks);
38 buffer_chunks = xnew(struct chunk, buffer_nr_chunks);
39 buffer_reset();
43 * @pos: returned pointer to available data
45 * Returns number of bytes available at @pos
47 * After reading bytes mark them consumed calling buffer_consume().
49 int buffer_get_rpos(char **pos)
51 struct chunk *c;
52 int size = 0;
54 cmus_mutex_lock(&buffer_mutex);
55 c = &buffer_chunks[buffer_ridx];
56 if (c->filled) {
57 size = c->h - c->l;
58 *pos = c->data + c->l;
60 cmus_mutex_unlock(&buffer_mutex);
62 return size;
66 * @pos: pointer to buffer position where data can be written
68 * Returns number of bytes can be written to @pos. If the return value is
69 * non-zero it is guaranteed to be >= 1024.
71 * After writing bytes mark them filled calling buffer_fill().
73 int buffer_get_wpos(char **pos)
75 struct chunk *c;
76 int size = 0;
78 cmus_mutex_lock(&buffer_mutex);
79 c = &buffer_chunks[buffer_widx];
80 if (!c->filled) {
81 size = CHUNK_SIZE - c->h;
82 *pos = c->data + c->h;
84 cmus_mutex_unlock(&buffer_mutex);
86 return size;
89 void buffer_consume(int count)
91 struct chunk *c;
93 BUG_ON(count <= 0);
94 cmus_mutex_lock(&buffer_mutex);
95 c = &buffer_chunks[buffer_ridx];
96 BUG_ON(!c->filled);
97 c->l += count;
98 if (c->l == c->h) {
99 c->l = 0;
100 c->h = 0;
101 c->filled = 0;
102 buffer_ridx++;
103 buffer_ridx %= buffer_nr_chunks;
105 cmus_mutex_unlock(&buffer_mutex);
108 /* chunk is marked filled if free bytes < 1024 or count == 0 */
109 int buffer_fill(int count)
111 struct chunk *c;
112 int filled = 0;
114 cmus_mutex_lock(&buffer_mutex);
115 c = &buffer_chunks[buffer_widx];
116 BUG_ON(c->filled);
117 c->h += count;
119 if (CHUNK_SIZE - c->h < 1024 || (count == 0 && c->h > 0)) {
120 c->filled = 1;
121 buffer_widx++;
122 buffer_widx %= buffer_nr_chunks;
123 filled = 1;
126 cmus_mutex_unlock(&buffer_mutex);
127 return filled;
130 void buffer_reset(void)
132 int i;
134 cmus_mutex_lock(&buffer_mutex);
135 buffer_ridx = 0;
136 buffer_widx = 0;
137 for (i = 0; i < buffer_nr_chunks; i++) {
138 buffer_chunks[i].l = 0;
139 buffer_chunks[i].h = 0;
140 buffer_chunks[i].filled = 0;
142 cmus_mutex_unlock(&buffer_mutex);
145 int buffer_get_filled_chunks(void)
147 int c;
149 cmus_mutex_lock(&buffer_mutex);
150 if (buffer_ridx < buffer_widx) {
152 * |__##########____|
153 * r w
155 * |############____|
156 * r w
158 c = buffer_widx - buffer_ridx;
159 } else if (buffer_ridx > buffer_widx) {
161 * |#######______###|
162 * w r
164 * |_____________###|
165 * w r
167 c = buffer_nr_chunks - buffer_ridx + buffer_widx;
168 } else {
170 * |################|
174 * |________________|
178 if (buffer_chunks[buffer_ridx].filled) {
179 c = buffer_nr_chunks;
180 } else {
181 c = 0;
184 cmus_mutex_unlock(&buffer_mutex);
185 return c;