Define default port in Makefile
[cmus.git] / buffer.c
blob5e4c6e9f00cbf980aed9be7d35d36a79d9327263
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 void buffer_fill(int count)
111 struct chunk *c;
113 cmus_mutex_lock(&buffer_mutex);
114 c = &buffer_chunks[buffer_widx];
115 BUG_ON(c->filled);
116 c->h += count;
118 if (CHUNK_SIZE - c->h < 1024 || (count == 0 && c->h > 0)) {
119 c->filled = 1;
120 buffer_widx++;
121 buffer_widx %= buffer_nr_chunks;
124 cmus_mutex_unlock(&buffer_mutex);
127 void buffer_reset(void)
129 int i;
131 cmus_mutex_lock(&buffer_mutex);
132 buffer_ridx = 0;
133 buffer_widx = 0;
134 for (i = 0; i < buffer_nr_chunks; i++) {
135 buffer_chunks[i].l = 0;
136 buffer_chunks[i].h = 0;
137 buffer_chunks[i].filled = 0;
139 cmus_mutex_unlock(&buffer_mutex);
142 int buffer_get_filled_chunks(void)
144 int c;
146 cmus_mutex_lock(&buffer_mutex);
147 if (buffer_ridx < buffer_widx) {
149 * |__##########____|
150 * r w
152 * |############____|
153 * r w
155 c = buffer_widx - buffer_ridx;
156 } else if (buffer_ridx > buffer_widx) {
158 * |#######______###|
159 * w r
161 * |_____________###|
162 * w r
164 c = buffer_nr_chunks - buffer_ridx + buffer_widx;
165 } else {
167 * |################|
171 * |________________|
175 if (buffer_chunks[buffer_ridx].filled) {
176 c = buffer_nr_chunks;
177 } else {
178 c = 0;
181 cmus_mutex_unlock(&buffer_mutex);
182 return c;