summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/buffering.c62
1 files changed, 37 insertions, 25 deletions
diff --git a/apps/buffering.c b/apps/buffering.c
index dd08b6ce78..35e47fe51e 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -377,37 +377,43 @@ static struct memory_handle *find_handle(const unsigned int handle_id)
377 return m; 377 return m;
378} 378}
379 379
380/* Move a memory handle and data_size of its data of delta. 380/* Move a memory handle and data_size of its data delta bytes along the buffer.
381 Return a pointer to the new location of the handle (null if it hasn't moved). 381 delta maximum bytes available to move the handle. If the move is performed
382 delta is the value of which to move the struct data, modified to the actual 382 it is set to the actual distance moved.
383 distance moved. 383 data_size is the amount of data to move along with the struct.
384 data_size is the amount of data to move along with the struct. */ 384 returns a valid memory_handle if the move is successful
385 NULL if the handle is NULL, the move would be less than the size of
386 a memory_handle after correcting for wraps or if the handle is not
387 found in the linked list for adjustment. This function has no side
388 effects if NULL is returned. */
385static struct memory_handle *move_handle(const struct memory_handle *h, 389static struct memory_handle *move_handle(const struct memory_handle *h,
386 size_t *delta, const size_t data_size) 390 size_t *delta, const size_t data_size)
387{ 391{
388 struct memory_handle *dest; 392 struct memory_handle *dest;
389 size_t newpos; 393 size_t newpos;
390 size_t size_to_move; 394 size_t size_to_move;
395 size_t new_delta = *delta;
391 int overlap; 396 int overlap;
392 397
393 if (*delta < sizeof(struct memory_handle)) { 398 if (h == NULL)
394 /* It's not worth trying to move such a short distance, and it would
395 * complicate the overlap calculations below */
396 return NULL; 399 return NULL;
397 }
398
399 mutex_lock(&llist_mutex);
400 400
401 size_to_move = sizeof(struct memory_handle) + data_size; 401 size_to_move = sizeof(struct memory_handle) + data_size;
402 402
403 /* Align to four bytes, down */ 403 /* Align to four bytes, down */
404 *delta &= ~3; 404 new_delta &= ~3;
405 newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta); 405 if (new_delta < sizeof(struct memory_handle)) {
406 /* It's not legal to move less than the size of the struct */
407 return NULL;
408 }
409
410 mutex_lock(&llist_mutex);
411
412 newpos = RINGBUF_ADD((void *)h - (void *)buffer, new_delta);
406 overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1); 413 overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1);
407 414
408 /* This means that moving the data will put it on the wrap */
409 if (overlap > 0) { 415 if (overlap > 0) {
410 /* This means that the memory_handle struct would wrap */ 416 /* Some part of the struct + data would wrap, maybe ok */
411 size_t correction; 417 size_t correction;
412 /* If the overlap lands inside the memory_handle */ 418 /* If the overlap lands inside the memory_handle */
413 if ((unsigned)overlap > data_size) { 419 if ((unsigned)overlap > data_size) {
@@ -415,19 +421,22 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
415 * wrapping, this guarantees an aligned delta, I think */ 421 * wrapping, this guarantees an aligned delta, I think */
416 correction = overlap - data_size; 422 correction = overlap - data_size;
417 } else { 423 } else {
418 /* Otherwise it falls in the data area and must all be backed out */ 424 /* Otherwise the overlap falls in the data area and must all be
425 * backed out. This may become conditional if ever we move
426 * data that is allowed to wrap (ie audio) */
419 correction = overlap; 427 correction = overlap;
420 /* Align to four bytes, up */ 428 /* Align correction to four bytes, up */
421 correction = (correction+3) & ~3; 429 correction = (correction+3) & ~3;
422 if (*delta <= correction) {
423 /* After correcting, no movement (or, impossibly, backwards) */
424 mutex_unlock(&llist_mutex);
425 return NULL;
426 }
427 } 430 }
431 if (new_delta < correction + sizeof(struct memory_handle)) {
432 /* Delta cannot end up less than the size of the struct */
433 mutex_unlock(&llist_mutex);
434 return NULL;
435 }
436
428 newpos -= correction; 437 newpos -= correction;
429 overlap -= correction; 438 overlap -= correction; /* Used below to know how to split the data */
430 *delta -= correction; 439 new_delta -= correction;
431 } 440 }
432 441
433 dest = (struct memory_handle *)(&buffer[newpos]); 442 dest = (struct memory_handle *)(&buffer[newpos]);
@@ -440,7 +449,7 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
440 while (m && m->next != h) { 449 while (m && m->next != h) {
441 m = m->next; 450 m = m->next;
442 } 451 }
443 if (h && m && m->next == h) { 452 if (m && m->next == h) {
444 m->next = dest; 453 m->next = dest;
445 } else { 454 } else {
446 mutex_unlock(&llist_mutex); 455 mutex_unlock(&llist_mutex);
@@ -448,6 +457,9 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
448 } 457 }
449 } 458 }
450 459
460 /* All checks pass, update the caller with how far we're moving */
461 *delta = new_delta;
462
451 /* Update the cache to prevent it from keeping the old location of h */ 463 /* Update the cache to prevent it from keeping the old location of h */
452 if (h == cached_handle) 464 if (h == cached_handle)
453 cached_handle = dest; 465 cached_handle = dest;