1 /*
2 * Copyright (C) 2000-2019 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 *
21 * contents:
22 *
23 * buffer_entry structure - serves as a transport encapsulation
24 * of the mpeg audio/video data through xine
25 *
26 * free buffer pool management routines
27 *
28 * FIFO buffer structures/routines
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <pthread.h>
38
39 /********** logging **********/
40 #define LOG_MODULE "buffer"
41 #define LOG_VERBOSE
42 /*
43 #define LOG
44 */
45
46 #include <xine/buffer.h>
47 #include <xine/xineutils.h>
48 #include <xine/xine_internal.h>
49
50 /* The large buffer feature.
51 * If we have enough contigous memory, and if we can afford to hand if out,
52 * provide an oversize item there. The buffers covering that extra space will
53 * hide inside our buffer array, and buffer_pool_free () will reappear them
54 * mysteriously later.
55 * Small bufs are requested frequently, so we dont do a straightforward
56 * heap manager. Instead, we keep bufs in pool sorted by address, and
57 * be_ei_t.nbufs holds the count of contigous bufs when this is the
58 * first of such a group.
59 * API permits using bufs in a different fifo than their pool origin
60 * (see demux_mpeg_block). Thats why we test buf->source.
61 * It is also possible to supply fully custom bufs. We detect these by
62 * buf->free_buffer != buffer_pool_free.
63 */
64
65 typedef struct {
66 buf_element_t elem; /* needs to be first */
67 int nbufs; /* # of contigous bufs */
68 extra_info_t ei;
69 } be_ei_t;
70
71 #define LARGE_NUM 0x7fffffff
72
73 /*
74 * put a previously allocated buffer element back into the buffer pool
75 */
buffer_pool_free(buf_element_t * element)76 static void buffer_pool_free (buf_element_t *element) {
77 fifo_buffer_t *this = (fifo_buffer_t *) element->source;
78 be_ei_t *newhead, *newtail, *nexthead;
79 int n;
80
81 pthread_mutex_lock (&this->buffer_pool_mutex);
82
83 newhead = (be_ei_t *)element;
84 n = newhead->nbufs;
85 this->buffer_pool_num_free += n;
86 if (this->buffer_pool_num_free > this->buffer_pool_capacity) {
87 fprintf(stderr, _("xine-lib: buffer.c: There has been a fatal error: TOO MANY FREE's\n"));
88 _x_abort();
89 }
90
91 /* we might be a new chunk */
92 newtail = newhead + 1;
93 while (--n > 0) {
94 newtail[-1].elem.next = &newtail[0].elem;
95 newtail++;
96 }
97
98 nexthead = (be_ei_t *)this->buffer_pool_top;
99 if (!nexthead || (nexthead >= newtail)) {
100 /* add head */
101 this->buffer_pool_top = &newhead->elem;
102 newtail[-1].elem.next = &nexthead->elem;
103 /* merge with next chunk if no gap */
104 if (newtail == nexthead)
105 newhead->nbufs += nexthead->nbufs;
106 } else {
107 /* Keep the pool sorted, elem1 > elem2 implies elem1->mem > elem2->mem. */
108 be_ei_t *prevhead, *prevtail;
109 while (1) {
110 prevhead = nexthead;
111 prevtail = prevhead + prevhead->nbufs;
112 nexthead = (be_ei_t *)prevtail[-1].elem.next;
113 if (!nexthead || (nexthead >= newtail))
114 break;
115 }
116 prevtail[-1].elem.next = &newhead->elem;
117 newtail[-1].elem.next = &nexthead->elem;
118 /* merge with next chunk if no gap */
119 if (newtail == nexthead)
120 newhead->nbufs += nexthead->nbufs;
121 /* merge with prev chunk if no gap */
122 if (prevtail == newhead)
123 prevhead->nbufs += newhead->nbufs;
124 }
125
126 /* dont provoke useless wakeups */
127 if (this->buffer_pool_num_waiters ||
128 (this->buffer_pool_large_wait <= this->buffer_pool_num_free))
129 pthread_cond_signal (&this->buffer_pool_cond_not_empty);
130
131 pthread_mutex_unlock (&this->buffer_pool_mutex);
132 }
133
134 /*
135 * allocate a buffer from buffer pool
136 */
137
buffer_pool_size_alloc_int(fifo_buffer_t * this,int n)138 static buf_element_t *buffer_pool_size_alloc_int (fifo_buffer_t *this, int n) {
139
140 int i;
141 be_ei_t *buf;
142
143 for (i = 0; this->alloc_cb[i]; i++)
144 this->alloc_cb[i] (this, this->alloc_cb_data[i]);
145
146 if (n < 1)
147 n = 1;
148 /* we always keep one free buffer for emergency situations like
149 * decoder flushes that would need a buffer in buffer_pool_try_alloc() */
150 n += 2;
151 if (this->buffer_pool_num_free < n) {
152 /* Paranoia: someone else than demux calling this in parallel ?? */
153 if (this->buffer_pool_large_wait != LARGE_NUM) {
154 this->buffer_pool_num_waiters++;
155 do {
156 pthread_cond_wait (&this->buffer_pool_cond_not_empty, &this->buffer_pool_mutex);
157 } while (this->buffer_pool_num_free < n);
158 this->buffer_pool_num_waiters--;
159 } else {
160 this->buffer_pool_large_wait = n;
161 do {
162 pthread_cond_wait (&this->buffer_pool_cond_not_empty, &this->buffer_pool_mutex);
163 } while (this->buffer_pool_num_free < n);
164 this->buffer_pool_large_wait = LARGE_NUM;
165 }
166 }
167 n -= 2;
168
169 buf = (be_ei_t *)this->buffer_pool_top;
170 if (n == 1) {
171
172 this->buffer_pool_top = buf->elem.next;
173 i = buf->nbufs - 1;
174 if (i > 0)
175 buf[1].nbufs = i;
176 this->buffer_pool_num_free--;
177
178 } else {
179
180 buf_element_t **link = &this->buffer_pool_top, **bestlink = link;
181 int bestsize = 0;
182 while (1) {
183 int l = buf->nbufs;
184 if (l > n) {
185 be_ei_t *next = buf + n;
186 next->nbufs = l - n;
187 *link = &next->elem;
188 break;
189 } else if (l == n) {
190 *link = buf[l - 1].elem.next;
191 break;
192 }
193 if (l > bestsize) {
194 bestsize = l;
195 bestlink = link;
196 }
197 buf += l - 1;
198 link = &buf->elem.next;
199 buf = (be_ei_t *)(*link);
200 if (!buf) {
201 buf = (be_ei_t *)(*bestlink);
202 n = bestsize;
203 *bestlink = buf[n - 1].elem.next;
204 break;
205 }
206 }
207 this->buffer_pool_num_free -= n;
208
209 }
210
211 pthread_mutex_unlock (&this->buffer_pool_mutex);
212
213 /* set sane values to the newly allocated buffer */
214 buf->elem.content = buf->elem.mem; /* 99% of demuxers will want this */
215 buf->elem.pts = 0;
216 buf->elem.size = 0;
217 buf->elem.max_size = n * this->buffer_pool_buf_size;
218 buf->elem.decoder_flags = 0;
219 buf->nbufs = n;
220 memset (buf->elem.decoder_info, 0, sizeof (buf->elem.decoder_info));
221 memset (buf->elem.decoder_info_ptr, 0, sizeof (buf->elem.decoder_info_ptr));
222 _x_extra_info_reset (buf->elem.extra_info);
223
224 return &buf->elem;
225 }
226
buffer_pool_size_alloc(fifo_buffer_t * this,size_t size)227 static buf_element_t *buffer_pool_size_alloc (fifo_buffer_t *this, size_t size) {
228 int n = size ? ((int)size + this->buffer_pool_buf_size - 1) / this->buffer_pool_buf_size : 1;
229 if (n > (this->buffer_pool_capacity >> 2))
230 n = this->buffer_pool_capacity >> 2;
231 pthread_mutex_lock (&this->buffer_pool_mutex);
232 return buffer_pool_size_alloc_int (this, n);
233 }
234
235
buffer_pool_alloc(fifo_buffer_t * this)236 static buf_element_t *buffer_pool_alloc (fifo_buffer_t *this) {
237 be_ei_t *buf;
238 int i;
239
240 pthread_mutex_lock (&this->buffer_pool_mutex);
241
242 for(i = 0; this->alloc_cb[i]; i++)
243 this->alloc_cb[i](this, this->alloc_cb_data[i]);
244
245 /* we always keep one free buffer for emergency situations like
246 * decoder flushes that would need a buffer in buffer_pool_try_alloc() */
247 if (this->buffer_pool_num_free < 2) {
248 this->buffer_pool_num_waiters++;
249 do {
250 pthread_cond_wait (&this->buffer_pool_cond_not_empty, &this->buffer_pool_mutex);
251 } while (this->buffer_pool_num_free < 2);
252 this->buffer_pool_num_waiters--;
253 }
254
255 buf = (be_ei_t *)this->buffer_pool_top;
256 this->buffer_pool_top = buf->elem.next;
257 i = buf->nbufs - 1;
258 if (i > 0)
259 buf[1].nbufs = i;
260 this->buffer_pool_num_free--;
261
262 pthread_mutex_unlock (&this->buffer_pool_mutex);
263
264 /* set sane values to the newly allocated buffer */
265 buf->elem.content = buf->elem.mem; /* 99% of demuxers will want this */
266 buf->elem.pts = 0;
267 buf->elem.size = 0;
268 buf->elem.max_size = this->buffer_pool_buf_size;
269 buf->elem.decoder_flags = 0;
270 buf->nbufs = 1;
271 memset (buf->elem.decoder_info, 0, sizeof (buf->elem.decoder_info));
272 memset (buf->elem.decoder_info_ptr, 0, sizeof (buf->elem.decoder_info_ptr));
273 _x_extra_info_reset (buf->elem.extra_info);
274
275 return &buf->elem;
276 }
277
buffer_pool_realloc(buf_element_t * buf,size_t new_size)278 static buf_element_t *buffer_pool_realloc (buf_element_t *buf, size_t new_size) {
279 fifo_buffer_t *this;
280 buf_element_t **last_buf;
281 be_ei_t *old_buf = (be_ei_t *)buf, *new_buf, *want_buf;
282 int n;
283
284 if (!old_buf)
285 return NULL;
286 if ((int)new_size <= old_buf->elem.max_size)
287 return NULL;
288 if (old_buf->elem.free_buffer != buffer_pool_free)
289 return NULL;
290 this = (fifo_buffer_t *)old_buf->elem.source;
291 if (!this)
292 return NULL;
293
294 n = ((int)new_size + this->buffer_pool_buf_size - 1) / this->buffer_pool_buf_size;
295 /* limit size to keep pool fluent */
296 if (n > (this->buffer_pool_capacity >> 3))
297 n = this->buffer_pool_capacity >> 3;
298 n -= old_buf->nbufs;
299
300 want_buf = old_buf + old_buf->nbufs;
301 last_buf = &this->buffer_pool_top;
302 pthread_mutex_lock (&this->buffer_pool_mutex);
303 while (1) {
304 new_buf = (be_ei_t *)(*last_buf);
305 if (!new_buf)
306 break;
307 if (new_buf == want_buf)
308 break;
309 if (new_buf > want_buf) {
310 new_buf = NULL;
311 break;
312 }
313 new_buf += new_buf->nbufs;
314 last_buf = &(new_buf[-1].elem.next);
315 }
316
317 if (new_buf) do {
318 int s;
319 /* save emergecy buf */
320 if (n > this->buffer_pool_num_free - 1)
321 n = this->buffer_pool_num_free - 1;
322 if (n < 1)
323 break;
324 s = new_buf->nbufs - n;
325 if (s > 0) {
326 new_buf += n;
327 new_buf->nbufs = s;
328 *last_buf = &new_buf->elem;
329 } else {
330 n = new_buf->nbufs;
331 new_buf += n;
332 *last_buf = new_buf[-1].elem.next;
333 }
334 this->buffer_pool_num_free -= n;
335 pthread_mutex_unlock (&this->buffer_pool_mutex);
336 old_buf->nbufs += n;
337 old_buf->elem.max_size = old_buf->nbufs * this->buffer_pool_buf_size;
338 return NULL;
339 } while (0);
340
341 return buffer_pool_size_alloc_int (this, n);
342 }
343
344 /*
345 * allocate a buffer from buffer pool - may fail if none is available
346 */
347
buffer_pool_try_alloc(fifo_buffer_t * this)348 static buf_element_t *buffer_pool_try_alloc (fifo_buffer_t *this) {
349 be_ei_t *buf;
350 int i;
351
352 pthread_mutex_lock (&this->buffer_pool_mutex);
353 buf = (be_ei_t *)this->buffer_pool_top;
354 if (!buf) {
355 pthread_mutex_unlock (&this->buffer_pool_mutex);
356 return NULL;
357 }
358
359 this->buffer_pool_top = buf->elem.next;
360 i = buf->nbufs - 1;
361 if (i > 0)
362 buf[1].nbufs = i;
363 this->buffer_pool_num_free--;
364 pthread_mutex_unlock (&this->buffer_pool_mutex);
365
366 /* set sane values to the newly allocated buffer */
367 buf->elem.content = buf->elem.mem; /* 99% of demuxers will want this */
368 buf->elem.pts = 0;
369 buf->elem.size = 0;
370 buf->elem.max_size = this->buffer_pool_buf_size;
371 buf->elem.decoder_flags = 0;
372 buf->nbufs = 1;
373 memset (buf->elem.decoder_info, 0, sizeof (buf->elem.decoder_info));
374 memset (buf->elem.decoder_info_ptr, 0, sizeof (buf->elem.decoder_info_ptr));
375 _x_extra_info_reset (buf->elem.extra_info);
376
377 return &buf->elem;
378 }
379
380
381 /*
382 * append buffer element to fifo buffer
383 */
fifo_buffer_put(fifo_buffer_t * fifo,buf_element_t * element)384 static void fifo_buffer_put (fifo_buffer_t *fifo, buf_element_t *element) {
385 int i;
386
387 pthread_mutex_lock (&fifo->mutex);
388
389 if (element->decoder_flags & BUF_FLAG_MERGE) {
390 be_ei_t *new = (be_ei_t *)element, *prev = (be_ei_t *)fifo->last;
391 new->elem.decoder_flags &= ~BUF_FLAG_MERGE;
392 if (prev && (prev + prev->nbufs == new)
393 && (prev->elem.type == new->elem.type)
394 && (prev->nbufs < (fifo->buffer_pool_capacity >> 3))) {
395 fifo->fifo_size += new->nbufs;
396 fifo->fifo_data_size += new->elem.size;
397 prev->nbufs += new->nbufs;
398 prev->elem.max_size += new->elem.max_size;
399 prev->elem.size += new->elem.size;
400 prev->elem.decoder_flags |= new->elem.decoder_flags;
401 pthread_mutex_unlock (&fifo->mutex);
402 return;
403 }
404 }
405
406 for(i = 0; fifo->put_cb[i]; i++)
407 fifo->put_cb[i](fifo, element, fifo->put_cb_data[i]);
408
409 if (fifo->last)
410 fifo->last->next = element;
411 else
412 fifo->first = element;
413
414 fifo->last = element;
415 element->next = NULL;
416
417 if (element->free_buffer == buffer_pool_free) {
418 be_ei_t *beei = (be_ei_t *)element;
419 fifo->fifo_size += beei->nbufs;
420 } else {
421 fifo->fifo_size += 1;
422 }
423 fifo->fifo_data_size += element->size;
424
425 if (fifo->fifo_num_waiters)
426 pthread_cond_signal (&fifo->not_empty);
427
428 pthread_mutex_unlock (&fifo->mutex);
429 }
430
431 /*
432 * simulate append buffer element to fifo buffer
433 */
dummy_fifo_buffer_put(fifo_buffer_t * fifo,buf_element_t * element)434 static void dummy_fifo_buffer_put (fifo_buffer_t *fifo, buf_element_t *element) {
435 int i;
436
437 pthread_mutex_lock (&fifo->mutex);
438
439 for(i = 0; fifo->put_cb[i]; i++)
440 fifo->put_cb[i](fifo, element, fifo->put_cb_data[i]);
441
442 pthread_mutex_unlock (&fifo->mutex);
443
444 element->free_buffer(element);
445 }
446
447 /*
448 * insert buffer element to fifo buffer (demuxers MUST NOT call this one)
449 */
fifo_buffer_insert(fifo_buffer_t * fifo,buf_element_t * element)450 static void fifo_buffer_insert (fifo_buffer_t *fifo, buf_element_t *element) {
451 pthread_mutex_lock (&fifo->mutex);
452
453 element->next = fifo->first;
454 fifo->first = element;
455
456 if( !fifo->last )
457 fifo->last = element;
458
459 if (element->free_buffer == buffer_pool_free) {
460 be_ei_t *beei = (be_ei_t *)element;
461 fifo->fifo_size += beei->nbufs;
462 } else {
463 fifo->fifo_size += 1;
464 }
465 fifo->fifo_data_size += element->size;
466
467 if (fifo->fifo_num_waiters)
468 pthread_cond_signal (&fifo->not_empty);
469
470 pthread_mutex_unlock (&fifo->mutex);
471 }
472
473 /*
474 * insert buffer element to fifo buffer (demuxers MUST NOT call this one)
475 */
dummy_fifo_buffer_insert(fifo_buffer_t * fifo,buf_element_t * element)476 static void dummy_fifo_buffer_insert (fifo_buffer_t *fifo, buf_element_t *element) {
477 (void)fifo;
478 element->free_buffer(element);
479 }
480
481 /*
482 * get element from fifo buffer
483 */
fifo_buffer_get(fifo_buffer_t * fifo)484 static buf_element_t *fifo_buffer_get (fifo_buffer_t *fifo) {
485 buf_element_t *buf;
486 int i;
487
488 pthread_mutex_lock (&fifo->mutex);
489
490 if (!fifo->first) {
491 fifo->fifo_num_waiters++;
492 do {
493 pthread_cond_wait (&fifo->not_empty, &fifo->mutex);
494 } while (!fifo->first);
495 fifo->fifo_num_waiters--;
496 }
497
498 buf = fifo->first;
499
500 fifo->first = fifo->first->next;
501 if (fifo->first==NULL)
502 fifo->last = NULL;
503
504 if (buf->free_buffer == buffer_pool_free) {
505 be_ei_t *beei = (be_ei_t *)buf;
506 fifo->fifo_size -= beei->nbufs;
507 } else {
508 fifo->fifo_size -= 1;
509 }
510 fifo->fifo_data_size -= buf->size;
511
512 for(i = 0; fifo->get_cb[i]; i++)
513 fifo->get_cb[i](fifo, buf, fifo->get_cb_data[i]);
514
515 pthread_mutex_unlock (&fifo->mutex);
516
517 return buf;
518 }
519
fifo_buffer_tget(fifo_buffer_t * fifo,xine_ticket_t * ticket)520 static buf_element_t *fifo_buffer_tget (fifo_buffer_t *fifo, xine_ticket_t *ticket) {
521 /* Optimization: let decoders hold port ticket by default.
522 * Unfortunately, fifo callbacks are 1 big freezer, as they run with fifo locked,
523 * and may try to revoke ticket for pauseing or other stuff.
524 * Always releasing ticket when there are callbacks is safe but inefficient.
525 * Instead, we release ticket when we are going to wait for fifo or a buffer,
526 * and of course, when the ticket has been revoked.
527 * This should melt the "put" side. We could still freeze ourselves directly
528 * at the "get" side, what ticket->revoke () self grant hack shall fix.
529 */
530 buf_element_t *buf;
531 int mode = ticket ? 2 : 0, i;
532
533 if (pthread_mutex_trylock (&fifo->mutex)) {
534 if (mode & 2) {
535 ticket->release (ticket, 0);
536 mode = 1;
537 }
538 pthread_mutex_lock (&fifo->mutex);
539 }
540
541 if (!fifo->first) {
542 if (mode & 2) {
543 ticket->release (ticket, 0);
544 mode = 1;
545 }
546 fifo->fifo_num_waiters++;
547 do {
548 pthread_cond_wait (&fifo->not_empty, &fifo->mutex);
549 } while (!fifo->first);
550 fifo->fifo_num_waiters--;
551 }
552
553 buf = fifo->first;
554
555 fifo->first = fifo->first->next;
556 if (fifo->first==NULL)
557 fifo->last = NULL;
558
559 if (buf->free_buffer == buffer_pool_free) {
560 be_ei_t *beei = (be_ei_t *)buf;
561 fifo->fifo_size -= beei->nbufs;
562 } else {
563 fifo->fifo_size -= 1;
564 }
565 fifo->fifo_data_size -= buf->size;
566
567 if ((mode & 2) && ticket->ticket_revoked) {
568 ticket->release (ticket, 0);
569 mode = 1;
570 }
571
572 for(i = 0; fifo->get_cb[i]; i++)
573 fifo->get_cb[i](fifo, buf, fifo->get_cb_data[i]);
574
575 pthread_mutex_unlock (&fifo->mutex);
576
577 if (mode & 1)
578 ticket->acquire (ticket, 0);
579
580 return buf;
581 }
582
583
584 /*
585 * clear buffer (put all contained buffer elements back into buffer pool)
586 */
fifo_buffer_clear(fifo_buffer_t * fifo)587 static void fifo_buffer_clear (fifo_buffer_t *fifo) {
588 be_ei_t *start;
589
590 pthread_mutex_lock (&fifo->mutex);
591
592 /* take out all at once */
593 start = (be_ei_t *)fifo->first;
594 fifo->first = fifo->last = NULL;
595 fifo->fifo_size = 0;
596 fifo->fifo_data_size = 0;
597
598 while (start) {
599 be_ei_t *buf, *next;
600 int n;
601
602 /* keep control bufs (flush, ...) */
603 if ((start->elem.type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE) {
604 if (!fifo->first)
605 fifo->first = &start->elem;
606 else
607 fifo->last->next = &start->elem;
608 fifo->last = &start->elem;
609 fifo->fifo_size += 1;
610 fifo->fifo_data_size += start->elem.size;
611 buf = (be_ei_t *)start->elem.next;
612 start->elem.next = NULL;
613 start = buf;
614 continue;
615 }
616
617 /* free custom buf */
618 if (start->elem.free_buffer != buffer_pool_free) {
619 buf = (be_ei_t *)start->elem.next;
620 start->elem.next = NULL;
621 start->elem.free_buffer (&start->elem);
622 start = buf;
623 continue;
624 }
625
626 /* optimize: get contiguous chunk */
627 buf = start;
628 n = 0;
629 while (1) {
630 int i = buf->nbufs;
631 next = (be_ei_t *)buf->elem.next;
632 n += i;
633 if (buf + i != next) /* includes next == NULL et al ;-) */
634 break;
635 if ((next->elem.type & BUF_MAJOR_MASK) == BUF_CONTROL_BASE)
636 break;
637 buf = next;
638 }
639 start->nbufs = n;
640 start->elem.free_buffer (&start->elem);
641 start = next;
642 }
643
644 /* printf("Free buffers after clear: %d\n", fifo->buffer_pool_num_free); */
645 pthread_mutex_unlock (&fifo->mutex);
646 }
647
fifo_buffer_all_clear(fifo_buffer_t * fifo)648 static void fifo_buffer_all_clear (fifo_buffer_t *fifo) {
649 be_ei_t *start;
650
651 pthread_mutex_lock (&fifo->mutex);
652
653 /* take out all at once */
654 start = (be_ei_t *)fifo->first;
655 fifo->first = fifo->last = NULL;
656 fifo->fifo_size = 0;
657 fifo->fifo_data_size = 0;
658
659 while (start) {
660 be_ei_t *buf, *next;
661 int n;
662
663 /* free custom buf */
664 if (start->elem.free_buffer != buffer_pool_free) {
665 buf = (be_ei_t *)start->elem.next;
666 start->elem.next = NULL;
667 start->elem.free_buffer (&start->elem);
668 start = buf;
669 continue;
670 }
671
672 /* optimize: get contiguous chunk */
673 buf = start;
674 n = 0;
675 while (1) {
676 int i = buf->nbufs;
677 next = (be_ei_t *)buf->elem.next;
678 n += i;
679 if (buf + i != next) /* includes next == NULL ;-) */
680 break;
681 buf = next;
682 }
683 /* free just sibling bufs */
684 if (start->elem.source != (void *)fifo) {
685 start->nbufs = n;
686 start->elem.free_buffer (&start->elem);
687 }
688 start = next;
689 }
690
691 pthread_mutex_unlock (&fifo->mutex);
692 }
693
694 /*
695 * Return the number of elements in the fifo buffer
696 */
fifo_buffer_size(fifo_buffer_t * this)697 static int fifo_buffer_size (fifo_buffer_t *this) {
698 int size;
699
700 pthread_mutex_lock(&this->mutex);
701 size = this->fifo_size;
702 pthread_mutex_unlock(&this->mutex);
703
704 return size;
705 }
706
707 /*
708 * Return the amount of the data in the fifo buffer
709 */
fifo_buffer_data_size(fifo_buffer_t * this)710 static uint32_t fifo_buffer_data_size (fifo_buffer_t *this) {
711 uint32_t data_size;
712
713 pthread_mutex_lock(&this->mutex);
714 data_size = this->fifo_data_size;
715 pthread_mutex_unlock(&this->mutex);
716
717 return data_size;
718 }
719
720 /*
721 * Return the number of free elements in the pool
722 */
fifo_buffer_num_free(fifo_buffer_t * this)723 static int fifo_buffer_num_free (fifo_buffer_t *this) {
724 int buffer_pool_num_free;
725
726 pthread_mutex_lock (&this->buffer_pool_mutex);
727 buffer_pool_num_free = this->buffer_pool_num_free;
728 pthread_mutex_unlock (&this->buffer_pool_mutex);
729
730 return buffer_pool_num_free;
731 }
732
733 /*
734 * Destroy the buffer
735 */
fifo_buffer_dispose(fifo_buffer_t * this)736 static void fifo_buffer_dispose (fifo_buffer_t *this) {
737 fifo_buffer_all_clear (this);
738 xine_free_aligned (this->buffer_pool_base);
739 pthread_mutex_destroy(&this->mutex);
740 pthread_cond_destroy(&this->not_empty);
741 pthread_mutex_destroy(&this->buffer_pool_mutex);
742 pthread_cond_destroy(&this->buffer_pool_cond_not_empty);
743 free (this);
744 }
745
746 /*
747 * Register an "alloc" callback
748 */
fifo_register_alloc_cb(fifo_buffer_t * this,void (* cb)(fifo_buffer_t * this,void * data_cb),void * data_cb)749 static void fifo_register_alloc_cb (fifo_buffer_t *this,
750 void (*cb)(fifo_buffer_t *this,
751 void *data_cb),
752 void *data_cb) {
753 int i;
754
755 pthread_mutex_lock(&this->mutex);
756 for(i = 0; this->alloc_cb[i]; i++)
757 ;
758 if( i != BUF_MAX_CALLBACKS-1 ) {
759 this->alloc_cb[i] = cb;
760 this->alloc_cb_data[i] = data_cb;
761 this->alloc_cb[i+1] = NULL;
762 }
763 pthread_mutex_unlock(&this->mutex);
764 }
765
766 /*
767 * Register a "put" callback
768 */
fifo_register_put_cb(fifo_buffer_t * this,void (* cb)(fifo_buffer_t * this,buf_element_t * buf,void * data_cb),void * data_cb)769 static void fifo_register_put_cb (fifo_buffer_t *this,
770 void (*cb)(fifo_buffer_t *this,
771 buf_element_t *buf,
772 void *data_cb),
773 void *data_cb) {
774 int i;
775
776 pthread_mutex_lock(&this->mutex);
777 for(i = 0; this->put_cb[i]; i++)
778 ;
779 if( i != BUF_MAX_CALLBACKS-1 ) {
780 this->put_cb[i] = cb;
781 this->put_cb_data[i] = data_cb;
782 this->put_cb[i+1] = NULL;
783 }
784 pthread_mutex_unlock(&this->mutex);
785 }
786
787 /*
788 * Register a "get" callback
789 */
fifo_register_get_cb(fifo_buffer_t * this,void (* cb)(fifo_buffer_t * this,buf_element_t * buf,void * data_cb),void * data_cb)790 static void fifo_register_get_cb (fifo_buffer_t *this,
791 void (*cb)(fifo_buffer_t *this,
792 buf_element_t *buf,
793 void *data_cb),
794 void *data_cb) {
795 int i;
796
797 pthread_mutex_lock(&this->mutex);
798 for(i = 0; this->get_cb[i]; i++)
799 ;
800 if( i != BUF_MAX_CALLBACKS-1 ) {
801 this->get_cb[i] = cb;
802 this->get_cb_data[i] = data_cb;
803 this->get_cb[i+1] = NULL;
804 }
805 pthread_mutex_unlock(&this->mutex);
806 }
807
808 /*
809 * Unregister an "alloc" callback
810 */
fifo_unregister_alloc_cb(fifo_buffer_t * this,void (* cb)(fifo_buffer_t * this,void * data_cb))811 static void fifo_unregister_alloc_cb (fifo_buffer_t *this,
812 void (*cb)(fifo_buffer_t *this,
813 void *data_cb) ) {
814 int i,j;
815
816 pthread_mutex_lock(&this->mutex);
817 for(i = 0; this->alloc_cb[i]; i++) {
818 if( this->alloc_cb[i] == cb ) {
819 for(j = i; this->alloc_cb[j]; j++) {
820 this->alloc_cb[j] = this->alloc_cb[j+1];
821 this->alloc_cb_data[j] = this->alloc_cb_data[j+1];
822 }
823 }
824 }
825 pthread_mutex_unlock(&this->mutex);
826 }
827
828 /*
829 * Unregister a "put" callback
830 */
fifo_unregister_put_cb(fifo_buffer_t * this,void (* cb)(fifo_buffer_t * this,buf_element_t * buf,void * data_cb))831 static void fifo_unregister_put_cb (fifo_buffer_t *this,
832 void (*cb)(fifo_buffer_t *this,
833 buf_element_t *buf,
834 void *data_cb) ) {
835 int i,j;
836
837 pthread_mutex_lock(&this->mutex);
838 for(i = 0; this->put_cb[i]; i++) {
839 if( this->put_cb[i] == cb ) {
840 for(j = i; this->put_cb[j]; j++) {
841 this->put_cb[j] = this->put_cb[j+1];
842 this->put_cb_data[j] = this->put_cb_data[j+1];
843 }
844 }
845 }
846 pthread_mutex_unlock(&this->mutex);
847 }
848
849 /*
850 * Unregister a "get" callback
851 */
fifo_unregister_get_cb(fifo_buffer_t * this,void (* cb)(fifo_buffer_t * this,buf_element_t * buf,void * data_cb))852 static void fifo_unregister_get_cb (fifo_buffer_t *this,
853 void (*cb)(fifo_buffer_t *this,
854 buf_element_t *buf,
855 void *data_cb) ) {
856 int i,j;
857
858 pthread_mutex_lock(&this->mutex);
859 for(i = 0; this->get_cb[i]; i++) {
860 if( this->get_cb[i] == cb ) {
861 for(j = i; this->get_cb[j]; j++) {
862 this->get_cb[j] = this->get_cb[j+1];
863 this->get_cb_data[j] = this->get_cb_data[j+1];
864 }
865 }
866 }
867 pthread_mutex_unlock(&this->mutex);
868 }
869
870 /*
871 * allocate and initialize new (empty) fifo buffer
872 */
_x_fifo_buffer_new(int num_buffers,uint32_t buf_size)873 fifo_buffer_t *_x_fifo_buffer_new (int num_buffers, uint32_t buf_size) {
874
875 fifo_buffer_t *this;
876 int i;
877 unsigned char *multi_buffer;
878 be_ei_t *beei;
879
880 this = calloc(1, sizeof(fifo_buffer_t));
881 if (!this)
882 return NULL;
883 #ifndef HAVE_ZERO_SAFE_MEM
884 /* Do these first, when compiler still knows "this" is all zeroed.
885 * Let it optimize away this on most systems where clear mem
886 * interpretes as 0, 0f or NULL safely.
887 */
888 this->first = NULL;
889 this->last = NULL;
890 this->fifo_size = 0;
891 this->fifo_num_waiters = 0;
892 this->buffer_pool_num_waiters = 0;
893 this->alloc_cb[0] = NULL;
894 this->get_cb[0] = NULL;
895 this->put_cb[0] = NULL;
896 this->alloc_cb_data[0] = NULL;
897 this->get_cb_data[0] = NULL;
898 this->put_cb_data[0] = NULL;
899 #endif
900
901 /* printf ("Allocating %d buffers of %ld bytes in one chunk\n", num_buffers, (long int) buf_size); */
902 multi_buffer = xine_mallocz_aligned (num_buffers * (buf_size + sizeof (be_ei_t)));
903 if (!multi_buffer) {
904 free (this);
905 return NULL;
906 }
907
908 this->put = fifo_buffer_put;
909 this->insert = fifo_buffer_insert;
910 this->get = fifo_buffer_get;
911 this->tget = fifo_buffer_tget;
912 this->clear = fifo_buffer_clear;
913 this->size = fifo_buffer_size;
914 this->num_free = fifo_buffer_num_free;
915 this->data_size = fifo_buffer_data_size;
916 this->dispose = fifo_buffer_dispose;
917 this->register_alloc_cb = fifo_register_alloc_cb;
918 this->register_get_cb = fifo_register_get_cb;
919 this->register_put_cb = fifo_register_put_cb;
920 this->unregister_alloc_cb = fifo_unregister_alloc_cb;
921 this->unregister_get_cb = fifo_unregister_get_cb;
922 this->unregister_put_cb = fifo_unregister_put_cb;
923 pthread_mutex_init (&this->mutex, NULL);
924 pthread_cond_init (&this->not_empty, NULL);
925
926 /* init buffer pool */
927
928 pthread_mutex_init (&this->buffer_pool_mutex, NULL);
929 pthread_cond_init (&this->buffer_pool_cond_not_empty, NULL);
930
931 this->buffer_pool_num_free =
932 this->buffer_pool_capacity = num_buffers;
933 this->buffer_pool_buf_size = buf_size;
934 this->buffer_pool_alloc = buffer_pool_alloc;
935 this->buffer_pool_try_alloc = buffer_pool_try_alloc;
936 this->buffer_pool_size_alloc = buffer_pool_size_alloc;
937 this->buffer_pool_realloc = buffer_pool_realloc;
938
939 this->buffer_pool_large_wait = LARGE_NUM;
940
941 this->buffer_pool_base = multi_buffer;
942 beei = (be_ei_t *)(multi_buffer + num_buffers * buf_size);
943 this->buffer_pool_top = &beei->elem;
944 beei->nbufs = num_buffers;
945
946 for (i = 0; i < num_buffers; i++) {
947 beei->elem.mem = multi_buffer;
948 multi_buffer += buf_size;
949 beei->elem.max_size = buf_size;
950 beei->elem.free_buffer = buffer_pool_free;
951 beei->elem.source = this;
952 beei->elem.extra_info = &beei->ei;
953 beei->elem.next = &(beei + 1)->elem;
954 beei++;
955 }
956
957 (beei - 1)->elem.next = NULL;
958
959 return this;
960 }
961
962 /*
963 * allocate and initialize new (empty) fifo buffer
964 */
_x_dummy_fifo_buffer_new(int num_buffers,uint32_t buf_size)965 fifo_buffer_t *_x_dummy_fifo_buffer_new (int num_buffers, uint32_t buf_size) {
966 fifo_buffer_t *this = _x_fifo_buffer_new (num_buffers, buf_size);
967 if (this) {
968 this->put = dummy_fifo_buffer_put;
969 this->insert = dummy_fifo_buffer_insert;
970 }
971 return this;
972 }
973
_x_free_buf_elements(buf_element_t * head)974 void _x_free_buf_elements(buf_element_t *head) {
975
976 if (head) {
977 buf_element_t *cur, *next;
978
979 cur = head;
980 while (cur) {
981 next = cur->next;
982 cur->free_buffer(cur);
983 cur = next;
984 }
985 }
986 }
987
988