forked from len0rd/rockbox
Dircache: Improve freed name memory recallocation
There's only a need to check every MAX_TINYNAME+1 bytes and that the last character of the needed size 0xff in order to verify the size of the block since the minimum indirectly-stored string is MAX_TINYNAME+1. Change-Id: Ic789376b8575bab9266fcd54c610db0961de5d7f
This commit is contained in:
parent
05739efe8d
commit
bfd04df480
1 changed files with 36 additions and 26 deletions
|
@ -781,56 +781,66 @@ static int alloc_name(size_t size)
|
||||||
if (dircache.namesfree >= size)
|
if (dircache.namesfree >= size)
|
||||||
{
|
{
|
||||||
/* scan for a free gap starting at the hint point - first fit */
|
/* scan for a free gap starting at the hint point - first fit */
|
||||||
unsigned char *start = get_name(dircache.nextnamefree), *p = start;
|
unsigned char * const start = get_name(dircache.nextnamefree);
|
||||||
unsigned char *namesend = get_name(dircache.names + dircache.sizenames);
|
unsigned char * const bufend = get_name(dircache.names + dircache.sizenames);
|
||||||
size_t gapsize = 0;
|
unsigned char *p = start;
|
||||||
|
unsigned char *end = bufend;
|
||||||
|
|
||||||
while (gapsize < size)
|
while (1)
|
||||||
{
|
{
|
||||||
if ((p = memchr(p, 0xff, namesend - p)))
|
if ((size_t)(bufend - p) >= size && (p = memchr(p, 0xff, end - p)))
|
||||||
{
|
{
|
||||||
/* found a sentinel; see if there are enough in a row */
|
/* found a sentinel; see if there are enough in a row */
|
||||||
gapsize = 1;
|
unsigned char *q = p + size - 1;
|
||||||
while (*++p == 0xff && gapsize < size)
|
|
||||||
gapsize++;
|
/* check end byte and every MAX_TINYNAME+1 bytes from the end;
|
||||||
|
the minimum-length indirectly allocated string that could be
|
||||||
|
in between must have at least one character at one of those
|
||||||
|
locations */
|
||||||
|
while (q > p && *q == 0xff)
|
||||||
|
q -= MAX_TINYNAME+1;
|
||||||
|
|
||||||
|
if (q <= p)
|
||||||
|
{
|
||||||
|
nameidx = get_nameidx(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (namesend == start)
|
if (end == start)
|
||||||
break; /* exhausted */
|
break; /* exhausted */
|
||||||
|
|
||||||
/* wrap */
|
/* wrap */
|
||||||
namesend = start;
|
end = start;
|
||||||
p = get_name(dircache.names);
|
p = get_name(dircache.names);
|
||||||
|
|
||||||
if (p == namesend)
|
if (p == end)
|
||||||
break; /* initial hint was at names start */
|
break; /* initial hint was at names start */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gapsize >= size)
|
if (nameidx)
|
||||||
{
|
{
|
||||||
unsigned char *namep = p - gapsize;
|
unsigned char *q = p + size;
|
||||||
nameidx = get_nameidx(namep);
|
if (q[0] == 0xff && q[MAX_TINYNAME] != 0xff)
|
||||||
|
|
||||||
if (*p == 0xff)
|
|
||||||
{
|
{
|
||||||
/* if only a tiny block remains after buffer, claim it too */
|
/* if only a tiny block remains after buffer, claim it and
|
||||||
size_t tinysize = 1;
|
hide it from scans since it's too small for indirect
|
||||||
while (*++p == 0xff && tinysize <= MAX_TINYNAME)
|
allocation */
|
||||||
tinysize++;
|
do
|
||||||
|
|
||||||
if (tinysize <= MAX_TINYNAME)
|
|
||||||
{
|
{
|
||||||
/* mark with tiny block sentinel */
|
*q = 0xfe;
|
||||||
memset(p - tinysize, 0xfe, tinysize);
|
size++;
|
||||||
size += tinysize;
|
|
||||||
}
|
}
|
||||||
|
while (*++q == 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
dircache.namesfree -= size;
|
dircache.namesfree -= size;
|
||||||
dircache.sizeused += size;
|
dircache.sizeused += size;
|
||||||
set_namesfree_hint(namep + size);
|
set_namesfree_hint(p + size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue