libsys: use linked list for free grants

With this change, obtaining an existing free grant is no longer an
operation of O(n) complexity.  As a result, the now-deprecated
getgrant/setgrant part of the grants API also no longer has a
performance advantage.

Change-Id: Ic19308a76924c6242f9784244a6b3600e561e0fe
This commit is contained in:
David van Moolenbroek 2015-12-29 15:37:11 +00:00 committed by Lionel Sambuc
parent ca779acd72
commit efc775b4c8
2 changed files with 27 additions and 10 deletions

View File

@ -31,6 +31,10 @@ typedef struct {
size_t cp_len; /* size in bytes */ size_t cp_len; /* size in bytes */
char cp_reserved[8]; /* future use */ char cp_reserved[8]; /* future use */
} cp_magic; } cp_magic;
struct {
/* (free slot) */
int cp_next; /* next free or -1 */
} cp_free;
} cp_u; } cp_u;
int cp_seq; /* sequence number */ int cp_seq; /* sequence number */
char cp_reserved[4]; /* future use */ char cp_reserved[4]; /* future use */

View File

@ -42,6 +42,7 @@
static cp_grant_t static_grants[NR_STATIC_GRANTS]; static cp_grant_t static_grants[NR_STATIC_GRANTS];
static cp_grant_t *grants = NULL; static cp_grant_t *grants = NULL;
static int ngrants = 0; static int ngrants = 0;
static int freelist = -1;
static void static void
cpf_grow(void) cpf_grow(void)
@ -78,10 +79,16 @@ cpf_grow(void)
* Make sure new slots are marked unused (CPF_USED is clear). * Make sure new slots are marked unused (CPF_USED is clear).
* Also start with a zero sequence number, for consistency; since the * Also start with a zero sequence number, for consistency; since the
* grant table is never shrunk, this introduces no issues by itself. * grant table is never shrunk, this introduces no issues by itself.
* Finally, form a new free list, in ascending order so that the lowest
* IDs get allocated first. Both the zeroed sequence number and the
* ascending order are necessary so that the first grant to be
* allocated has a zero ID (see the live update comment below).
*/ */
for(g = ngrants; g < new_size; g++) { for(g = ngrants; g < new_size; g++) {
new_grants[g].cp_flags = 0; new_grants[g].cp_flags = 0;
new_grants[g].cp_seq = 0; new_grants[g].cp_seq = 0;
new_grants[g].cp_u.cp_free.cp_next =
(g < new_size - 1) ? (g + 1) : freelist;
} }
/* Inform kernel about new size (and possibly new location). */ /* Inform kernel about new size (and possibly new location). */
@ -92,6 +99,7 @@ cpf_grow(void)
/* Update internal data. */ /* Update internal data. */
if(grants && ngrants > 0 && grants != static_grants) free(grants); if(grants && ngrants > 0 && grants != static_grants) free(grants);
freelist = ngrants;
grants = new_grants; grants = new_grants;
ngrants = new_size; ngrants = new_size;
} }
@ -105,17 +113,11 @@ cpf_new_grantslot(void)
*/ */
int g; int g;
/* Find free slot. */ /* Obtain a free slot. */
for(g = 0; g < ngrants && (grants[g].cp_flags & CPF_USED); g++) if ((g = freelist) == -1) {
; /* Table full - try to make the table larger. */
assert(g <= ngrants);
/* No free slot found? */
if(g == ngrants) {
cpf_grow(); cpf_grow();
assert(g <= ngrants); /* ngrants can't shrink. */ if ((g = freelist) == -1) {
if(g == ngrants) {
/* ngrants hasn't increased. */ /* ngrants hasn't increased. */
errno = ENOSPC; errno = ENOSPC;
return -1; return -1;
@ -129,6 +131,9 @@ cpf_new_grantslot(void)
assert(g < ngrants); assert(g < ngrants);
assert(!(grants[g].cp_flags & CPF_USED)); assert(!(grants[g].cp_flags & CPF_USED));
/* Take the slot off the free list, and return its slot number. */
freelist = grants[g].cp_u.cp_free.cp_next;
return g; return g;
} }
@ -226,6 +231,14 @@ cpf_revoke(cp_grant_id_t grant)
else else
grants[g].cp_seq = 0; grants[g].cp_seq = 0;
/*
* Put the grant back on the free list. The list is single-headed, so
* the last freed grant will be the first to be reused. Especially
* given the presence of sequence numbers, this is not a problem.
*/
grants[g].cp_u.cp_free.cp_next = freelist;
freelist = g;
return 0; return 0;
} }