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