diff options
Diffstat (limited to 'freebsd/sys/kern/subr_unit.c')
-rw-r--r-- | freebsd/sys/kern/subr_unit.c | 214 |
1 files changed, 125 insertions, 89 deletions
diff --git a/freebsd/sys/kern/subr_unit.c b/freebsd/sys/kern/subr_unit.c index a560eb50..678916f8 100644 --- a/freebsd/sys/kern/subr_unit.c +++ b/freebsd/sys/kern/subr_unit.c @@ -69,13 +69,13 @@ * N is the number of the highest unit allocated. */ +#include <rtems/bsd/sys/param.h> #include <sys/types.h> -#include <sys/queue.h> -#include <sys/bitstring.h> +#include <sys/_unrhdr.h> #ifdef _KERNEL -#include <rtems/bsd/sys/param.h> +#include <sys/bitstring.h> #include <sys/malloc.h> #include <sys/kernel.h> #include <sys/systm.h> @@ -100,6 +100,11 @@ MTX_SYSINIT(unit, &unitmtx, "unit# allocation", MTX_DEF); #else /* ...USERLAND */ +#include <bitstring.h> +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -166,7 +171,7 @@ mtx_assert(struct mtx *mp, int flag) * element: * If ptr is NULL, it represents a run of free items. * If ptr points to the unrhdr it represents a run of allocated items. - * Otherwise it points to an bitstring of allocated items. + * Otherwise it points to a bitstring of allocated items. * * For runs the len field is the length of the run. * For bitmaps the len field represents the number of allocated items. @@ -180,29 +185,32 @@ struct unr { }; struct unrb { - u_char busy; - bitstr_t map[sizeof(struct unr) - 1]; + bitstr_t map[sizeof(struct unr) / sizeof(bitstr_t)]; }; -CTASSERT(sizeof(struct unr) == sizeof(struct unrb)); +CTASSERT((sizeof(struct unr) % sizeof(bitstr_t)) == 0); -/* Number of bits in the bitmap */ -#define NBITS ((int)sizeof(((struct unrb *)NULL)->map) * 8) +/* Number of bits we can store in the bitmap */ +#define NBITS (8 * sizeof(((struct unrb*)NULL)->map)) -/* Header element for a unr number space. */ +/* Is the unrb empty in at least the first len bits? */ +static inline bool +ub_empty(struct unrb *ub, int len) { + int first_set; -struct unrhdr { - TAILQ_HEAD(unrhd,unr) head; - u_int low; /* Lowest item */ - u_int high; /* Highest item */ - u_int busy; /* Count of allocated items */ - u_int alloc; /* Count of memory allocations */ - u_int first; /* items in allocated from start */ - u_int last; /* items free at end */ - struct mtx *mtx; - TAILQ_HEAD(unrfr,unr) ppfree; /* Items to be freed after mtx - lock dropped */ -}; + bit_ffs(ub->map, len, &first_set); + return (first_set == -1); +} + +/* Is the unrb full? That is, is the number of set elements equal to len? */ +static inline bool +ub_full(struct unrb *ub, int len) +{ + int first_clear; + + bit_ffc(ub->map, len, &first_clear); + return (first_clear == -1); +} #if defined(DIAGNOSTIC) || !defined(_KERNEL) @@ -218,7 +226,8 @@ check_unrhdr(struct unrhdr *uh, int line) { struct unr *up; struct unrb *ub; - u_int x, y, z, w; + int w; + u_int y, z; y = uh->first; z = 0; @@ -227,16 +236,11 @@ check_unrhdr(struct unrhdr *uh, int line) if (up->ptr != uh && up->ptr != NULL) { ub = up->ptr; KASSERT (up->len <= NBITS, - ("UNR inconsistency: len %u max %d (line %d)\n", + ("UNR inconsistency: len %u max %zd (line %d)\n", up->len, NBITS, line)); z++; w = 0; - for (x = 0; x < up->len; x++) - if (bit_test(ub->map, x)) - w++; - KASSERT (w == ub->busy, - ("UNR inconsistency: busy %u found %u (line %d)\n", - ub->busy, w, line)); + bit_count(ub->map, 0, up->len, &w); y += w; } else if (up->ptr != NULL) y += up->len; @@ -252,7 +256,7 @@ check_unrhdr(struct unrhdr *uh, int line) #else static __inline void -check_unrhdr(struct unrhdr *uh, int line) +check_unrhdr(struct unrhdr *uh __unused, int line __unused) { } @@ -317,20 +321,12 @@ clean_unrhdr(struct unrhdr *uh) mtx_unlock(uh->mtx); } -/* - * Allocate a new unrheader set. - * - * Highest and lowest valid values given as parameters. - */ - -struct unrhdr * -new_unrhdr(int low, int high, struct mtx *mutex) +void +init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex) { - struct unrhdr *uh; KASSERT(low >= 0 && low <= high, ("UNR: use error: new_unrhdr(%d, %d)", low, high)); - uh = Malloc(sizeof *uh); if (mutex != NULL) uh->mtx = mutex; else @@ -342,6 +338,21 @@ new_unrhdr(int low, int high, struct mtx *mutex) uh->first = 0; uh->last = 1 + (high - low); check_unrhdr(uh, __LINE__); +} + +/* + * Allocate a new unrheader set. + * + * Highest and lowest valid values given as parameters. + */ + +struct unrhdr * +new_unrhdr(int low, int high, struct mtx *mutex) +{ + struct unrhdr *uh; + + uh = Malloc(sizeof *uh); + init_unrhdr(uh, low, high, mutex); return (uh); } @@ -423,32 +434,24 @@ optimize_unr(struct unrhdr *uh) a = us->len; l = us->ptr == uh ? 1 : 0; ub = (void *)us; - ub->busy = 0; - if (l) { + bit_nclear(ub->map, 0, NBITS - 1); + if (l) bit_nset(ub->map, 0, a); - ub->busy += a; - } else { - bit_nclear(ub->map, 0, a); - } if (!is_bitmap(uh, uf)) { - if (uf->ptr == NULL) { + if (uf->ptr == NULL) bit_nclear(ub->map, a, a + uf->len - 1); - } else { + else bit_nset(ub->map, a, a + uf->len - 1); - ub->busy += uf->len; - } uf->ptr = ub; uf->len += a; us = uf; } else { ubf = uf->ptr; for (l = 0; l < uf->len; l++, a++) { - if (bit_test(ubf->map, l)) { + if (bit_test(ubf->map, l)) bit_set(ub->map, a); - ub->busy++; - } else { + else bit_clear(ub->map, a); - } } uf->len = a; delete_unr(uh, uf->ptr); @@ -470,19 +473,16 @@ optimize_unr(struct unrhdr *uh) delete_unr(uh, uf); } else if (uf->ptr == uh) { bit_nset(ub->map, us->len, us->len + uf->len - 1); - ub->busy += uf->len; us->len += uf->len; TAILQ_REMOVE(&uh->head, uf, list); delete_unr(uh, uf); } else { ubf = uf->ptr; for (l = 0; l < uf->len; l++, us->len++) { - if (bit_test(ubf->map, l)) { + if (bit_test(ubf->map, l)) bit_set(ub->map, us->len); - ub->busy++; - } else { + else bit_clear(ub->map, us->len); - } } TAILQ_REMOVE(&uh->head, uf, list); delete_unr(uh, ubf); @@ -505,10 +505,10 @@ collapse_unr(struct unrhdr *uh, struct unr *up) /* If bitmap is all set or clear, change it to runlength */ if (is_bitmap(uh, up)) { ub = up->ptr; - if (ub->busy == up->len) { + if (ub_full(ub, up->len)) { delete_unr(uh, up->ptr); up->ptr = uh; - } else if (ub->busy == 0) { + } else if (ub_empty(ub, up->len)) { delete_unr(uh, up->ptr); up->ptr = NULL; } @@ -606,11 +606,9 @@ alloc_unrl(struct unrhdr *uh) up->len--; } else { /* bitmap */ ub = up->ptr; - KASSERT(ub->busy < up->len, ("UNR bitmap confusion")); bit_ffc(ub->map, up->len, &y); KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap.")); bit_set(ub->map, y); - ub->busy++; x += y; } uh->busy++; @@ -694,7 +692,6 @@ alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2) ub = up->ptr; if (bit_test(ub->map, i) == 0) { bit_set(ub->map, i); - ub->busy++; goto done; } else return (-1); @@ -813,7 +810,6 @@ free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2) ("UNR: Freeing free item %d (bitmap)\n", item)); bit_clear(ub->map, item); uh->busy--; - ub->busy--; collapse_unr(uh, up); return; } @@ -891,9 +887,13 @@ free_unr(struct unrhdr *uh, u_int item) #ifndef _KERNEL /* USERLAND test driver */ /* - * Simple stochastic test driver for the above functions + * Simple stochastic test driver for the above functions. The code resides + * here so that it can access static functions and structures. */ +static bool verbose; +#define VPRINTF(...) {if (verbose) printf(__VA_ARGS__);} + static void print_unr(struct unrhdr *uh, struct unr *up) { @@ -907,7 +907,7 @@ print_unr(struct unrhdr *uh, struct unr *up) printf("alloc\n"); else { ub = up->ptr; - printf("bitmap(%d) [", ub->busy); + printf("bitmap ["); for (x = 0; x < up->len; x++) { if (bit_test(ub->map, x)) printf("#"); @@ -944,7 +944,7 @@ test_alloc_unr(struct unrhdr *uh, u_int i, char a[]) int j; if (a[i]) { - printf("F %u\n", i); + VPRINTF("F %u\n", i); free_unr(uh, i); a[i] = 0; } else { @@ -952,7 +952,7 @@ test_alloc_unr(struct unrhdr *uh, u_int i, char a[]) j = alloc_unr(uh); if (j != -1) { a[j] = 1; - printf("A %d\n", j); + VPRINTF("A %d\n", j); } no_alloc = 0; } @@ -965,40 +965,73 @@ test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[]) j = alloc_unr_specific(uh, i); if (j == -1) { - printf("F %u\n", i); + VPRINTF("F %u\n", i); a[i] = 0; free_unr(uh, i); } else { a[i] = 1; - printf("A %d\n", j); + VPRINTF("A %d\n", j); } } -/* Number of unrs to test */ -#define NN 10000 +static void +usage(char** argv) +{ + printf("%s [-h] [-r REPETITIONS] [-v]\n", argv[0]); +} int -main(int argc __unused, const char **argv __unused) +main(int argc, char **argv) { struct unrhdr *uh; - u_int i, x, m, j; - char a[NN]; + char *a; + long count = 10000; /* Number of unrs to test */ + long reps = 1, m; + int ch; + u_int i, x, j; + + verbose = false; + + while ((ch = getopt(argc, argv, "hr:v")) != -1) { + switch (ch) { + case 'r': + errno = 0; + reps = strtol(optarg, NULL, 0); + if (errno == ERANGE || errno == EINVAL) { + usage(argv); + exit(2); + } + + break; + case 'v': + verbose = true; + break; + case 'h': + default: + usage(argv); + exit(2); + } + + + } setbuf(stdout, NULL); - uh = new_unrhdr(0, NN - 1, NULL); + uh = new_unrhdr(0, count - 1, NULL); print_unrhdr(uh); - memset(a, 0, sizeof a); + a = calloc(count, sizeof(char)); + if (a == NULL) + err(1, "calloc failed"); srandomdev(); - fprintf(stderr, "sizeof(struct unr) %zu\n", sizeof(struct unr)); - fprintf(stderr, "sizeof(struct unrb) %zu\n", sizeof(struct unrb)); - fprintf(stderr, "sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr)); - fprintf(stderr, "NBITS %d\n", NBITS); + printf("sizeof(struct unr) %zu\n", sizeof(struct unr)); + printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb)); + printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr)); + printf("NBITS %lu\n", (unsigned long)NBITS); x = 1; - for (m = 0; m < NN * 100; m++) { + for (m = 0; m < count * reps; m++) { j = random(); - i = (j >> 1) % NN; + i = (j >> 1) % count; #if 0 if (a[i] && (j & 1)) continue; @@ -1008,19 +1041,22 @@ main(int argc __unused, const char **argv __unused) else test_alloc_unr_specific(uh, i, a); - if (1) /* XXX: change this for detailed debug printout */ + if (verbose) print_unrhdr(uh); check_unrhdr(uh, __LINE__); } - for (i = 0; i < NN; i++) { + for (i = 0; i < (u_int)count; i++) { if (a[i]) { - printf("C %u\n", i); + if (verbose) { + printf("C %u\n", i); + print_unrhdr(uh); + } free_unr(uh, i); - print_unrhdr(uh); } } print_unrhdr(uh); delete_unrhdr(uh); + free(a); return (0); } #endif |