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