xref: /illumos-gate/usr/src/lib/libsip/common/sip_hash.c (revision 0a44ef6d9afbfe052a7e975f55ea0d2954b62a82)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <pthread.h>
31 #include <sip.h>
32 
33 #include "sip_hash.h"
34 #include "sip_miscdefs.h"
35 
36 /*
37  * This file implements functions that add, search or remove an object
38  * from the hash table. The object is opaque to the hash functions. To add
39  * an object to the hash table, the caller provides the hash table,
40  * the object and the index into the hash table. To search an object,
41  * the caller provides the hash table, the digest (opaque), the index into
42  * the hash table and the function that does the actual match. Similarly,
43  * for removing an object, the caller provides the hash table, the digest
44  * (opaque), the index into the hash table and the function that does
45  * the acutal deletion of the object - if the deletion is successful,
46  * the object is taken off of the hash table.
47  */
48 
49 /*
50  * Given an object and the hash index, add it to the given hash table
51  */
52 int
53 sip_hash_add(sip_hash_t	*sip_hash, void *obj, int hindex)
54 {
55 	sip_hash_obj_t	*new_obj;
56 	sip_hash_t	*hash_entry;
57 
58 	assert(obj != NULL);
59 
60 	new_obj = (sip_hash_obj_t *)malloc(sizeof (*new_obj));
61 	if (new_obj == NULL)
62 		return (-1);
63 	new_obj->sip_obj = obj;
64 	new_obj->next_obj = NULL;
65 	new_obj->prev_obj = NULL;
66 	hash_entry = &sip_hash[hindex];
67 	(void) pthread_mutex_lock(&hash_entry->sip_hash_mutex);
68 	if (hash_entry->hash_count == 0) {
69 		assert(hash_entry->hash_head == NULL);
70 		assert(hash_entry->hash_tail == NULL);
71 		hash_entry->hash_head = new_obj;
72 	} else {
73 		hash_entry->hash_tail->next_obj = new_obj;
74 		new_obj->prev_obj = hash_entry->hash_tail;
75 	}
76 	hash_entry->hash_tail = new_obj;
77 	hash_entry->hash_count++;
78 	(void) pthread_mutex_unlock(&hash_entry->sip_hash_mutex);
79 	return (0);
80 }
81 
82 /*
83  * Given the hash table, the digest to be searched for,  index into the hash
84  * table and the function to do the actual matching, return the object,
85  * if found.
86  */
87 void *
88 sip_hash_find(sip_hash_t *sip_hash, void *digest, int hindex,
89     boolean_t (*match_func)(void *, void *))
90 {
91 	int		count;
92 	sip_hash_obj_t	*tmp;
93 	sip_hash_t	*hash_entry;
94 
95 	hash_entry =  &sip_hash[hindex];
96 	(void) pthread_mutex_lock(&hash_entry->sip_hash_mutex);
97 	tmp = hash_entry->hash_head;
98 	for (count = 0; count < hash_entry->hash_count; count++) {
99 		if (match_func(tmp->sip_obj, digest)) {
100 			(void) pthread_mutex_unlock(
101 			    &hash_entry->sip_hash_mutex);
102 			return (tmp->sip_obj);
103 		}
104 		tmp = tmp->next_obj;
105 	}
106 	(void) pthread_mutex_unlock(&hash_entry->sip_hash_mutex);
107 	return (NULL);
108 }
109 
110 /*
111  * Walk the hash table and invoke func on each object. 'arg' is passed
112  * to 'func'
113  */
114 void
115 sip_walk_hash(sip_hash_t *sip_hash, void (*func)(void *, void *), void *arg)
116 {
117 	sip_hash_t	*hash_entry;
118 	int		count;
119 	int		hcount;
120 	sip_hash_obj_t	*tmp;
121 
122 	for (count = 0; count < SIP_HASH_SZ; count++) {
123 		hash_entry =  &sip_hash[count];
124 		(void) pthread_mutex_lock(&hash_entry->sip_hash_mutex);
125 		tmp = hash_entry->hash_head;
126 		for (hcount = 0; hcount < hash_entry->hash_count; hcount++) {
127 			assert(tmp->sip_obj != NULL);
128 			func(tmp->sip_obj, arg);
129 			tmp = tmp->next_obj;
130 		}
131 		(void) pthread_mutex_unlock(&hash_entry->sip_hash_mutex);
132 	}
133 }
134 
135 /*
136  * Given the hash table, the digest to be searched for,  the index into the
137  * hash table and the  delete function provided to do the actual deletion,
138  * remove the object from the hash table (i.e. only if the object is deleted).
139  */
140 void
141 sip_hash_delete(sip_hash_t *sip_hash, void *digest, int hindex,
142     boolean_t (*del_func)(void *, void *, int *))
143 {
144 	sip_hash_t	*hash_entry;
145 	int		count;
146 	sip_hash_obj_t	*tmp;
147 	int		found;
148 
149 	hash_entry =  &sip_hash[hindex];
150 	(void) pthread_mutex_lock(&hash_entry->sip_hash_mutex);
151 	tmp = hash_entry->hash_head;
152 	for (count = 0; count < hash_entry->hash_count; count++) {
153 		if (del_func(tmp->sip_obj, digest, &found)) {
154 			if (tmp == hash_entry->hash_head) {
155 				if (tmp->next_obj != NULL) {
156 					hash_entry->hash_head = tmp->next_obj;
157 					tmp->next_obj->prev_obj = NULL;
158 				} else {
159 					assert(hash_entry->hash_tail ==
160 					    hash_entry->hash_head);
161 					hash_entry->hash_head = NULL;
162 					hash_entry->hash_tail = NULL;
163 				}
164 			} else {
165 				sip_hash_obj_t	*next = tmp->next_obj;
166 
167 				if (next != NULL) {
168 					tmp->prev_obj->next_obj = next;
169 					next->prev_obj = tmp->prev_obj;
170 				} else {
171 					assert(hash_entry->hash_tail == tmp);
172 					tmp->prev_obj->next_obj = NULL;
173 					hash_entry->hash_tail =
174 					    tmp->prev_obj;
175 				}
176 			}
177 			tmp->prev_obj = NULL;
178 			tmp->next_obj = NULL;
179 			free(tmp);
180 			hash_entry->hash_count--;
181 			(void) pthread_mutex_unlock(
182 			    &hash_entry->sip_hash_mutex);
183 			return;
184 		/*
185 		 * If we found the object, we are done
186 		 */
187 		} else if (found == 1) {
188 			(void) pthread_mutex_unlock(
189 			    &hash_entry->sip_hash_mutex);
190 			return;
191 		}
192 		tmp = tmp->next_obj;
193 	}
194 	(void) pthread_mutex_unlock(&hash_entry->sip_hash_mutex);
195 }
196