JasonWoof / cmus-unofficial

cmus fork for collecting patches from mailing list

This URL has Read+Write access

flyingmutant (author)
Thu May 28 14:42:21 -0700 2009
Jason Woofenden (committer)
Thu May 28 15:30:57 -0700 2009
cmus-unofficial / buffer.c
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 1 #include "buffer.h"
2 #include "xmalloc.h"
3 #include "locking.h"
4 #include "debug.h"
5
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];
12
13 /* index to data, first filled byte */
14 unsigned int l;
15
16 /* index to data, last filled byte + 1
17 *
18 * there are h - l bytes available (filled)
19 */
20 unsigned int h : 31;
21
22 /* if chunk is marked filled it can only be accessed by consumer
23 * otherwise only producer is allowed to access the chunk
24 */
25 unsigned int filled : 1;
26 };
27
28 unsigned int buffer_nr_chunks;
29
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;
34
35 void buffer_init(void)
36 {
37 free(buffer_chunks);
38 buffer_chunks = xnew(struct chunk, buffer_nr_chunks);
39 buffer_reset();
40 }
41
42 /*
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 43 * @pos: returned pointer to available data
44 *
45 * Returns number of bytes available at @pos
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 46 *
47 * After reading bytes mark them consumed calling buffer_consume().
48 */
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 49 int buffer_get_rpos(char **pos)
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 50 {
51 struct chunk *c;
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 52 int size = 0;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 53
54 cmus_mutex_lock(&buffer_mutex);
55 c = &buffer_chunks[buffer_ridx];
56 if (c->filled) {
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 57 size = c->h - c->l;
58 *pos = c->data + c->l;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 59 }
60 cmus_mutex_unlock(&buffer_mutex);
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 61
62 return size;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 63 }
64
65 /*
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 66 * @pos: pointer to buffer position where data can be written
67 *
68 * Returns number of bytes can be written to @pos. If the return value is
69 * non-zero it is guaranteed to be >= 1024.
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 70 *
71 * After writing bytes mark them filled calling buffer_fill().
72 */
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 73 int buffer_get_wpos(char **pos)
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 74 {
75 struct chunk *c;
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 76 int size = 0;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 77
78 cmus_mutex_lock(&buffer_mutex);
79 c = &buffer_chunks[buffer_widx];
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 80 if (!c->filled) {
81 size = CHUNK_SIZE - c->h;
82 *pos = c->data + c->h;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 83 }
84 cmus_mutex_unlock(&buffer_mutex);
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 85
86 return size;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 87 }
88
89 void buffer_consume(int count)
90 {
91 struct chunk *c;
92
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;
104 }
105 cmus_mutex_unlock(&buffer_mutex);
106 }
107
c8121dda » Timo Hirvonen 2006-02-27 Make buffer_get_[rw]pos() r... 108 /* chunk is marked filled if free bytes < 1024 or count == 0 */
26c3ab52 » Timo Hirvonen 2006-10-15 buffer_fill(): Return numbe... 109 int buffer_fill(int count)
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 110 {
111 struct chunk *c;
26c3ab52 » Timo Hirvonen 2006-10-15 buffer_fill(): Return numbe... 112 int filled = 0;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 113
114 cmus_mutex_lock(&buffer_mutex);
115 c = &buffer_chunks[buffer_widx];
116 BUG_ON(c->filled);
117 c->h += count;
118
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;
26c3ab52 » Timo Hirvonen 2006-10-15 buffer_fill(): Return numbe... 123 filled = 1;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 124 }
125
126 cmus_mutex_unlock(&buffer_mutex);
26c3ab52 » Timo Hirvonen 2006-10-15 buffer_fill(): Return numbe... 127 return filled;
f35b01de » Timo Hirvonen 2006-02-27 Simplify buffering code 128 }
129
130 void buffer_reset(void)
131 {
132 int i;
133
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;
141 }
142 cmus_mutex_unlock(&buffer_mutex);
143 }
144
145 int buffer_get_filled_chunks(void)
146 {
147 int c;
148
149 cmus_mutex_lock(&buffer_mutex);
150 if (buffer_ridx < buffer_widx) {
151 /*
152 * |__##########____|
153 * r w
154 *
155 * |############____|
156 * r w
157 */
158 c = buffer_widx - buffer_ridx;
159 } else if (buffer_ridx > buffer_widx) {
160 /*
161 * |#######______###|
162 * w r
163 *
164 * |_____________###|
165 * w r
166 */
167 c = buffer_nr_chunks - buffer_ridx + buffer_widx;
168 } else {
169 /*
170 * |################|
171 * r
172 * w
173 *
174 * |________________|
175 * r
176 * w
177 */
178 if (buffer_chunks[buffer_ridx].filled) {
179 c = buffer_nr_chunks;
180 } else {
181 c = 0;
182 }
183 }
184 cmus_mutex_unlock(&buffer_mutex);
185 return c;
186 }