70 #include <sys/types.h>
71 #include <sys/queue.h>
72 #include <sys/bitstring.h>
76 #include <sys/param.h>
77 #include <sys/malloc.h>
78 #include <sys/kernel.h>
79 #include <sys/systm.h>
80 #include <sys/limits.h>
82 #include <sys/mutex.h>
90 static MALLOC_DEFINE(M_UNIT,
"Unitno",
"Unit number allocation");
92 #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO)
93 #define Free(foo) free(foo, M_UNIT)
105 #define KASSERT(cond, arg) \
114 #define Malloc(foo) _Malloc(foo, __LINE__)
116 _Malloc(
size_t foo,
int line)
119 KASSERT(no_alloc == 0, (
"malloc in wrong place() line %d", line));
120 return (calloc(foo, 1));
122 #define Free(foo) free(foo)
132 mtx_lock(
struct mtx *mp)
134 KASSERT(mp->state == 0, (
"mutex already locked"));
139 mtx_unlock(
struct mtx *mp)
141 KASSERT(mp->state == 1, (
"mutex not locked"));
148 mtx_assert(
struct mtx *mp,
int flag)
150 if (flag == MA_OWNED) {
151 KASSERT(mp->state == 1, (
"mtx_assert(MA_OWNED) not true"));
155 #define CTASSERT(foo)
156 #define WITNESS_WARN(flags, lock, fmt, ...) (void)0
175 TAILQ_ENTRY(
unr) list;
188 #define NBITS ((int)sizeof(((struct unrb *)NULL)->map) * 8)
206 #if defined(DIAGNOSTIC) || !defined(_KERNEL)
223 TAILQ_FOREACH(up, &uh->head, list) {
225 if (up->ptr != uh && up->ptr != NULL) {
227 KASSERT (up->len <=
NBITS,
228 (
"UNR inconsistency: len %u max %d (line %d)\n",
229 up->len,
NBITS, line));
232 for (x = 0; x < up->len; x++)
233 if (bit_test(ub->
map, x))
235 KASSERT (w == ub->
busy,
236 (
"UNR inconsistency: busy %u found %u (line %d)\n",
239 }
else if (up->ptr != NULL)
242 KASSERT (y == uh->busy,
243 (
"UNR inconsistency: items %u found %u (line %d)\n",
245 KASSERT (z == uh->alloc,
246 (
"UNR inconsistency: chunks %u found %u (line %d)\n",
247 uh->alloc, z, line));
266 static __inline
void *
272 KASSERT(*p1 != NULL || *p2 != NULL, (
"Out of cached memory"));
291 TAILQ_INSERT_TAIL(&uh->ppfree, up, list);
299 mtx_assert(uh->mtx, MA_OWNED);
300 while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) {
301 TAILQ_REMOVE(&uh->ppfree, up, list);
329 KASSERT(low >= 0 && low <= high,
330 (
"UNR: use error: new_unrhdr(%d, %d)", low, high));
336 TAILQ_INIT(&uh->head);
337 TAILQ_INIT(&uh->ppfree);
341 uh->last = 1 + (high - low);
351 KASSERT(uh->busy == 0, (
"unrhdr has %u allocations", uh->busy));
352 KASSERT(uh->alloc == 0, (
"UNR memory leak in delete_unrhdr"));
353 KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL,
354 (
"unrhdr has postponed item for free"));
361 return (up->ptr != uh && up->ptr != NULL);
376 struct unr *up, *uf, *us;
377 struct unrb *ub, *ubf;
386 TAILQ_FOREACH(uf, &uh->head, list) {
387 if (uf->len >=
NBITS)
395 up = TAILQ_NEXT(up, list);
398 if ((up->len + l) >
NBITS)
419 uf = TAILQ_NEXT(us, list);
420 TAILQ_REMOVE(&uh->head, us, list);
422 l = us->ptr == uh ? 1 : 0;
426 bit_nset(ub->
map, 0, a);
429 bit_nclear(ub->
map, 0, a);
432 if (uf->ptr == NULL) {
433 bit_nclear(ub->
map, a, a + uf->len - 1);
435 bit_nset(ub->
map, a, a + uf->len - 1);
443 for (l = 0; l < uf->len; l++, a++) {
444 if (bit_test(ubf->
map, l)) {
448 bit_clear(ub->
map, a);
459 uf = TAILQ_NEXT(us, list);
462 if (uf->len + us->len >
NBITS)
464 if (uf->ptr == NULL) {
465 bit_nclear(ub->
map, us->len, us->len + uf->len - 1);
467 TAILQ_REMOVE(&uh->head, uf, list);
469 }
else if (uf->ptr == uh) {
470 bit_nset(ub->
map, us->len, us->len + uf->len - 1);
473 TAILQ_REMOVE(&uh->head, uf, list);
477 for (l = 0; l < uf->len; l++, us->len++) {
478 if (bit_test(ubf->
map, l)) {
479 bit_set(ub->
map, us->len);
482 bit_clear(ub->
map, us->len);
485 TAILQ_REMOVE(&uh->head, uf, list);
506 if (ub->
busy == up->len) {
509 }
else if (ub->
busy == 0) {
517 upp = TAILQ_PREV(up, unrhd, list);
519 upp = TAILQ_NEXT(up, list);
520 TAILQ_REMOVE(&uh->head, up, list);
527 upp = TAILQ_PREV(up, unrhd, list);
528 if (upp != NULL && up->ptr == upp->ptr) {
530 TAILQ_REMOVE(&uh->head, upp, list);
533 upp = TAILQ_NEXT(up, list);
534 if (upp != NULL && up->ptr == upp->ptr) {
536 TAILQ_REMOVE(&uh->head, upp, list);
542 upp = TAILQ_FIRST(&uh->head);
543 if (upp != NULL && upp->ptr == uh) {
544 uh->first += upp->len;
545 TAILQ_REMOVE(&uh->head, upp, list);
552 upp = TAILQ_LAST(&uh->head, unrhd);
553 if (upp != NULL && upp->ptr == NULL) {
554 uh->last += upp->len;
555 TAILQ_REMOVE(&uh->head, upp, list);
577 mtx_assert(uh->mtx, MA_OWNED);
579 x = uh->low + uh->first;
581 up = TAILQ_FIRST(&uh->head);
586 if (up == NULL && uh->last > 0) {
600 KASSERT(up->ptr != uh, (
"UNR first element is allocated"));
602 if (up->ptr == NULL) {
607 KASSERT(ub->
busy < up->len, (
"UNR bitmap confusion"));
608 bit_ffc(ub->
map, up->len, &y);
609 KASSERT(y != -1, (
"UNR corruption: No clear bit in bitmap."));
634 struct unr *up, *upn;
638 mtx_assert(uh->mtx, MA_OWNED);
640 if (item < uh->low + uh->first || item > uh->high)
643 up = TAILQ_FIRST(&uh->head);
645 if (up == NULL && item - uh->low == uh->first) {
653 i = item - uh->low - uh->first;
659 TAILQ_INSERT_TAIL(&uh->head, up, list);
663 TAILQ_INSERT_TAIL(&uh->head, up, list);
664 uh->last = uh->high - uh->low - i;
670 TAILQ_FOREACH(up, &uh->head, list) {
682 TAILQ_INSERT_TAIL(&uh->head, up, list);
687 TAILQ_INSERT_TAIL(&uh->head, up, list);
693 if (bit_test(ub->
map, i) == 0) {
699 }
else if (up->ptr == uh)
702 KASSERT(up->ptr == NULL,
703 (
"alloc_unr_specificl: up->ptr != NULL (up=%p)", up));
706 tl = up->len - (1 + i);
711 TAILQ_INSERT_AFTER(&uh->head, up, upn, list);
719 TAILQ_INSERT_BEFORE(up, upn, list);
725 last = uh->high - uh->low - (item - uh->low);
740 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"alloc_unr_specific");
765 struct unr *up, *upp, *upn;
769 KASSERT(item >= uh->low && item <= uh->high,
770 (
"UNR: free_unr(%u) out of range [%u...%u]",
771 item, uh->low, uh->high));
774 upp = TAILQ_FIRST(&uh->head);
778 if (item + 1 == uh->first && upp == NULL) {
789 if (item < uh->first) {
792 up->len = uh->first - item;
793 TAILQ_INSERT_HEAD(&uh->head, up, list);
794 uh->first -= up->len;
800 TAILQ_FOREACH(up, &uh->head, list) {
810 KASSERT(bit_test(ub->
map, item) != 0,
811 (
"UNR: Freeing free item %d (bitmap)\n", item));
812 bit_clear(ub->
map, item);
819 KASSERT(up->ptr == uh, (
"UNR Freeing free item %d (run))\n", item));
830 upp = TAILQ_PREV(up, unrhd, list);
831 if (item == 0 && upp != NULL && upp->ptr == NULL) {
840 upn = TAILQ_NEXT(up, list);
841 if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) {
850 pl = up->len - (1 + item);
855 TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
863 TAILQ_INSERT_BEFORE(up, upp, list);
876 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"free_unr");
896 print_unr(
struct unrhdr *uh,
struct unr *up)
901 printf(
" %p len = %5u ", up, up->len);
904 else if (up->ptr == uh)
909 for (x = 0; x < up->len; x++) {
910 if (bit_test(ub->
map, x))
920 print_unrhdr(
struct unrhdr *uh)
926 "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n",
927 uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc);
928 x = uh->low + uh->first;
929 TAILQ_FOREACH(up, &uh->head, list) {
932 if (up->ptr == NULL || up->ptr == uh)
940 test_alloc_unr(
struct unrhdr *uh, u_int i,
char a[])
960 test_alloc_unr_specific(
struct unrhdr *uh, u_int i,
char a[])
979 main(
int argc __unused,
const char **
argv __unused)
985 setbuf(stdout, NULL);
989 memset(a, 0,
sizeof a);
992 fprintf(stderr,
"sizeof(struct unr) %zu\n",
sizeof(
struct unr));
993 fprintf(stderr,
"sizeof(struct unrb) %zu\n",
sizeof(
struct unrb));
994 fprintf(stderr,
"sizeof(struct unrhdr) %zu\n",
sizeof(
struct unrhdr));
995 fprintf(stderr,
"NBITS %d\n",
NBITS);
997 for (m = 0; m < NN * 100; m++) {
1001 if (a[i] && (j & 1))
1004 if ((random() & 1) != 0)
1005 test_alloc_unr(uh, i, a);
1007 test_alloc_unr_specific(uh, i, a);
1013 for (i = 0; i < NN; i++) {
static __inline void * new_unr(struct unrhdr *uh, void **p1, void **p2)
int alloc_unrl(struct unrhdr *uh)
TAILQ_HEAD(note_info_list, note_info)
int alloc_unr_specific(struct unrhdr *uh, u_int item)
int alloc_unr(struct unrhdr *uh)
static struct mtx unitmtx
void clean_unrhdr(struct unrhdr *uh)
static __inline void check_unrhdr(struct unrhdr *uh, int line)
MTX_SYSINIT(unit,&unitmtx,"unit# allocation", MTX_DEF)
void clean_unrhdrl(struct unrhdr *uh)
static void free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2)
static int optimize_unr(struct unrhdr *uh)
struct unrhdr * new_unrhdr(int low, int high, struct mtx *mutex)
int printf(const char *fmt,...)
static __inline int is_bitmap(struct unrhdr *uh, struct unr *up)
bitstr_t map[sizeof(struct unr)-1]
CTASSERT(sizeof(struct unr)==sizeof(struct unrb))
static __inline void delete_unr(struct unrhdr *uh, void *ptr)
static int alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2)
void delete_unrhdr(struct unrhdr *uh)
static void collapse_unr(struct unrhdr *uh, struct unr *up)
void free_unr(struct unrhdr *uh, u_int item)
static MALLOC_DEFINE(M_UNIT,"Unitno","Unit number allocation")