forked from len0rd/rockbox
Remove can_add_handle, its safety and benefit are both questionable. Make shrink_buffer a function to reduce code duplication. Change move_handle semantics so that the caller never loses track of the current position of h, even if the move fails.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15362 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
30d3d36513
commit
483dca99c4
1 changed files with 43 additions and 69 deletions
110
apps/buffering.c
110
apps/buffering.c
|
@ -386,30 +386,31 @@ static struct memory_handle *find_handle(const unsigned int handle_id)
|
||||||
a memory_handle after correcting for wraps or if the handle is not
|
a memory_handle after correcting for wraps or if the handle is not
|
||||||
found in the linked list for adjustment. This function has no side
|
found in the linked list for adjustment. This function has no side
|
||||||
effects if NULL is returned. */
|
effects if NULL is returned. */
|
||||||
static struct memory_handle *move_handle(const struct memory_handle *h,
|
static bool move_handle(struct memory_handle const **h,
|
||||||
size_t *delta, const size_t data_size)
|
size_t *delta, const size_t data_size)
|
||||||
{
|
{
|
||||||
struct memory_handle *dest;
|
struct memory_handle *dest;
|
||||||
|
const struct memory_handle *src;
|
||||||
size_t newpos;
|
size_t newpos;
|
||||||
size_t size_to_move;
|
size_t size_to_move;
|
||||||
size_t new_delta = *delta;
|
size_t final_delta = *delta;
|
||||||
int overlap;
|
int overlap;
|
||||||
|
|
||||||
if (h == NULL)
|
if (h == NULL || (src = *h) == NULL)
|
||||||
return NULL;
|
return false;
|
||||||
|
|
||||||
size_to_move = sizeof(struct memory_handle) + data_size;
|
size_to_move = sizeof(struct memory_handle) + data_size;
|
||||||
|
|
||||||
/* Align to four bytes, down */
|
/* Align to four bytes, down */
|
||||||
new_delta &= ~3;
|
final_delta &= ~3;
|
||||||
if (new_delta < sizeof(struct memory_handle)) {
|
if (final_delta < sizeof(struct memory_handle)) {
|
||||||
/* It's not legal to move less than the size of the struct */
|
/* It's not legal to move less than the size of the struct */
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&llist_mutex);
|
mutex_lock(&llist_mutex);
|
||||||
|
|
||||||
newpos = RINGBUF_ADD((void *)h - (void *)buffer, new_delta);
|
newpos = RINGBUF_ADD((void *)src - (void *)buffer, final_delta);
|
||||||
overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1);
|
overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1);
|
||||||
|
|
||||||
if (overlap > 0) {
|
if (overlap > 0) {
|
||||||
|
@ -428,54 +429,55 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
|
||||||
/* Align correction to four bytes, up */
|
/* Align correction to four bytes, up */
|
||||||
correction = (correction+3) & ~3;
|
correction = (correction+3) & ~3;
|
||||||
}
|
}
|
||||||
if (new_delta < correction + sizeof(struct memory_handle)) {
|
if (final_delta < correction + sizeof(struct memory_handle)) {
|
||||||
/* Delta cannot end up less than the size of the struct */
|
/* Delta cannot end up less than the size of the struct */
|
||||||
mutex_unlock(&llist_mutex);
|
mutex_unlock(&llist_mutex);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
newpos -= correction;
|
newpos -= correction;
|
||||||
overlap -= correction; /* Used below to know how to split the data */
|
overlap -= correction; /* Used below to know how to split the data */
|
||||||
new_delta -= correction;
|
final_delta -= correction;
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = (struct memory_handle *)(&buffer[newpos]);
|
dest = (struct memory_handle *)(&buffer[newpos]);
|
||||||
|
|
||||||
if (h == first_handle) {
|
if (src == first_handle) {
|
||||||
first_handle = dest;
|
first_handle = dest;
|
||||||
buf_ridx = newpos;
|
buf_ridx = newpos;
|
||||||
} else {
|
} else {
|
||||||
struct memory_handle *m = first_handle;
|
struct memory_handle *m = first_handle;
|
||||||
while (m && m->next != h) {
|
while (m && m->next != src) {
|
||||||
m = m->next;
|
m = m->next;
|
||||||
}
|
}
|
||||||
if (m && m->next == h) {
|
if (m && m->next == src) {
|
||||||
m->next = dest;
|
m->next = dest;
|
||||||
} else {
|
} else {
|
||||||
mutex_unlock(&llist_mutex);
|
mutex_unlock(&llist_mutex);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All checks pass, update the caller with how far we're moving */
|
|
||||||
*delta = new_delta;
|
|
||||||
|
|
||||||
/* Update the cache to prevent it from keeping the old location of h */
|
/* Update the cache to prevent it from keeping the old location of h */
|
||||||
if (h == cached_handle)
|
if (src == cached_handle)
|
||||||
cached_handle = dest;
|
cached_handle = dest;
|
||||||
|
|
||||||
/* the cur_handle pointer might need updating */
|
/* the cur_handle pointer might need updating */
|
||||||
if (h == cur_handle)
|
if (src == cur_handle)
|
||||||
cur_handle = dest;
|
cur_handle = dest;
|
||||||
|
|
||||||
if (overlap > 0) {
|
if (overlap > 0) {
|
||||||
size_t first_part = size_to_move - overlap;
|
size_t first_part = size_to_move - overlap;
|
||||||
memmove(dest, h, first_part);
|
memmove(dest, src, first_part);
|
||||||
memmove(buffer, (char *)h + first_part, overlap);
|
memmove(buffer, (char *)src + first_part, overlap);
|
||||||
} else {
|
} else {
|
||||||
memmove(dest, h, size_to_move);
|
memmove(dest, src, size_to_move);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update the caller with the new location of h and the distance moved */
|
||||||
|
*h = dest;
|
||||||
|
*delta = final_delta;
|
||||||
mutex_unlock(&llist_mutex);
|
mutex_unlock(&llist_mutex);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -683,8 +685,8 @@ static void shrink_handle(int handle_id)
|
||||||
delta = handle_distance - h->available;
|
delta = handle_distance - h->available;
|
||||||
|
|
||||||
/* The value of delta might change for alignment reasons */
|
/* The value of delta might change for alignment reasons */
|
||||||
h = move_handle(h, &delta, h->available);
|
if (!move_handle(&h, &delta, h->available))
|
||||||
if (!h) return;
|
return;
|
||||||
|
|
||||||
size_t olddata = h->data;
|
size_t olddata = h->data;
|
||||||
h->data = RINGBUF_ADD(h->data, delta);
|
h->data = RINGBUF_ADD(h->data, delta);
|
||||||
|
@ -702,8 +704,8 @@ static void shrink_handle(int handle_id)
|
||||||
{
|
{
|
||||||
/* only move the handle struct */
|
/* only move the handle struct */
|
||||||
delta = RINGBUF_SUB(h->ridx, h->data);
|
delta = RINGBUF_SUB(h->ridx, h->data);
|
||||||
h = move_handle(h, &delta, 0);
|
if (!move_handle(&h, &delta, 0))
|
||||||
if (!h) return;
|
return;
|
||||||
|
|
||||||
h->data = RINGBUF_ADD(h->data, delta);
|
h->data = RINGBUF_ADD(h->data, delta);
|
||||||
h->available -= delta;
|
h->available -= delta;
|
||||||
|
@ -733,26 +735,6 @@ static void fill_buffer(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check whether it's safe to add a new handle and reserve space to let the
|
|
||||||
current one finish buffering its data. Used by bufopen and bufalloc as
|
|
||||||
a preliminary check before even trying to physically add the handle.
|
|
||||||
Returns true if it's ok to add a new handle, false if not.
|
|
||||||
*/
|
|
||||||
static bool can_add_handle(void)
|
|
||||||
{
|
|
||||||
/* the current handle hasn't finished buffering. We can only add
|
|
||||||
a new one if there is already enough free space to finish
|
|
||||||
the buffering. */
|
|
||||||
if (cur_handle && cur_handle->filerem > 0) {
|
|
||||||
size_t minimum_space =
|
|
||||||
cur_handle->filerem + sizeof(struct memory_handle );
|
|
||||||
if (RINGBUF_ADD_CROSS(cur_handle->widx, minimum_space, buf_ridx) >= 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_data_counters(void)
|
void update_data_counters(void)
|
||||||
{
|
{
|
||||||
struct memory_handle *m = find_handle(base_handle_id);
|
struct memory_handle *m = find_handle(base_handle_id);
|
||||||
|
@ -802,9 +784,6 @@ management functions for all the actual handle management work.
|
||||||
*/
|
*/
|
||||||
int bufopen(const char *file, size_t offset, enum data_type type)
|
int bufopen(const char *file, size_t offset, enum data_type type)
|
||||||
{
|
{
|
||||||
if (!can_add_handle())
|
|
||||||
return ERR_BUFFER_FULL;
|
|
||||||
|
|
||||||
int fd = open(file, O_RDONLY);
|
int fd = open(file, O_RDONLY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return ERR_FILE_ERROR;
|
return ERR_FILE_ERROR;
|
||||||
|
@ -853,9 +832,6 @@ int bufopen(const char *file, size_t offset, enum data_type type)
|
||||||
*/
|
*/
|
||||||
int bufalloc(const void *src, size_t size, enum data_type type)
|
int bufalloc(const void *src, size_t size, enum data_type type)
|
||||||
{
|
{
|
||||||
if (!can_add_handle())
|
|
||||||
return ERR_BUFFER_FULL;
|
|
||||||
|
|
||||||
struct memory_handle *h = add_handle(size, false, true);
|
struct memory_handle *h = add_handle(size, false, true);
|
||||||
|
|
||||||
if (!h)
|
if (!h)
|
||||||
|
@ -1141,6 +1117,16 @@ static void call_buffer_low_callbacks(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void shrink_buffer(bool audio, bool other) {
|
||||||
|
/* shrink selected buffers */
|
||||||
|
struct memory_handle *m = first_handle;
|
||||||
|
while (m) {
|
||||||
|
if ((m->type==TYPE_AUDIO && audio) || (m->type!=TYPE_AUDIO && other))
|
||||||
|
shrink_handle(m->id);
|
||||||
|
m = m->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void buffering_thread(void)
|
void buffering_thread(void)
|
||||||
{
|
{
|
||||||
struct queue_event ev;
|
struct queue_event ev;
|
||||||
|
@ -1231,22 +1217,10 @@ void buffering_thread(void)
|
||||||
if (data_counters.remaining > 0 &&
|
if (data_counters.remaining > 0 &&
|
||||||
data_counters.wasted > data_counters.buffered/2)
|
data_counters.wasted > data_counters.buffered/2)
|
||||||
{
|
{
|
||||||
/* free buffer from outdated audio data */
|
/* First work forward, shrinking any unmoveable handles */
|
||||||
struct memory_handle *m = first_handle;
|
shrink_buffer(true,false);
|
||||||
while (m) {
|
/* Then work forward following those up with moveable handles */
|
||||||
if (m->type == TYPE_AUDIO)
|
shrink_buffer(false,true);
|
||||||
shrink_handle(m->id);
|
|
||||||
m = m->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free buffer by moving metadata */
|
|
||||||
m = first_handle;
|
|
||||||
while (m) {
|
|
||||||
if (m->type != TYPE_AUDIO)
|
|
||||||
shrink_handle(m->id);
|
|
||||||
m = m->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_data_counters();
|
update_data_counters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue