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 *
fmd_serd_eng_alloc(const char * name,uint64_t n,hrtime_t 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
fmd_serd_eng_free(fmd_serd_eng_t * sgp)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
fmd_serd_hash_create(fmd_serd_hash_t * shp)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
fmd_serd_hash_destroy(fmd_serd_hash_t * shp)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
fmd_serd_hash_apply(fmd_serd_hash_t * shp,fmd_serd_eng_f * func,void * arg)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
fmd_serd_hash_count(fmd_serd_hash_t * shp)93 fmd_serd_hash_count(fmd_serd_hash_t *shp)
94 {
95 return (shp->sh_count);
96 }
97
98 int
fmd_serd_hash_contains(fmd_serd_hash_t * shp,fmd_event_t * ep)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 *
fmd_serd_eng_insert(fmd_serd_hash_t * shp,const char * name,uint_t n,hrtime_t 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 *
fmd_serd_eng_lookup(fmd_serd_hash_t * shp,const char * name)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
fmd_serd_eng_delete(fmd_serd_hash_t * shp,const char * name)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
fmd_serd_eng_discard(fmd_serd_eng_t * sgp,fmd_serd_elem_t * sep)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
fmd_serd_eng_contains(fmd_serd_eng_t * sgp,fmd_event_t * ep)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
fmd_serd_eng_record(void * ptr,fmd_event_t * ep)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
fmd_serd_eng_fired(fmd_serd_eng_t * sgp)233 fmd_serd_eng_fired(fmd_serd_eng_t *sgp)
234 {
235 return (sgp->sg_flags & FMD_SERD_FIRED);
236 }
237
238 int
fmd_serd_eng_empty(fmd_serd_eng_t * sgp)239 fmd_serd_eng_empty(fmd_serd_eng_t *sgp)
240 {
241 return (sgp->sg_count == 0);
242 }
243
244 void
fmd_serd_eng_reset(fmd_serd_eng_t * sgp)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
fmd_serd_eng_gc(fmd_serd_eng_t * sgp,void * arg __unused)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
fmd_serd_eng_commit(fmd_serd_eng_t * sgp,void * arg __unused)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
fmd_serd_eng_clrdirty(fmd_serd_eng_t * sgp,void * arg __unused)292 fmd_serd_eng_clrdirty(fmd_serd_eng_t *sgp, void *arg __unused)
293 {
294 sgp->sg_flags &= ~FMD_SERD_DIRTY;
295 }
296