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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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 <fmd_alloc.h> 30 #include <fmd_string.h> 31 #include <fmd_subr.h> 32 #include <fmd_api.h> 33 #include <fmd_serd.h> 34 #include <fmd.h> 35 36 static fmd_serd_eng_t * 37 fmd_serd_eng_alloc(const char *name, uint64_t n, hrtime_t t) 38 { 39 fmd_serd_eng_t *sgp = fmd_zalloc(sizeof (fmd_serd_eng_t), FMD_SLEEP); 40 41 sgp->sg_name = fmd_strdup(name, FMD_SLEEP); 42 sgp->sg_flags = FMD_SERD_DIRTY; 43 sgp->sg_n = n; 44 sgp->sg_t = t; 45 46 return (sgp); 47 } 48 49 static void 50 fmd_serd_eng_free(fmd_serd_eng_t *sgp) 51 { 52 fmd_serd_eng_reset(sgp); 53 fmd_strfree(sgp->sg_name); 54 fmd_free(sgp, sizeof (fmd_serd_eng_t)); 55 } 56 57 void 58 fmd_serd_hash_create(fmd_serd_hash_t *shp) 59 { 60 shp->sh_hashlen = fmd.d_str_buckets; 61 shp->sh_hash = fmd_zalloc(sizeof (void *) * shp->sh_hashlen, FMD_SLEEP); 62 shp->sh_count = 0; 63 } 64 65 void 66 fmd_serd_hash_destroy(fmd_serd_hash_t *shp) 67 { 68 fmd_serd_eng_t *sgp, *ngp; 69 uint_t i; 70 71 for (i = 0; i < shp->sh_hashlen; i++) { 72 for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = ngp) { 73 ngp = sgp->sg_next; 74 fmd_serd_eng_free(sgp); 75 } 76 } 77 78 fmd_free(shp->sh_hash, sizeof (void *) * shp->sh_hashlen); 79 bzero(shp, sizeof (fmd_serd_hash_t)); 80 } 81 82 void 83 fmd_serd_hash_apply(fmd_serd_hash_t *shp, fmd_serd_eng_f *func, void *arg) 84 { 85 fmd_serd_eng_t *sgp; 86 uint_t i; 87 88 for (i = 0; i < shp->sh_hashlen; i++) { 89 for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = sgp->sg_next) 90 func(sgp, arg); 91 } 92 } 93 94 uint_t 95 fmd_serd_hash_count(fmd_serd_hash_t *shp) 96 { 97 return (shp->sh_count); 98 } 99 100 int 101 fmd_serd_hash_contains(fmd_serd_hash_t *shp, fmd_event_t *ep) 102 { 103 fmd_serd_eng_t *sgp; 104 uint_t i; 105 106 for (i = 0; i < shp->sh_hashlen; i++) { 107 for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = sgp->sg_next) { 108 if (fmd_serd_eng_contains(sgp, ep)) { 109 fmd_event_transition(ep, FMD_EVS_ACCEPTED); 110 return (1); 111 } 112 } 113 } 114 115 return (0); 116 } 117 118 fmd_serd_eng_t * 119 fmd_serd_eng_insert(fmd_serd_hash_t *shp, 120 const char *name, uint_t n, hrtime_t t) 121 { 122 uint_t h = fmd_strhash(name) % shp->sh_hashlen; 123 fmd_serd_eng_t *sgp = fmd_serd_eng_alloc(name, n, t); 124 125 sgp->sg_next = shp->sh_hash[h]; 126 shp->sh_hash[h] = sgp; 127 shp->sh_count++; 128 129 return (sgp); 130 } 131 132 fmd_serd_eng_t * 133 fmd_serd_eng_lookup(fmd_serd_hash_t *shp, const char *name) 134 { 135 uint_t h = fmd_strhash(name) % shp->sh_hashlen; 136 fmd_serd_eng_t *sgp; 137 138 for (sgp = shp->sh_hash[h]; sgp != NULL; sgp = sgp->sg_next) { 139 if (strcmp(name, sgp->sg_name) == 0) 140 return (sgp); 141 } 142 143 return (NULL); 144 } 145 146 void 147 fmd_serd_eng_delete(fmd_serd_hash_t *shp, const char *name) 148 { 149 uint_t h = fmd_strhash(name) % shp->sh_hashlen; 150 fmd_serd_eng_t *sgp, **pp = &shp->sh_hash[h]; 151 152 for (sgp = *pp; sgp != NULL; sgp = sgp->sg_next) { 153 if (strcmp(sgp->sg_name, name) != 0) 154 pp = &sgp->sg_next; 155 else 156 break; 157 } 158 159 if (sgp != NULL) { 160 *pp = sgp->sg_next; 161 fmd_serd_eng_free(sgp); 162 ASSERT(shp->sh_count != 0); 163 shp->sh_count--; 164 } 165 } 166 167 static void 168 fmd_serd_eng_discard(fmd_serd_eng_t *sgp, fmd_serd_elem_t *sep) 169 { 170 fmd_list_delete(&sgp->sg_list, sep); 171 sgp->sg_count--; 172 173 fmd_event_rele(sep->se_event); 174 fmd_free(sep, sizeof (fmd_serd_elem_t)); 175 } 176 177 int 178 fmd_serd_eng_contains(fmd_serd_eng_t *sgp, fmd_event_t *ep) 179 { 180 fmd_serd_elem_t *sep; 181 182 for (sep = fmd_list_next(&sgp->sg_list); 183 sep != NULL; sep = fmd_list_next(sep)) { 184 if (fmd_event_equal(sep->se_event, ep)) 185 return (1); 186 } 187 188 return (0); 189 } 190 191 int 192 fmd_serd_eng_record(fmd_serd_eng_t *sgp, fmd_event_t *ep) 193 { 194 fmd_serd_elem_t *sep, *oep; 195 196 /* 197 * If the fired flag is already set, return false and discard the 198 * event. This means that the caller will only see the engine "fire" 199 * once until fmd_serd_eng_reset() is called. The fmd_serd_eng_fired() 200 * function can also be used in combination with fmd_serd_eng_record(). 201 */ 202 if (sgp->sg_flags & FMD_SERD_FIRED) 203 return (FMD_B_FALSE); 204 205 while (sgp->sg_count > sgp->sg_n) 206 fmd_serd_eng_discard(sgp, fmd_list_next(&sgp->sg_list)); 207 208 fmd_event_hold(ep); 209 fmd_event_transition(ep, FMD_EVS_ACCEPTED); 210 211 sep = fmd_alloc(sizeof (fmd_serd_elem_t), FMD_SLEEP); 212 sep->se_event = ep; 213 214 fmd_list_append(&sgp->sg_list, sep); 215 sgp->sg_count++; 216 217 /* 218 * Pick up the oldest element pointer for comparison to 'sep'. We must 219 * do this after adding 'sep' because 'oep' and 'sep' can be the same. 220 */ 221 oep = fmd_list_next(&sgp->sg_list); 222 223 if (sgp->sg_count > sgp->sg_n && 224 fmd_event_delta(oep->se_event, sep->se_event) <= sgp->sg_t) { 225 sgp->sg_flags |= FMD_SERD_FIRED | FMD_SERD_DIRTY; 226 return (FMD_B_TRUE); 227 } 228 229 sgp->sg_flags |= FMD_SERD_DIRTY; 230 return (FMD_B_FALSE); 231 } 232 233 int 234 fmd_serd_eng_fired(fmd_serd_eng_t *sgp) 235 { 236 return (sgp->sg_flags & FMD_SERD_FIRED); 237 } 238 239 int 240 fmd_serd_eng_empty(fmd_serd_eng_t *sgp) 241 { 242 return (sgp->sg_count == 0); 243 } 244 245 void 246 fmd_serd_eng_reset(fmd_serd_eng_t *sgp) 247 { 248 while (sgp->sg_count != 0) 249 fmd_serd_eng_discard(sgp, fmd_list_next(&sgp->sg_list)); 250 251 sgp->sg_flags &= ~FMD_SERD_FIRED; 252 sgp->sg_flags |= FMD_SERD_DIRTY; 253 } 254 255 void 256 fmd_serd_eng_gc(fmd_serd_eng_t *sgp) 257 { 258 fmd_serd_elem_t *sep, *nep; 259 hrtime_t hrt; 260 261 if (sgp->sg_count == 0 || (sgp->sg_flags & FMD_SERD_FIRED)) 262 return; /* no garbage collection needed if empty or fired */ 263 264 sep = fmd_list_prev(&sgp->sg_list); 265 hrt = fmd_event_hrtime(sep->se_event) - sgp->sg_t; 266 267 for (sep = fmd_list_next(&sgp->sg_list); sep != NULL; sep = nep) { 268 if (fmd_event_hrtime(sep->se_event) >= hrt) 269 break; /* sep and subsequent events are all within T */ 270 271 nep = fmd_list_next(sep); 272 fmd_serd_eng_discard(sgp, sep); 273 sgp->sg_flags |= FMD_SERD_DIRTY; 274 } 275 } 276 277 void 278 fmd_serd_eng_commit(fmd_serd_eng_t *sgp) 279 { 280 fmd_serd_elem_t *sep; 281 282 if (!(sgp->sg_flags & FMD_SERD_DIRTY)) 283 return; /* engine has not changed since last commit */ 284 285 for (sep = fmd_list_next(&sgp->sg_list); sep != NULL; 286 sep = fmd_list_next(sep)) 287 fmd_event_commit(sep->se_event); 288 289 sgp->sg_flags &= ~FMD_SERD_DIRTY; 290 } 291 292 void 293 fmd_serd_eng_clrdirty(fmd_serd_eng_t *sgp) 294 { 295 sgp->sg_flags &= ~FMD_SERD_DIRTY; 296 } 297