summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/buffering.c90
1 files changed, 47 insertions, 43 deletions
diff --git a/apps/buffering.c b/apps/buffering.c
index 14db47bb91..9bc5abd963 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -434,11 +434,7 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
434{ 434{
435 struct memory_handle *dest; 435 struct memory_handle *dest;
436 const struct memory_handle *src; 436 const struct memory_handle *src;
437 int32_t *here; 437 size_t final_delta = *delta, size_to_move;
438 int32_t *there;
439 int32_t *end;
440 int32_t *begin;
441 size_t final_delta = *delta, size_to_move, n;
442 uintptr_t oldpos, newpos; 438 uintptr_t oldpos, newpos;
443 intptr_t overlap, overlap_old; 439 intptr_t overlap, overlap_old;
444 440
@@ -454,17 +450,14 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
454 return false; 450 return false;
455 } 451 }
456 452
457 mutex_lock(&llist_mutex);
458 mutex_lock(&llist_mod_mutex);
459
460 oldpos = ringbuf_offset(src); 453 oldpos = ringbuf_offset(src);
461 newpos = ringbuf_add(oldpos, final_delta); 454 newpos = ringbuf_add(oldpos, final_delta);
462 overlap = ringbuf_add_cross(newpos, size_to_move, buffer_len - 1); 455 overlap = ringbuf_add_cross(newpos, size_to_move, buffer_len);
463 overlap_old = ringbuf_add_cross(oldpos, size_to_move, buffer_len -1); 456 overlap_old = ringbuf_add_cross(oldpos, size_to_move, buffer_len);
464 457
465 if (overlap > 0) { 458 if (overlap > 0) {
466 /* Some part of the struct + data would wrap, maybe ok */ 459 /* Some part of the struct + data would wrap, maybe ok */
467 size_t correction = 0; 460 ssize_t correction = 0;
468 /* If the overlap lands inside the memory_handle */ 461 /* If the overlap lands inside the memory_handle */
469 if (!can_wrap) { 462 if (!can_wrap) {
470 /* Otherwise the overlap falls in the data area and must all be 463 /* Otherwise the overlap falls in the data area and must all be
@@ -473,7 +466,8 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
473 correction = overlap; 466 correction = overlap;
474 } else if ((uintptr_t)overlap > data_size) { 467 } else if ((uintptr_t)overlap > data_size) {
475 /* Correct the position and real delta to prevent the struct from 468 /* Correct the position and real delta to prevent the struct from
476 * wrapping, this guarantees an aligned delta, I think */ 469 * wrapping, this guarantees an aligned delta if the struct size is
470 * aligned and the buffer is aligned */
477 correction = overlap - data_size; 471 correction = overlap - data_size;
478 } 472 }
479 if (correction) { 473 if (correction) {
@@ -481,8 +475,6 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
481 correction = (correction + 3) & ~3; 475 correction = (correction + 3) & ~3;
482 if (final_delta < correction + sizeof(struct memory_handle)) { 476 if (final_delta < correction + sizeof(struct memory_handle)) {
483 /* Delta cannot end up less than the size of the struct */ 477 /* Delta cannot end up less than the size of the struct */
484 mutex_unlock(&llist_mod_mutex);
485 mutex_unlock(&llist_mutex);
486 return false; 478 return false;
487 } 479 }
488 newpos -= correction; 480 newpos -= correction;
@@ -504,13 +496,10 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
504 if (m && m->next == src) { 496 if (m && m->next == src) {
505 m->next = dest; 497 m->next = dest;
506 } else { 498 } else {
507 mutex_unlock(&llist_mod_mutex);
508 mutex_unlock(&llist_mutex);
509 return false; 499 return false;
510 } 500 }
511 } 501 }
512 502
513
514 /* Update the cache to prevent it from keeping the old location of h */ 503 /* Update the cache to prevent it from keeping the old location of h */
515 if (src == cached_handle) 504 if (src == cached_handle)
516 cached_handle = dest; 505 cached_handle = dest;
@@ -519,39 +508,54 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
519 if (src == cur_handle) 508 if (src == cur_handle)
520 cur_handle = dest; 509 cur_handle = dest;
521 510
511 /* x = handle(s) following this one...
512 * ...if last handle, unmoveable if metadata, only shrinkable if audio.
513 * In other words, no legal move can be made that would have the src head
514 * and dest tail of the data overlap itself. These facts reduce the
515 * problem to four essential permutations.
516 *
517 * movement: always "clockwise" >>>>
518 *
519 * (src nowrap, dest nowrap)
520 * |0123 x |
521 * | 0123x | etc...
522 * move: "0123"
523 *
524 * (src nowrap, dest wrap)
525 * | x0123 |
526 * |23x 01|
527 * move: "23", "01"
528 *
529 * (src wrap, dest nowrap)
530 * |23 x01|
531 * | 0123x |
532 * move: "23", "01"
533 *
534 * (src wrap, dest wrap)
535 * |23 x 01|
536 * |123x 0|
537 * move: "23", "1", "0"
538 */
539 if (overlap_old > 0) {
540 /* Move over already wrapped data by the final delta */
541 memmove(&buffer[final_delta], buffer, overlap_old);
542 if (overlap <= 0)
543 size_to_move -= overlap_old;
544 }
522 545
523 /* Copying routine takes into account that the handles have a 546 if (overlap > 0) {
524 * distance between each other which is a multiple of four. Faster 2 word 547 /* Move data that now wraps to the beginning */
525 * copy may be ok but do this for safety and because wrapped copies should 548 size_to_move -= overlap;
526 * be fairly uncommon */ 549 memmove(buffer, SKIPBYTES(src, size_to_move),
527 550 overlap_old > 0 ? final_delta : (size_t)overlap);
528 here = (int32_t *)((ringbuf_add(oldpos, size_to_move - 1) & ~3)+ (intptr_t)buffer);
529 there =(int32_t *)((ringbuf_add(newpos, size_to_move - 1) & ~3)+ (intptr_t)buffer);
530 end = (int32_t *)(( intptr_t)buffer + buffer_len - 4);
531 begin =(int32_t *)buffer;
532
533 n = (size_to_move & ~3)/4;
534
535 if ( overlap_old > 0 || overlap > 0 ) {
536 /* Old or moved handle wraps */
537 while (n--) {
538 if (here < begin)
539 here = end;
540 if (there < begin)
541 there = end;
542 *there-- = *here--;
543 }
544 } else {
545 /* both handles do not wrap */
546 memmove(dest,src,size_to_move);
547 } 551 }
548 552
553 /* Move leading fragment containing handle struct */
554 memmove(dest, src, size_to_move);
549 555
550 /* Update the caller with the new location of h and the distance moved */ 556 /* Update the caller with the new location of h and the distance moved */
551 *h = dest; 557 *h = dest;
552 *delta = final_delta; 558 *delta = final_delta;
553 mutex_unlock(&llist_mod_mutex);
554 mutex_unlock(&llist_mutex);
555 return true; 559 return true;
556} 560}
557 561