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