diff options
Diffstat (limited to 'apps/buffering.c')
-rw-r--r-- | apps/buffering.c | 90 |
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 | ||