4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * mod_hash: flexible hash table implementation.
29 * This is a reasonably fast, reasonably flexible hash table implementation
30 * which features pluggable hash algorithms to support storing arbitrary keys
31 * and values. It is designed to handle small (< 100,000 items) amounts of
32 * data. The hash uses chaining to resolve collisions, and does not feature a
33 * mechanism to grow the hash. Care must be taken to pick nchains to be large
34 * enough for the application at hand, or lots of time will be wasted searching
37 * The client of the hash is required to supply a number of items to support
38 * the various hash functions:
40 * - Destructor functions for the key and value being hashed.
41 * A destructor is responsible for freeing an object when the hash
42 * table is no longer storing it. Since keys and values can be of
43 * arbitrary type, separate destructors for keys & values are used.
44 * These may be mod_hash_null_keydtor and mod_hash_null_valdtor if no
45 * destructor is needed for either a key or value.
47 * - A hashing algorithm which returns a uint_t representing a hash index
48 * The number returned need _not_ be between 0 and nchains. The mod_hash
49 * code will take care of doing that. The second argument (after the
50 * key) to the hashing function is a void * that represents
51 * hash_alg_data-- this is provided so that the hashing algrorithm can
52 * maintain some state across calls, or keep algorithm-specific
53 * constants associated with the hash table.
55 * A pointer-hashing and a string-hashing algorithm are supplied in
58 * - A key comparator (a la qsort).
59 * This is used when searching the hash chain. The key comparator
60 * determines if two keys match. It should follow the return value
61 * semantics of strcmp.
63 * string and pointer comparators are supplied in this file.
65 * mod_hash_create_strhash() and mod_hash_create_ptrhash() provide good
66 * examples of how to create a customized hash table.
68 * Basic hash operations:
70 * mod_hash_create_strhash(name, nchains, dtor),
71 * create a hash using strings as keys.
72 * NOTE: This create a hash which automatically cleans up the string
73 * values it is given for keys.
75 * mod_hash_create_ptrhash(name, nchains, dtor, key_elem_size):
76 * create a hash using pointers as keys.
78 * mod_hash_create_extended(name, nchains, kdtor, vdtor,
79 * hash_alg, hash_alg_data,
81 * create a customized hash table.
83 * mod_hash_destroy_hash(hash):
84 * destroy the given hash table, calling the key and value destructors
85 * on each key-value pair stored in the hash.
87 * mod_hash_insert(hash, key, val):
88 * place a key, value pair into the given hash.
89 * duplicate keys are rejected.
91 * mod_hash_insert_reserve(hash, key, val, handle):
92 * place a key, value pair into the given hash, using handle to indicate
93 * the reserved storage for the pair. (no memory allocation is needed
94 * during a mod_hash_insert_reserve.) duplicate keys are rejected.
96 * mod_hash_reserve(hash, *handle):
97 * reserve storage for a key-value pair using the memory allocation
98 * policy of 'hash', returning the storage handle in 'handle'.
100 * mod_hash_reserve_nosleep(hash, *handle): reserve storage for a key-value
101 * pair ignoring the memory allocation policy of 'hash' and always without
102 * sleep, returning the storage handle in 'handle'.
104 * mod_hash_remove(hash, key, *val):
105 * remove a key-value pair with key 'key' from 'hash', destroying the
106 * stored key, and returning the value in val.
108 * mod_hash_replace(hash, key, val)
109 * atomically remove an existing key-value pair from a hash, and replace
110 * the key and value with the ones supplied. The removed key and value
111 * (if any) are destroyed.
113 * mod_hash_destroy(hash, key):
114 * remove a key-value pair with key 'key' from 'hash', destroying both
115 * stored key and stored value.
117 * mod_hash_find(hash, key, val):
118 * find a value in the hash table corresponding to the given key.
120 * mod_hash_find_cb(hash, key, val, found_callback)
121 * find a value in the hash table corresponding to the given key.
122 * If a value is found, call specified callback passing key and val to it.
123 * The callback is called with the hash lock held.
124 * It is intended to be used in situations where the act of locating the
125 * data must also modify it - such as in reference counting schemes.
127 * mod_hash_walk(hash, callback(key, elem, arg), arg)
128 * walks all the elements in the hashtable and invokes the callback
129 * function with the key/value pair for each element. the hashtable
130 * is locked for readers so the callback function should not attempt
131 * to do any updates to the hashable. the callback function should
132 * return MH_WALK_CONTINUE to continue walking the hashtable or
133 * MH_WALK_TERMINATE to abort the walk of the hashtable.
135 * mod_hash_clear(hash):
136 * clears the given hash table of entries, calling the key and value
137 * destructors for every element in the hash.
140 #include <sys/bitmap.h>
141 #include <sys/debug.h>
142 #include <sys/kmem.h>
143 #include <sys/sunddi.h>
145 #include <sys/modhash_impl.h>
149 * Invoke the key destructor.
151 #define MH_KEY_DESTROY(hash, key) ((hash->mh_kdtor)(key))
155 * Invoke the value destructor.
157 #define MH_VAL_DESTROY(hash, val) ((hash->mh_vdtor)(val))
161 * Call the key comparator for the given hash keys.
163 #define MH_KEYCMP(hash, key1, key2) ((hash->mh_keycmp)(key1, key2))
166 * Cache for struct mod_hash_entry
168 kmem_cache_t
*mh_e_cache
= NULL
;
169 mod_hash_t
*mh_head
= NULL
;
170 kmutex_t mh_head_lock
;
173 * mod_hash_null_keydtor()
174 * mod_hash_null_valdtor()
175 * no-op key and value destructors.
179 mod_hash_null_keydtor(mod_hash_key_t key
)
185 mod_hash_null_valdtor(mod_hash_val_t val
)
191 * mod_hash_strkey_cmp()
192 * mod_hash_strkey_dtor()
193 * mod_hash_strval_dtor()
194 * Hash and key comparison routines for hashes with string keys.
196 * mod_hash_create_strhash()
197 * Create a hash using strings as keys
199 * The string hashing algorithm is from the "Dragon Book" --
200 * "Compilers: Principles, Tools & Techniques", by Aho, Sethi, Ullman
205 mod_hash_bystr(void *hash_data
, mod_hash_key_t key
)
209 char *p
, *k
= (char *)key
;
212 for (p
= k
; *p
!= '\0'; p
++) {
213 hash
= (hash
<< 4) + *p
;
214 if ((g
= (hash
& 0xf0000000)) != 0) {
223 mod_hash_strkey_cmp(mod_hash_key_t key1
, mod_hash_key_t key2
)
225 return (strcmp((char *)key1
, (char *)key2
));
229 mod_hash_strkey_dtor(mod_hash_key_t key
)
231 char *c
= (char *)key
;
232 kmem_free(c
, strlen(c
) + 1);
236 mod_hash_strval_dtor(mod_hash_val_t val
)
238 char *c
= (char *)val
;
239 kmem_free(c
, strlen(c
) + 1);
243 mod_hash_create_strhash(char *name
, size_t nchains
,
244 void (*val_dtor
)(mod_hash_val_t
))
246 return mod_hash_create_extended(name
, nchains
, mod_hash_strkey_dtor
,
247 val_dtor
, mod_hash_bystr
, NULL
, mod_hash_strkey_cmp
, KM_SLEEP
);
251 mod_hash_destroy_strhash(mod_hash_t
*strhash
)
254 mod_hash_destroy_hash(strhash
);
260 * mod_hash_ptrkey_cmp()
261 * Hash and key comparison routines for hashes with pointer keys.
263 * mod_hash_create_ptrhash()
264 * mod_hash_destroy_ptrhash()
265 * Create a hash that uses pointers as keys. This hash algorithm
266 * picks an appropriate set of middle bits in the address to hash on
267 * based on the size of the hash table and a hint about the size of
268 * the items pointed at.
271 mod_hash_byptr(void *hash_data
, mod_hash_key_t key
)
273 uintptr_t k
= (uintptr_t)key
;
274 k
>>= (int)(uintptr_t)hash_data
;
280 mod_hash_ptrkey_cmp(mod_hash_key_t key1
, mod_hash_key_t key2
)
282 uintptr_t k1
= (uintptr_t)key1
;
283 uintptr_t k2
= (uintptr_t)key2
;
293 mod_hash_create_ptrhash(char *name
, size_t nchains
,
294 void (*val_dtor
)(mod_hash_val_t
), size_t key_elem_size
)
299 * We want to hash on the bits in the middle of the address word
300 * Bits far to the right in the word have little significance, and
301 * are likely to all look the same (for example, an array of
302 * 256-byte structures will have the bottom 8 bits of address
303 * words the same). So we want to right-shift each address to
304 * ignore the bottom bits.
306 * The high bits, which are also unused, will get taken out when
307 * mod_hash takes hashkey % nchains.
309 rshift
= highbit(key_elem_size
);
311 return mod_hash_create_extended(name
, nchains
, mod_hash_null_keydtor
,
312 val_dtor
, mod_hash_byptr
, (void *)rshift
, mod_hash_ptrkey_cmp
,
317 mod_hash_destroy_ptrhash(mod_hash_t
*hash
)
320 mod_hash_destroy_hash(hash
);
325 * mod_hash_idkey_cmp()
326 * Hash and key comparison routines for hashes with 32-bit unsigned keys.
328 * mod_hash_create_idhash()
329 * mod_hash_destroy_idhash()
330 * mod_hash_iddata_gen()
331 * Create a hash that uses numeric keys.
333 * The hash algorithm is documented in "Introduction to Algorithms"
334 * (Cormen, Leiserson, Rivest); when the hash table is created, it
335 * attempts to find the next largest prime above the number of hash
336 * slots. The hash index is then this number times the key modulo
337 * the hash size, or (key * prime) % nchains.
340 mod_hash_byid(void *hash_data
, mod_hash_key_t key
)
342 uint_t kval
= (uint_t
)(uintptr_t)hash_data
;
343 return ((uint_t
)(uintptr_t)key
* (uint_t
)kval
);
347 mod_hash_idkey_cmp(mod_hash_key_t key1
, mod_hash_key_t key2
)
349 return ((uint_t
)(uintptr_t)key1
- (uint_t
)(uintptr_t)key2
);
353 * Generate the next largest prime number greater than nchains; this value
354 * is intended to be later passed in to mod_hash_create_extended() as the
358 mod_hash_iddata_gen(size_t nchains
)
360 uint_t kval
, i
, prime
;
363 * Pick the first (odd) prime greater than nchains. Make sure kval is
364 * odd (so start with nchains +1 or +2 as appropriate).
366 kval
= (nchains
% 2 == 0) ? nchains
+ 1 : nchains
+ 2;
370 for (i
= 3; i
* i
<= kval
; i
+= 2) {
382 mod_hash_create_idhash(char *name
, size_t nchains
,
383 void (*val_dtor
)(mod_hash_val_t
))
385 uint_t kval
= mod_hash_iddata_gen(nchains
);
387 return (mod_hash_create_extended(name
, nchains
, mod_hash_null_keydtor
,
388 val_dtor
, mod_hash_byid
, (void *)(uintptr_t)kval
,
389 mod_hash_idkey_cmp
, KM_SLEEP
));
393 mod_hash_destroy_idhash(mod_hash_t
*hash
)
396 mod_hash_destroy_hash(hash
);
401 * sets up globals, etc for mod_hash_*
406 ASSERT(mh_e_cache
== NULL
);
407 mh_e_cache
= kmem_cache_create("mod_hash_entries",
408 sizeof (struct mod_hash_entry
), 0, NULL
, NULL
, NULL
, NULL
,
413 * mod_hash_create_extended()
414 * The full-blown hash creation function.
417 * nchains - how many hash slots to create. More hash slots will
418 * result in shorter hash chains, but will consume
419 * slightly more memory up front.
420 * sleep - should be KM_SLEEP or KM_NOSLEEP, to indicate whether
421 * to sleep for memory, or fail in low-memory conditions.
423 * Fails only if KM_NOSLEEP was specified, and no memory was available.
426 mod_hash_create_extended(
427 char *hname
, /* descriptive name for hash */
428 size_t nchains
, /* number of hash slots */
429 void (*kdtor
)(mod_hash_key_t
), /* key destructor */
430 void (*vdtor
)(mod_hash_val_t
), /* value destructor */
431 uint_t (*hash_alg
)(void *, mod_hash_key_t
), /* hash algorithm */
432 void *hash_alg_data
, /* pass-thru arg for hash_alg */
433 int (*keycmp
)(mod_hash_key_t
, mod_hash_key_t
), /* key comparator */
434 int sleep
) /* whether to sleep for mem */
436 mod_hash_t
*mod_hash
;
437 ASSERT(hname
&& keycmp
&& hash_alg
&& vdtor
&& kdtor
);
439 if ((mod_hash
= kmem_zalloc(MH_SIZE(nchains
), sleep
)) == NULL
)
442 mod_hash
->mh_name
= kmem_alloc(strlen(hname
) + 1, sleep
);
443 if (mod_hash
->mh_name
== NULL
) {
444 kmem_free(mod_hash
, MH_SIZE(nchains
));
447 (void) strcpy(mod_hash
->mh_name
, hname
);
449 mod_hash
->mh_sleep
= sleep
;
450 mod_hash
->mh_nchains
= nchains
;
451 mod_hash
->mh_kdtor
= kdtor
;
452 mod_hash
->mh_vdtor
= vdtor
;
453 mod_hash
->mh_hashalg
= hash_alg
;
454 mod_hash
->mh_hashalg_data
= hash_alg_data
;
455 mod_hash
->mh_keycmp
= keycmp
;
457 rw_init(&mod_hash
->mh_contents
, NULL
, RW_DEFAULT
, NULL
);
460 * Link the hash up on the list of hashes
462 mutex_enter(&mh_head_lock
);
463 mod_hash
->mh_next
= mh_head
;
465 mutex_exit(&mh_head_lock
);
471 * mod_hash_destroy_hash()
472 * destroy a hash table, destroying all of its stored keys and values
476 mod_hash_destroy_hash(mod_hash_t
*hash
)
478 mod_hash_t
*mhp
, *mhpp
;
480 mutex_enter(&mh_head_lock
);
482 * Remove the hash from the hash list
484 if (hash
== mh_head
) { /* removing 1st list elem */
485 mh_head
= mh_head
->mh_next
;
488 * mhpp can start out NULL since we know the 1st elem isn't the
489 * droid we're looking for.
492 for (mhp
= mh_head
; mhp
!= NULL
; mhp
= mhp
->mh_next
) {
494 mhpp
->mh_next
= mhp
->mh_next
;
500 mutex_exit(&mh_head_lock
);
503 * Clean out keys and values.
505 mod_hash_clear(hash
);
507 rw_destroy(&hash
->mh_contents
);
509 kmem_free(hash
->mh_name
, strlen(hash
->mh_name
) + 1);
510 kmem_free(hash
, MH_SIZE(hash
->mh_nchains
));
515 * Call the hashing algorithm for this hash table, with the given key.
518 i_mod_hash(mod_hash_t
*hash
, mod_hash_key_t key
)
522 * Prevent div by 0 problems;
523 * Also a nice shortcut when using a hash as a list
525 if (hash
->mh_nchains
== 1)
528 h
= (hash
->mh_hashalg
)(hash
->mh_hashalg_data
, key
);
529 return (h
% (hash
->mh_nchains
- 1));
533 * i_mod_hash_insert_nosync()
535 * mod_hash_insert_reserve()
536 * insert 'val' into the hash table, using 'key' as its key. If 'key' is
537 * already a key in the hash, an error will be returned, and the key-val
538 * pair will not be inserted. i_mod_hash_insert_nosync() supports a simple
539 * handle abstraction, allowing hash entry allocation to be separated from
540 * the hash insertion. this abstraction allows simple use of the mod_hash
541 * structure in situations where mod_hash_insert() with a KM_SLEEP
542 * allocation policy would otherwise be unsafe.
545 i_mod_hash_insert_nosync(mod_hash_t
*hash
, mod_hash_key_t key
,
546 mod_hash_val_t val
, mod_hash_hndl_t handle
)
549 struct mod_hash_entry
*entry
;
554 * If we've not been given reserved storage, allocate storage directly,
555 * using the hash's allocation policy.
557 if (handle
== (mod_hash_hndl_t
)0) {
558 entry
= kmem_cache_alloc(mh_e_cache
, hash
->mh_sleep
);
560 hash
->mh_stat
.mhs_nomem
++;
561 return (MH_ERR_NOMEM
);
564 entry
= (struct mod_hash_entry
*)handle
;
567 hashidx
= i_mod_hash(hash
, key
);
568 entry
->mhe_key
= key
;
569 entry
->mhe_val
= val
;
570 entry
->mhe_next
= hash
->mh_entries
[hashidx
];
572 hash
->mh_entries
[hashidx
] = entry
;
573 hash
->mh_stat
.mhs_nelems
++;
579 mod_hash_insert(mod_hash_t
*hash
, mod_hash_key_t key
, mod_hash_val_t val
)
584 rw_enter(&hash
->mh_contents
, RW_WRITER
);
587 * Disallow duplicate keys in the hash
589 if (i_mod_hash_find_nosync(hash
, key
, &v
) == 0) {
590 rw_exit(&hash
->mh_contents
);
591 hash
->mh_stat
.mhs_coll
++;
592 return (MH_ERR_DUPLICATE
);
595 res
= i_mod_hash_insert_nosync(hash
, key
, val
, (mod_hash_hndl_t
)0);
596 rw_exit(&hash
->mh_contents
);
602 mod_hash_insert_reserve(mod_hash_t
*hash
, mod_hash_key_t key
,
603 mod_hash_val_t val
, mod_hash_hndl_t handle
)
608 rw_enter(&hash
->mh_contents
, RW_WRITER
);
611 * Disallow duplicate keys in the hash
613 if (i_mod_hash_find_nosync(hash
, key
, &v
) == 0) {
614 rw_exit(&hash
->mh_contents
);
615 hash
->mh_stat
.mhs_coll
++;
616 return (MH_ERR_DUPLICATE
);
618 res
= i_mod_hash_insert_nosync(hash
, key
, val
, handle
);
619 rw_exit(&hash
->mh_contents
);
626 * mod_hash_reserve_nosleep()
628 * Make or cancel a mod_hash_entry_t reservation. Reservations are used in
629 * mod_hash_insert_reserve() above.
632 mod_hash_reserve(mod_hash_t
*hash
, mod_hash_hndl_t
*handlep
)
634 *handlep
= kmem_cache_alloc(mh_e_cache
, hash
->mh_sleep
);
635 if (*handlep
== NULL
) {
636 hash
->mh_stat
.mhs_nomem
++;
637 return (MH_ERR_NOMEM
);
644 mod_hash_reserve_nosleep(mod_hash_t
*hash
, mod_hash_hndl_t
*handlep
)
646 *handlep
= kmem_cache_alloc(mh_e_cache
, KM_NOSLEEP
);
647 if (*handlep
== NULL
) {
648 hash
->mh_stat
.mhs_nomem
++;
649 return (MH_ERR_NOMEM
);
658 mod_hash_cancel(mod_hash_t
*hash
, mod_hash_hndl_t
*handlep
)
660 kmem_cache_free(mh_e_cache
, *handlep
);
661 *handlep
= (mod_hash_hndl_t
)0;
665 * i_mod_hash_remove_nosync()
667 * Remove an element from the hash table.
670 i_mod_hash_remove_nosync(mod_hash_t
*hash
, mod_hash_key_t key
,
674 struct mod_hash_entry
*e
, *ep
;
676 hashidx
= i_mod_hash(hash
, key
);
677 ep
= NULL
; /* e's parent */
679 for (e
= hash
->mh_entries
[hashidx
]; e
!= NULL
; e
= e
->mhe_next
) {
680 if (MH_KEYCMP(hash
, e
->mhe_key
, key
) == 0)
685 if (e
== NULL
) { /* not found */
686 return (MH_ERR_NOTFOUND
);
689 if (ep
== NULL
) /* special case 1st element in bucket */
690 hash
->mh_entries
[hashidx
] = e
->mhe_next
;
692 ep
->mhe_next
= e
->mhe_next
;
695 * Clean up resources used by the node's key.
697 MH_KEY_DESTROY(hash
, e
->mhe_key
);
700 kmem_cache_free(mh_e_cache
, e
);
701 hash
->mh_stat
.mhs_nelems
--;
707 mod_hash_remove(mod_hash_t
*hash
, mod_hash_key_t key
, mod_hash_val_t
*val
)
711 rw_enter(&hash
->mh_contents
, RW_WRITER
);
712 res
= i_mod_hash_remove_nosync(hash
, key
, val
);
713 rw_exit(&hash
->mh_contents
);
720 * atomically remove an existing key-value pair from a hash, and replace
721 * the key and value with the ones supplied. The removed key and value
722 * (if any) are destroyed.
725 mod_hash_replace(mod_hash_t
*hash
, mod_hash_key_t key
, mod_hash_val_t val
)
730 rw_enter(&hash
->mh_contents
, RW_WRITER
);
732 if (i_mod_hash_remove_nosync(hash
, key
, &v
) == 0) {
734 * mod_hash_remove() takes care of freeing up the key resources.
736 MH_VAL_DESTROY(hash
, v
);
738 res
= i_mod_hash_insert_nosync(hash
, key
, val
, (mod_hash_hndl_t
)0);
740 rw_exit(&hash
->mh_contents
);
747 * Remove an element from the hash table matching 'key', and destroy it.
750 mod_hash_destroy(mod_hash_t
*hash
, mod_hash_key_t key
)
755 rw_enter(&hash
->mh_contents
, RW_WRITER
);
757 if ((rv
= i_mod_hash_remove_nosync(hash
, key
, &val
)) == 0) {
759 * mod_hash_remove() takes care of freeing up the key resources.
761 MH_VAL_DESTROY(hash
, val
);
764 rw_exit(&hash
->mh_contents
);
769 * i_mod_hash_find_nosync()
771 * Find a value in the hash table corresponding to the given key.
774 i_mod_hash_find_nosync(mod_hash_t
*hash
, mod_hash_key_t key
,
778 struct mod_hash_entry
*e
;
780 hashidx
= i_mod_hash(hash
, key
);
782 for (e
= hash
->mh_entries
[hashidx
]; e
!= NULL
; e
= e
->mhe_next
) {
783 if (MH_KEYCMP(hash
, e
->mhe_key
, key
) == 0) {
785 hash
->mh_stat
.mhs_hit
++;
789 hash
->mh_stat
.mhs_miss
++;
790 return (MH_ERR_NOTFOUND
);
794 mod_hash_find(mod_hash_t
*hash
, mod_hash_key_t key
, mod_hash_val_t
*val
)
798 rw_enter(&hash
->mh_contents
, RW_READER
);
799 res
= i_mod_hash_find_nosync(hash
, key
, val
);
800 rw_exit(&hash
->mh_contents
);
806 mod_hash_find_cb(mod_hash_t
*hash
, mod_hash_key_t key
, mod_hash_val_t
*val
,
807 void (*find_cb
)(mod_hash_key_t
, mod_hash_val_t
))
811 rw_enter(&hash
->mh_contents
, RW_READER
);
812 res
= i_mod_hash_find_nosync(hash
, key
, val
);
816 rw_exit(&hash
->mh_contents
);
822 mod_hash_find_cb_rval(mod_hash_t
*hash
, mod_hash_key_t key
, mod_hash_val_t
*val
,
823 int (*find_cb
)(mod_hash_key_t
, mod_hash_val_t
), int *cb_rval
)
827 rw_enter(&hash
->mh_contents
, RW_READER
);
828 res
= i_mod_hash_find_nosync(hash
, key
, val
);
830 *cb_rval
= find_cb(key
, *val
);
832 rw_exit(&hash
->mh_contents
);
838 i_mod_hash_walk_nosync(mod_hash_t
*hash
,
839 uint_t (*callback
)(mod_hash_key_t
, mod_hash_val_t
*, void *), void *arg
)
841 struct mod_hash_entry
*e
;
843 int res
= MH_WALK_CONTINUE
;
846 (hashidx
< (hash
->mh_nchains
- 1)) && (res
== MH_WALK_CONTINUE
);
848 e
= hash
->mh_entries
[hashidx
];
849 while ((e
!= NULL
) && (res
== MH_WALK_CONTINUE
)) {
850 res
= callback(e
->mhe_key
, e
->mhe_val
, arg
);
858 * Walks all the elements in the hashtable and invokes the callback
859 * function with the key/value pair for each element. The hashtable
860 * is locked for readers so the callback function should not attempt
861 * to do any updates to the hashable. The callback function should
862 * return MH_WALK_CONTINUE to continue walking the hashtable or
863 * MH_WALK_TERMINATE to abort the walk of the hashtable.
866 mod_hash_walk(mod_hash_t
*hash
,
867 uint_t (*callback
)(mod_hash_key_t
, mod_hash_val_t
*, void *), void *arg
)
869 rw_enter(&hash
->mh_contents
, RW_READER
);
870 i_mod_hash_walk_nosync(hash
, callback
, arg
);
871 rw_exit(&hash
->mh_contents
);
876 * i_mod_hash_clear_nosync()
878 * Clears the given hash table by calling the destructor of every hash
879 * element and freeing up all mod_hash_entry's.
882 i_mod_hash_clear_nosync(mod_hash_t
*hash
)
885 struct mod_hash_entry
*e
, *old_e
;
887 for (i
= 0; i
< hash
->mh_nchains
; i
++) {
888 e
= hash
->mh_entries
[i
];
890 MH_KEY_DESTROY(hash
, e
->mhe_key
);
891 MH_VAL_DESTROY(hash
, e
->mhe_val
);
894 kmem_cache_free(mh_e_cache
, old_e
);
896 hash
->mh_entries
[i
] = NULL
;
898 hash
->mh_stat
.mhs_nelems
= 0;
902 mod_hash_clear(mod_hash_t
*hash
)
905 rw_enter(&hash
->mh_contents
, RW_WRITER
);
906 i_mod_hash_clear_nosync(hash
);
907 rw_exit(&hash
->mh_contents
);