diff options
Diffstat (limited to 'apps/buffering.c')
-rw-r--r-- | apps/buffering.c | 89 |
1 files changed, 46 insertions, 43 deletions
diff --git a/apps/buffering.c b/apps/buffering.c index e80dc79b54..79144e78db 100644 --- a/apps/buffering.c +++ b/apps/buffering.c | |||
@@ -403,10 +403,17 @@ static bool move_handle(struct memory_handle **h, size_t *delta, | |||
403 | { | 403 | { |
404 | struct memory_handle *dest; | 404 | struct memory_handle *dest; |
405 | const struct memory_handle *src; | 405 | const struct memory_handle *src; |
406 | int32_t *here; | ||
407 | int32_t *there; | ||
408 | int32_t *end; | ||
409 | int32_t *begin; | ||
410 | size_t oldpos; | ||
406 | size_t newpos; | 411 | size_t newpos; |
407 | size_t size_to_move; | 412 | size_t size_to_move; |
408 | size_t final_delta = *delta; | 413 | size_t final_delta = *delta; |
414 | size_t n; | ||
409 | int overlap; | 415 | int overlap; |
416 | int overlap_old; | ||
410 | 417 | ||
411 | if (h == NULL || (src = *h) == NULL) | 418 | if (h == NULL || (src = *h) == NULL) |
412 | return false; | 419 | return false; |
@@ -423,33 +430,34 @@ static bool move_handle(struct memory_handle **h, size_t *delta, | |||
423 | mutex_lock(&llist_mutex); | 430 | mutex_lock(&llist_mutex); |
424 | mutex_lock(&llist_mod_mutex); | 431 | mutex_lock(&llist_mod_mutex); |
425 | 432 | ||
426 | newpos = RINGBUF_ADD((void *)src - (void *)buffer, final_delta); | 433 | oldpos = (void *)src - (void *)buffer; |
434 | newpos = RINGBUF_ADD(oldpos, final_delta); | ||
427 | overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1); | 435 | overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1); |
436 | overlap_old = RINGBUF_ADD_CROSS(oldpos, size_to_move, buffer_len -1); | ||
428 | 437 | ||
429 | if (overlap > 0) { | 438 | if (overlap > 0) { |
430 | /* Some part of the struct + data would wrap, maybe ok */ | 439 | /* Some part of the struct + data would wrap, maybe ok */ |
431 | size_t correction = 0; | 440 | size_t correction = 0; |
432 | /* If the overlap lands inside the memory_handle */ | 441 | /* If the overlap lands inside the memory_handle */ |
433 | if ((unsigned)overlap > data_size) { | 442 | if (!can_wrap) { |
434 | /* Correct the position and real delta to prevent the struct from | ||
435 | * wrapping, this guarantees an aligned delta, I think */ | ||
436 | correction = overlap - data_size; | ||
437 | } else if (!can_wrap) { | ||
438 | /* Otherwise the overlap falls in the data area and must all be | 443 | /* Otherwise the overlap falls in the data area and must all be |
439 | * backed out. This may become conditional if ever we move | 444 | * backed out. This may become conditional if ever we move |
440 | * data that is allowed to wrap (ie audio) */ | 445 | * data that is allowed to wrap (ie audio) */ |
441 | correction = overlap; | 446 | correction = overlap; |
442 | /* Align correction to four bytes, up */ | 447 | } else if ((unsigned)overlap > data_size) { |
443 | correction = (correction+3) & ~3; | 448 | /* Correct the position and real delta to prevent the struct from |
449 | * wrapping, this guarantees an aligned delta, I think */ | ||
450 | correction = overlap - data_size; | ||
444 | } | 451 | } |
445 | if (correction) { | 452 | if (correction) { |
453 | /* Align correction to four bytes up */ | ||
454 | correction = (correction + 3) & ~3; | ||
446 | if (final_delta < correction + sizeof(struct memory_handle)) { | 455 | if (final_delta < correction + sizeof(struct memory_handle)) { |
447 | /* Delta cannot end up less than the size of the struct */ | 456 | /* Delta cannot end up less than the size of the struct */ |
448 | mutex_unlock(&llist_mod_mutex); | 457 | mutex_unlock(&llist_mod_mutex); |
449 | mutex_unlock(&llist_mutex); | 458 | mutex_unlock(&llist_mutex); |
450 | return false; | 459 | return false; |
451 | } | 460 | } |
452 | |||
453 | newpos -= correction; | 461 | newpos -= correction; |
454 | overlap -= correction;/* Used below to know how to split the data */ | 462 | overlap -= correction;/* Used below to know how to split the data */ |
455 | final_delta -= correction; | 463 | final_delta -= correction; |
@@ -484,38 +492,33 @@ static bool move_handle(struct memory_handle **h, size_t *delta, | |||
484 | if (src == cur_handle) | 492 | if (src == cur_handle) |
485 | cur_handle = dest; | 493 | cur_handle = dest; |
486 | 494 | ||
487 | if (overlap > 0) { | 495 | |
488 | /* FIXME : this code is broken and can leave the data corrupted when | 496 | /* Copying routine takes into account that the handles have a |
489 | * the amount of data to move is close to the whole buffer size. | 497 | * distance between each other which is a multiple of four. Faster 2 word |
490 | * | 498 | * copy may be ok but do this for safety and because wrapped copies should |
491 | * Example : ('S' is the source data, '-' is empty buffer) | 499 | * be fairly uncommon */ |
492 | * Size of the buffer is 8 bytes, starts at 0. | 500 | |
493 | * Size of the data to move is 7 bytes. | 501 | here = (int32_t *)((RINGBUF_ADD(oldpos, size_to_move - 1) & ~3)+ (intptr_t)buffer); |
494 | * | 502 | there =(int32_t *)((RINGBUF_ADD(newpos, size_to_move - 1) & ~3)+ (intptr_t)buffer); |
495 | * -SSSSSSS | 503 | end = (int32_t *)(( intptr_t)buffer + buffer_len - 4); |
496 | * ^-------- start of source data == 1 | 504 | begin =(int32_t *)buffer; |
497 | * | 505 | |
498 | * DD-DDDDD ('D' is desired destination data) | 506 | n = (size_to_move & ~3)/4; |
499 | * ^------ start of destination data == 3 | 507 | |
500 | * | 508 | if ( overlap_old > 0 || overlap > 0 ) { |
501 | * memmove(3, 1, 5); | 509 | /* Old or moved handle wraps */ |
502 | * memmove(0, 7, 2); | 510 | while (n--) { |
503 | * | 511 | if (here < begin) |
504 | * First memmove() call will leave the buffer in this state: | 512 | here = end; |
505 | * | 513 | if (there < begin) |
506 | * -SSDDDDD | 514 | there = end; |
507 | * ^^ | 515 | *there-- = *here--; |
508 | * \--- data to be moved by the second memmove() call, but | 516 | } |
509 | * overwritten by the first call. | ||
510 | * | ||
511 | * See FS#10605 for more details | ||
512 | */ | ||
513 | size_t first_part = size_to_move - overlap; | ||
514 | memmove(dest, src, first_part); | ||
515 | memmove(buffer, (const char *)src + first_part, overlap); | ||
516 | } else { | 517 | } else { |
517 | memmove(dest, src, size_to_move); | 518 | /* both handles do not wrap */ |
518 | } | 519 | memmove(dest,src,size_to_move); |
520 | } | ||
521 | |||
519 | 522 | ||
520 | /* Update the caller with the new location of h and the distance moved */ | 523 | /* Update the caller with the new location of h and the distance moved */ |
521 | *h = dest; | 524 | *h = dest; |
@@ -641,10 +644,10 @@ static bool buffer_handle(int handle_id) | |||
641 | if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0) | 644 | if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0) |
642 | return false; | 645 | return false; |
643 | 646 | ||
644 | /* This would read into the next handle, this is broken */ | 647 | /* This would read into the next handle, this is broken |
645 | if (h->next && RINGBUF_ADD_CROSS(h->widx, copy_n, | 648 | if (h->next && RINGBUF_ADD_CROSS(h->widx, copy_n, |
646 | (unsigned)((void *)h->next - (void *)buffer)) > 0) { | 649 | (unsigned)((void *)h->next - (void *)buffer)) > 0) { |
647 | /* Try to recover by truncating this file */ | 650 | Try to recover by truncating this file |
648 | copy_n = RINGBUF_ADD_CROSS(h->widx, copy_n, | 651 | copy_n = RINGBUF_ADD_CROSS(h->widx, copy_n, |
649 | (unsigned)((void *)h->next - (void *)buffer)); | 652 | (unsigned)((void *)h->next - (void *)buffer)); |
650 | h->filerem -= copy_n; | 653 | h->filerem -= copy_n; |
@@ -654,7 +657,7 @@ static bool buffer_handle(int handle_id) | |||
654 | continue; | 657 | continue; |
655 | else | 658 | else |
656 | break; | 659 | break; |
657 | } | 660 | } */ |
658 | 661 | ||
659 | /* rc is the actual amount read */ | 662 | /* rc is the actual amount read */ |
660 | int rc = read(h->fd, &buffer[h->widx], copy_n); | 663 | int rc = read(h->fd, &buffer[h->widx], copy_n); |