00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "xmmspriv/xmms_ringbuf.h"
00021 #include <string.h>
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 struct xmms_ringbuf_St {
00033
00034 guint8 *buffer;
00035
00036 guint buffer_size;
00037
00038 guint buffer_size_usable;
00039
00040 guint rd_index, wr_index;
00041 gboolean eos;
00042
00043 GQueue *hotspots;
00044
00045 GCond *free_cond, *used_cond, *eos_cond;
00046 };
00047
00048 typedef struct xmms_ringbuf_hotspot_St {
00049 guint pos;
00050 gboolean (*callback) (void *);
00051 void (*destroy) (void *);
00052 void *arg;
00053 } xmms_ringbuf_hotspot_t;
00054
00055
00056
00057
00058
00059 guint
00060 xmms_ringbuf_size (xmms_ringbuf_t *ringbuf)
00061 {
00062 g_return_val_if_fail (ringbuf, 0);
00063
00064 return ringbuf->buffer_size_usable;
00065 }
00066
00067
00068
00069
00070
00071
00072
00073 xmms_ringbuf_t *
00074 xmms_ringbuf_new (guint size)
00075 {
00076 xmms_ringbuf_t *ringbuf = g_new0 (xmms_ringbuf_t, 1);
00077
00078 g_return_val_if_fail (size > 0, NULL);
00079 g_return_val_if_fail (size < G_MAXUINT, NULL);
00080
00081
00082
00083
00084
00085
00086
00087 ringbuf->buffer_size_usable = size;
00088 ringbuf->buffer_size = size + 1;
00089 ringbuf->buffer = g_malloc (ringbuf->buffer_size);
00090
00091 ringbuf->free_cond = g_cond_new ();
00092 ringbuf->used_cond = g_cond_new ();
00093 ringbuf->eos_cond = g_cond_new ();
00094
00095 ringbuf->hotspots = g_queue_new ();
00096
00097 return ringbuf;
00098 }
00099
00100
00101
00102
00103 void
00104 xmms_ringbuf_destroy (xmms_ringbuf_t *ringbuf)
00105 {
00106 g_return_if_fail (ringbuf);
00107
00108 g_cond_free (ringbuf->eos_cond);
00109 g_cond_free (ringbuf->used_cond);
00110 g_cond_free (ringbuf->free_cond);
00111
00112 g_queue_free (ringbuf->hotspots);
00113 g_free (ringbuf->buffer);
00114 g_free (ringbuf);
00115 }
00116
00117
00118
00119
00120 void
00121 xmms_ringbuf_clear (xmms_ringbuf_t *ringbuf)
00122 {
00123 g_return_if_fail (ringbuf);
00124
00125 ringbuf->rd_index = 0;
00126 ringbuf->wr_index = 0;
00127
00128 while (!g_queue_is_empty (ringbuf->hotspots)) {
00129 xmms_ringbuf_hotspot_t *hs;
00130 hs = g_queue_pop_head (ringbuf->hotspots);
00131 if (hs->destroy)
00132 hs->destroy (hs->arg);
00133 g_free (hs);
00134 }
00135 g_cond_signal (ringbuf->free_cond);
00136 }
00137
00138
00139
00140
00141 guint
00142 xmms_ringbuf_bytes_free (const xmms_ringbuf_t *ringbuf)
00143 {
00144 g_return_val_if_fail (ringbuf, 0);
00145
00146 return ringbuf->buffer_size_usable -
00147 xmms_ringbuf_bytes_used (ringbuf);
00148 }
00149
00150
00151
00152
00153 guint
00154 xmms_ringbuf_bytes_used (const xmms_ringbuf_t *ringbuf)
00155 {
00156 g_return_val_if_fail (ringbuf, 0);
00157
00158 if (ringbuf->wr_index >= ringbuf->rd_index) {
00159 return ringbuf->wr_index - ringbuf->rd_index;
00160 }
00161
00162 return ringbuf->buffer_size - (ringbuf->rd_index - ringbuf->wr_index);
00163 }
00164
00165 static guint
00166 read_bytes (xmms_ringbuf_t *ringbuf, guint8 *data, guint len)
00167 {
00168 guint to_read, r = 0, cnt, tmp;
00169 gboolean ok;
00170
00171 to_read = MIN (len, xmms_ringbuf_bytes_used (ringbuf));
00172
00173 while (!g_queue_is_empty (ringbuf->hotspots)) {
00174 xmms_ringbuf_hotspot_t *hs = g_queue_peek_head (ringbuf->hotspots);
00175 if (hs->pos != ringbuf->rd_index) {
00176
00177 to_read = MIN (to_read,
00178 (hs->pos - ringbuf->rd_index + ringbuf->buffer_size)
00179 % ringbuf->buffer_size);
00180 break;
00181 }
00182
00183 (void) g_queue_pop_head (ringbuf->hotspots);
00184 ok = hs->callback (hs->arg);
00185 if (hs->destroy)
00186 hs->destroy (hs->arg);
00187 g_free (hs);
00188
00189 if (!ok) {
00190 return 0;
00191 }
00192
00193
00194
00195 }
00196
00197 tmp = ringbuf->rd_index;
00198
00199 while (to_read > 0) {
00200 cnt = MIN (to_read, ringbuf->buffer_size - tmp);
00201 memcpy (data, ringbuf->buffer + tmp, cnt);
00202 tmp = (tmp + cnt) % ringbuf->buffer_size;
00203 to_read -= cnt;
00204 r += cnt;
00205 data += cnt;
00206 }
00207
00208 return r;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 guint
00222 xmms_ringbuf_read (xmms_ringbuf_t *ringbuf, gpointer data, guint len)
00223 {
00224 guint r;
00225
00226 g_return_val_if_fail (ringbuf, 0);
00227 g_return_val_if_fail (data, 0);
00228 g_return_val_if_fail (len > 0, 0);
00229
00230 r = read_bytes (ringbuf, (guint8 *) data, len);
00231
00232 ringbuf->rd_index += r;
00233 ringbuf->rd_index %= ringbuf->buffer_size;
00234
00235 if (r) {
00236 g_cond_broadcast (ringbuf->free_cond);
00237 }
00238
00239 return r;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248 guint
00249 xmms_ringbuf_peek (xmms_ringbuf_t *ringbuf, gpointer data, guint len)
00250 {
00251 g_return_val_if_fail (ringbuf, 0);
00252 g_return_val_if_fail (data, 0);
00253 g_return_val_if_fail (len > 0, 0);
00254 g_return_val_if_fail (len <= ringbuf->buffer_size_usable, 0);
00255
00256 return read_bytes (ringbuf, (guint8 *) data, len);
00257 }
00258
00259
00260
00261
00262
00263
00264 guint
00265 xmms_ringbuf_read_wait (xmms_ringbuf_t *ringbuf, gpointer data,
00266 guint len, GMutex *mtx)
00267 {
00268 guint r = 0, res;
00269 guint8 *dest = data;
00270
00271 g_return_val_if_fail (ringbuf, 0);
00272 g_return_val_if_fail (data, 0);
00273 g_return_val_if_fail (len > 0, 0);
00274 g_return_val_if_fail (mtx, 0);
00275
00276 while (r < len) {
00277 res = xmms_ringbuf_read (ringbuf, dest + r, len - r);
00278 r += res;
00279 if (r == len || ringbuf->eos) {
00280 break;
00281 }
00282 if (!res)
00283 g_cond_wait (ringbuf->used_cond, mtx);
00284 }
00285
00286 return r;
00287 }
00288
00289
00290
00291
00292
00293
00294 guint
00295 xmms_ringbuf_peek_wait (xmms_ringbuf_t *ringbuf, gpointer data,
00296 guint len, GMutex *mtx)
00297 {
00298 g_return_val_if_fail (ringbuf, 0);
00299 g_return_val_if_fail (data, 0);
00300 g_return_val_if_fail (len > 0, 0);
00301 g_return_val_if_fail (len <= ringbuf->buffer_size_usable, 0);
00302 g_return_val_if_fail (mtx, 0);
00303
00304 xmms_ringbuf_wait_used (ringbuf, len, mtx);
00305
00306 return xmms_ringbuf_peek (ringbuf, data, len);
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 guint
00321 xmms_ringbuf_write (xmms_ringbuf_t *ringbuf, gconstpointer data,
00322 guint len)
00323 {
00324 guint to_write, w = 0, cnt;
00325 const guint8 *src = data;
00326
00327 g_return_val_if_fail (ringbuf, 0);
00328 g_return_val_if_fail (data, 0);
00329 g_return_val_if_fail (len > 0, 0);
00330
00331 to_write = MIN (len, xmms_ringbuf_bytes_free (ringbuf));
00332
00333 while (to_write > 0) {
00334 cnt = MIN (to_write, ringbuf->buffer_size - ringbuf->wr_index);
00335 memcpy (ringbuf->buffer + ringbuf->wr_index, src + w, cnt);
00336 ringbuf->wr_index = (ringbuf->wr_index + cnt) % ringbuf->buffer_size;
00337 to_write -= cnt;
00338 w += cnt;
00339 }
00340
00341 if (w) {
00342 g_cond_broadcast (ringbuf->used_cond);
00343 }
00344
00345 return w;
00346 }
00347
00348
00349
00350
00351
00352 guint
00353 xmms_ringbuf_write_wait (xmms_ringbuf_t *ringbuf, gconstpointer data,
00354 guint len, GMutex *mtx)
00355 {
00356 guint w = 0;
00357 const guint8 *src = data;
00358
00359 g_return_val_if_fail (ringbuf, 0);
00360 g_return_val_if_fail (data, 0);
00361 g_return_val_if_fail (len > 0, 0);
00362 g_return_val_if_fail (mtx, 0);
00363
00364 while (w < len) {
00365 w += xmms_ringbuf_write (ringbuf, src + w, len - w);
00366 if (w == len || ringbuf->eos) {
00367 break;
00368 }
00369
00370 g_cond_wait (ringbuf->free_cond, mtx);
00371 }
00372
00373 return w;
00374 }
00375
00376
00377
00378
00379 void
00380 xmms_ringbuf_wait_free (const xmms_ringbuf_t *ringbuf, guint len, GMutex *mtx)
00381 {
00382 g_return_if_fail (ringbuf);
00383 g_return_if_fail (len > 0);
00384 g_return_if_fail (len <= ringbuf->buffer_size_usable);
00385 g_return_if_fail (mtx);
00386
00387 while ((xmms_ringbuf_bytes_free (ringbuf) < len) && !ringbuf->eos) {
00388 g_cond_wait (ringbuf->free_cond, mtx);
00389 }
00390 }
00391
00392
00393
00394
00395
00396 void
00397 xmms_ringbuf_wait_used (const xmms_ringbuf_t *ringbuf, guint len, GMutex *mtx)
00398 {
00399 g_return_if_fail (ringbuf);
00400 g_return_if_fail (len > 0);
00401 g_return_if_fail (len <= ringbuf->buffer_size_usable);
00402 g_return_if_fail (mtx);
00403
00404 while ((xmms_ringbuf_bytes_used (ringbuf) < len) && !ringbuf->eos) {
00405 g_cond_wait (ringbuf->used_cond, mtx);
00406 }
00407 }
00408
00409
00410
00411
00412
00413
00414
00415 gboolean
00416 xmms_ringbuf_iseos (const xmms_ringbuf_t *ringbuf)
00417 {
00418 g_return_val_if_fail (ringbuf, TRUE);
00419
00420 return !xmms_ringbuf_bytes_used (ringbuf) && ringbuf->eos;
00421 }
00422
00423
00424
00425
00426 void
00427 xmms_ringbuf_set_eos (xmms_ringbuf_t *ringbuf, gboolean eos)
00428 {
00429 g_return_if_fail (ringbuf);
00430
00431 ringbuf->eos = eos;
00432
00433 if (eos) {
00434 g_cond_broadcast (ringbuf->eos_cond);
00435 g_cond_broadcast (ringbuf->used_cond);
00436 g_cond_broadcast (ringbuf->free_cond);
00437 }
00438 }
00439
00440
00441
00442
00443
00444 void
00445 xmms_ringbuf_wait_eos (const xmms_ringbuf_t *ringbuf, GMutex *mtx)
00446 {
00447 g_return_if_fail (ringbuf);
00448 g_return_if_fail (mtx);
00449
00450 while (!xmms_ringbuf_iseos (ringbuf)) {
00451 g_cond_wait (ringbuf->eos_cond, mtx);
00452 }
00453
00454 }
00455
00456
00457
00458
00459
00460
00461 void
00462 xmms_ringbuf_hotspot_set (xmms_ringbuf_t *ringbuf, gboolean (*cb) (void *), void (*destroy) (void *), void *arg)
00463 {
00464 xmms_ringbuf_hotspot_t *hs;
00465 g_return_if_fail (ringbuf);
00466
00467 hs = g_new0 (xmms_ringbuf_hotspot_t, 1);
00468 hs->pos = ringbuf->wr_index;
00469 hs->callback = cb;
00470 hs->destroy = destroy;
00471 hs->arg = arg;
00472
00473 g_queue_push_tail (ringbuf->hotspots, hs);
00474 }
00475
00476