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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <fmd_alloc.h>
30 #include <fmd_string.h>
36 static fmd_serd_eng_t
*
37 fmd_serd_eng_alloc(const char *name
, uint64_t n
, hrtime_t t
)
39 fmd_serd_eng_t
*sgp
= fmd_zalloc(sizeof (fmd_serd_eng_t
), FMD_SLEEP
);
41 sgp
->sg_name
= fmd_strdup(name
, FMD_SLEEP
);
42 sgp
->sg_flags
= FMD_SERD_DIRTY
;
50 fmd_serd_eng_free(fmd_serd_eng_t
*sgp
)
52 fmd_serd_eng_reset(sgp
);
53 fmd_strfree(sgp
->sg_name
);
54 fmd_free(sgp
, sizeof (fmd_serd_eng_t
));
58 fmd_serd_hash_create(fmd_serd_hash_t
*shp
)
60 shp
->sh_hashlen
= fmd
.d_str_buckets
;
61 shp
->sh_hash
= fmd_zalloc(sizeof (void *) * shp
->sh_hashlen
, FMD_SLEEP
);
66 fmd_serd_hash_destroy(fmd_serd_hash_t
*shp
)
68 fmd_serd_eng_t
*sgp
, *ngp
;
71 for (i
= 0; i
< shp
->sh_hashlen
; i
++) {
72 for (sgp
= shp
->sh_hash
[i
]; sgp
!= NULL
; sgp
= ngp
) {
74 fmd_serd_eng_free(sgp
);
78 fmd_free(shp
->sh_hash
, sizeof (void *) * shp
->sh_hashlen
);
79 bzero(shp
, sizeof (fmd_serd_hash_t
));
83 fmd_serd_hash_apply(fmd_serd_hash_t
*shp
, fmd_serd_eng_f
*func
, void *arg
)
88 for (i
= 0; i
< shp
->sh_hashlen
; i
++) {
89 for (sgp
= shp
->sh_hash
[i
]; sgp
!= NULL
; sgp
= sgp
->sg_next
)
95 fmd_serd_hash_count(fmd_serd_hash_t
*shp
)
97 return (shp
->sh_count
);
101 fmd_serd_hash_contains(fmd_serd_hash_t
*shp
, fmd_event_t
*ep
)
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
);
119 fmd_serd_eng_insert(fmd_serd_hash_t
*shp
,
120 const char *name
, uint_t n
, hrtime_t t
)
122 uint_t h
= fmd_strhash(name
) % shp
->sh_hashlen
;
123 fmd_serd_eng_t
*sgp
= fmd_serd_eng_alloc(name
, n
, t
);
125 sgp
->sg_next
= shp
->sh_hash
[h
];
126 shp
->sh_hash
[h
] = sgp
;
133 fmd_serd_eng_lookup(fmd_serd_hash_t
*shp
, const char *name
)
135 uint_t h
= fmd_strhash(name
) % shp
->sh_hashlen
;
138 for (sgp
= shp
->sh_hash
[h
]; sgp
!= NULL
; sgp
= sgp
->sg_next
) {
139 if (strcmp(name
, sgp
->sg_name
) == 0)
147 fmd_serd_eng_delete(fmd_serd_hash_t
*shp
, const char *name
)
149 uint_t h
= fmd_strhash(name
) % shp
->sh_hashlen
;
150 fmd_serd_eng_t
*sgp
, **pp
= &shp
->sh_hash
[h
];
152 for (sgp
= *pp
; sgp
!= NULL
; sgp
= sgp
->sg_next
) {
153 if (strcmp(sgp
->sg_name
, name
) != 0)
161 fmd_serd_eng_free(sgp
);
162 ASSERT(shp
->sh_count
!= 0);
168 fmd_serd_eng_discard(fmd_serd_eng_t
*sgp
, fmd_serd_elem_t
*sep
)
170 fmd_list_delete(&sgp
->sg_list
, sep
);
173 fmd_event_rele(sep
->se_event
);
174 fmd_free(sep
, sizeof (fmd_serd_elem_t
));
178 fmd_serd_eng_contains(fmd_serd_eng_t
*sgp
, fmd_event_t
*ep
)
180 fmd_serd_elem_t
*sep
;
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
))
192 fmd_serd_eng_record(fmd_serd_eng_t
*sgp
, fmd_event_t
*ep
)
194 fmd_serd_elem_t
*sep
, *oep
;
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().
202 if (sgp
->sg_flags
& FMD_SERD_FIRED
)
203 return (FMD_B_FALSE
);
205 while (sgp
->sg_count
> sgp
->sg_n
)
206 fmd_serd_eng_discard(sgp
, fmd_list_next(&sgp
->sg_list
));
209 fmd_event_transition(ep
, FMD_EVS_ACCEPTED
);
211 sep
= fmd_alloc(sizeof (fmd_serd_elem_t
), FMD_SLEEP
);
214 fmd_list_append(&sgp
->sg_list
, sep
);
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.
221 oep
= fmd_list_next(&sgp
->sg_list
);
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
;
229 sgp
->sg_flags
|= FMD_SERD_DIRTY
;
230 return (FMD_B_FALSE
);
234 fmd_serd_eng_fired(fmd_serd_eng_t
*sgp
)
236 return (sgp
->sg_flags
& FMD_SERD_FIRED
);
240 fmd_serd_eng_empty(fmd_serd_eng_t
*sgp
)
242 return (sgp
->sg_count
== 0);
246 fmd_serd_eng_reset(fmd_serd_eng_t
*sgp
)
248 while (sgp
->sg_count
!= 0)
249 fmd_serd_eng_discard(sgp
, fmd_list_next(&sgp
->sg_list
));
251 sgp
->sg_flags
&= ~FMD_SERD_FIRED
;
252 sgp
->sg_flags
|= FMD_SERD_DIRTY
;
256 fmd_serd_eng_gc(fmd_serd_eng_t
*sgp
)
258 fmd_serd_elem_t
*sep
, *nep
;
261 if (sgp
->sg_count
== 0 || (sgp
->sg_flags
& FMD_SERD_FIRED
))
262 return; /* no garbage collection needed if empty or fired */
264 sep
= fmd_list_prev(&sgp
->sg_list
);
265 hrt
= fmd_event_hrtime(sep
->se_event
) - sgp
->sg_t
;
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 */
271 nep
= fmd_list_next(sep
);
272 fmd_serd_eng_discard(sgp
, sep
);
273 sgp
->sg_flags
|= FMD_SERD_DIRTY
;
278 fmd_serd_eng_commit(fmd_serd_eng_t
*sgp
)
280 fmd_serd_elem_t
*sep
;
282 if (!(sgp
->sg_flags
& FMD_SERD_DIRTY
))
283 return; /* engine has not changed since last commit */
285 for (sep
= fmd_list_next(&sgp
->sg_list
); sep
!= NULL
;
286 sep
= fmd_list_next(sep
))
287 fmd_event_commit(sep
->se_event
);
289 sgp
->sg_flags
&= ~FMD_SERD_DIRTY
;
293 fmd_serd_eng_clrdirty(fmd_serd_eng_t
*sgp
)
295 sgp
->sg_flags
&= ~FMD_SERD_DIRTY
;