/* * Small id to pointer translation service. * * It uses a radix tree like structure as a sparse array indexed * by the id to obtain the pointer. The bitmap makes allocating * an new id quick. */ #include "id.h" #ifdef __KERNEL__ static kmem_cache_t *id_layer_cache; #endif void *id_lookup(struct id *idp, int id) { int n = idp->layers * ID_BITS; struct id_layer *p = idp->top; if (id >= (1 << n)) return(NULL); while (n > 0 && p) { n -= ID_BITS; p = p->ary[(id >> n) & ID_MASK]; } return((void *)p); } static int sub_alloc(struct id_layer *p, int shift, int id, void *ptr) { int n = (id >> shift) & ID_MASK; int bitmap = p->bitmap; int id_base = id & ~((1 << (shift+ID_BITS))-1); int v; for ( ; n <= ID_MASK; n++, id = id_base + (n << shift)) { if (bitmap & (1 << n)) continue; if (shift == 0) { p->ary[n] = (struct id_layer *)ptr; p->bitmap |= 1<ary[n]) p->ary[n] = alloc_layer(); if (v = sub_alloc(p->ary[n], shift-ID_BITS, id, ptr)) { update_bitmap(p, n); return(v); } } return(0); } int id_new(struct id *idp, void *ptr) { int n = idp->layers * ID_BITS; int last = idp->last; struct id_layer **p, *new; int id, v; /* * Add a new layer if the array is full or the last id * was at the limit and we don't want to wrap. */ if ((last == ((1 << n)-1) && last < idp->min_wrap) || idp->count == (1 << n)) { ++idp->layers; n += ID_BITS; new = alloc_layer(); new->ary[0] = idp->top; idp->top = new; update_bitmap(new, 0); } if (last >= ((1 << n)-1)) last = 0; /* * Search for a free id starting after last id allocated. * If that fails wrap back to start. */ id = last+1; if (!(v = sub_alloc(idp->top, n-ID_BITS, id, ptr))) v = sub_alloc(idp->top, n-ID_BITS, 1, ptr); idp->last = v; idp->count++; return(v); } static int sub_remove(struct id_layer *p, int shift, int id) { int n = (id >> shift) & ID_MASK; int i, bitmap, rv; if (!p) { printf("in sub_remove for id=%d called with null pointer.\n", id); return(0); } rv = 0; bitmap = p->bitmap & ~(1<bitmap = bitmap; if (shift == 0) { p->ary[n] = NULL; rv = !bitmap; } else { if (sub_remove(p->ary[n], shift-ID_BITS, id)) { free_layer(p->ary[n]); p->ary[n] = 0; for (i = 0; i < (1 << ID_BITS); i++) if (p->ary[i]) break; if (i == (1 << ID_BITS)) rv = 1; } } return(rv); } void id_remove(struct id *idp, int id) { sub_remove(idp->top, (idp->layers-1)*ID_BITS, id); idp->count--; } void id_init(struct id *idp, int min_wrap) { #ifdef __KERNEL__ id_layer_cache = kmem_cache_create("id_layer_cache", sizeof(struct id_layer), 0, 0, 0, 0); #endif idp->count = 1; idp->last = 0; idp->layers = 1; idp->top = alloc_layer(); idp->top->bitmap = 1; idp->min_wrap = min_wrap; }