forked from len0rd/rockbox
Improve move_handle's semantics. Shoudl have no functional impact
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15351 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
94b133ad33
commit
4feab10a0c
1 changed files with 37 additions and 25 deletions
|
|
@ -377,37 +377,43 @@ static struct memory_handle *find_handle(const unsigned int handle_id)
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move a memory handle and data_size of its data of delta.
|
/* Move a memory handle and data_size of its data delta bytes along the buffer.
|
||||||
Return a pointer to the new location of the handle (null if it hasn't moved).
|
delta maximum bytes available to move the handle. If the move is performed
|
||||||
delta is the value of which to move the struct data, modified to the actual
|
it is set to the actual distance moved.
|
||||||
distance moved.
|
data_size is the amount of data to move along with the struct.
|
||||||
data_size is the amount of data to move along with the struct. */
|
returns a valid memory_handle if the move is successful
|
||||||
|
NULL if the handle is NULL, the move would be less than the size of
|
||||||
|
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
|
||||||
|
effects if NULL is returned. */
|
||||||
static struct memory_handle *move_handle(const struct memory_handle *h,
|
static struct memory_handle *move_handle(const struct memory_handle *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;
|
||||||
size_t newpos;
|
size_t newpos;
|
||||||
size_t size_to_move;
|
size_t size_to_move;
|
||||||
|
size_t new_delta = *delta;
|
||||||
int overlap;
|
int overlap;
|
||||||
|
|
||||||
if (*delta < sizeof(struct memory_handle)) {
|
if (h == NULL)
|
||||||
/* It's not worth trying to move such a short distance, and it would
|
return NULL;
|
||||||
* complicate the overlap calculations below */
|
|
||||||
|
size_to_move = sizeof(struct memory_handle) + data_size;
|
||||||
|
|
||||||
|
/* Align to four bytes, down */
|
||||||
|
new_delta &= ~3;
|
||||||
|
if (new_delta < sizeof(struct memory_handle)) {
|
||||||
|
/* It's not legal to move less than the size of the struct */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&llist_mutex);
|
mutex_lock(&llist_mutex);
|
||||||
|
|
||||||
size_to_move = sizeof(struct memory_handle) + data_size;
|
newpos = RINGBUF_ADD((void *)h - (void *)buffer, new_delta);
|
||||||
|
|
||||||
/* Align to four bytes, down */
|
|
||||||
*delta &= ~3;
|
|
||||||
newpos = RINGBUF_ADD((void *)h - (void *)buffer, *delta);
|
|
||||||
overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1);
|
overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1);
|
||||||
|
|
||||||
/* This means that moving the data will put it on the wrap */
|
|
||||||
if (overlap > 0) {
|
if (overlap > 0) {
|
||||||
/* This means that the memory_handle struct would wrap */
|
/* Some part of the struct + data would wrap, maybe ok */
|
||||||
size_t correction;
|
size_t correction;
|
||||||
/* If the overlap lands inside the memory_handle */
|
/* If the overlap lands inside the memory_handle */
|
||||||
if ((unsigned)overlap > data_size) {
|
if ((unsigned)overlap > data_size) {
|
||||||
|
|
@ -415,19 +421,22 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
|
||||||
* wrapping, this guarantees an aligned delta, I think */
|
* wrapping, this guarantees an aligned delta, I think */
|
||||||
correction = overlap - data_size;
|
correction = overlap - data_size;
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise it falls in the data area and must all be backed out */
|
/* Otherwise the overlap falls in the data area and must all be
|
||||||
|
* backed out. This may become conditional if ever we move
|
||||||
|
* data that is allowed to wrap (ie audio) */
|
||||||
correction = overlap;
|
correction = overlap;
|
||||||
/* Align to four bytes, up */
|
/* Align correction to four bytes, up */
|
||||||
correction = (correction+3) & ~3;
|
correction = (correction+3) & ~3;
|
||||||
if (*delta <= correction) {
|
|
||||||
/* After correcting, no movement (or, impossibly, backwards) */
|
|
||||||
mutex_unlock(&llist_mutex);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (new_delta < correction + sizeof(struct memory_handle)) {
|
||||||
|
/* Delta cannot end up less than the size of the struct */
|
||||||
|
mutex_unlock(&llist_mutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
newpos -= correction;
|
newpos -= correction;
|
||||||
overlap -= correction;
|
overlap -= correction; /* Used below to know how to split the data */
|
||||||
*delta -= correction;
|
new_delta -= correction;
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = (struct memory_handle *)(&buffer[newpos]);
|
dest = (struct memory_handle *)(&buffer[newpos]);
|
||||||
|
|
@ -440,7 +449,7 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
|
||||||
while (m && m->next != h) {
|
while (m && m->next != h) {
|
||||||
m = m->next;
|
m = m->next;
|
||||||
}
|
}
|
||||||
if (h && m && m->next == h) {
|
if (m && m->next == h) {
|
||||||
m->next = dest;
|
m->next = dest;
|
||||||
} else {
|
} else {
|
||||||
mutex_unlock(&llist_mutex);
|
mutex_unlock(&llist_mutex);
|
||||||
|
|
@ -448,6 +457,9 @@ static struct memory_handle *move_handle(const struct memory_handle *h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 (h == cached_handle)
|
||||||
cached_handle = dest;
|
cached_handle = dest;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue