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 https://opensource.org/licenses/CDDL-1.0.
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.
26 * Copyright (c) 2016, Intel Corporation.
38 #include "../zed_log.h"
41 #define FMD_STR_BUCKETS 211
45 #define serd_log_msg(fmt, ...) \
46 zed_log_msg(LOG_INFO, fmt, __VA_ARGS__)
48 #define serd_log_msg(fmt, ...)
57 * Compute the delta between events in nanoseconds. To account for very old
58 * events which are replayed, we must handle the case where time is negative.
59 * We convert the hrtime_t's to unsigned 64-bit integers and then handle the
60 * case where 'old' is greater than 'new' (i.e. high-res time has wrapped).
63 fmd_event_delta(hrtime_t t1
, hrtime_t t2
)
68 return (new >= old
? new - old
: (UINT64_MAX
- old
) + new + 1);
71 static fmd_serd_eng_t
*
72 fmd_serd_eng_alloc(const char *name
, uint64_t n
, hrtime_t t
)
76 sgp
= malloc(sizeof (fmd_serd_eng_t
));
81 memset(sgp
, 0, sizeof (fmd_serd_eng_t
));
83 sgp
->sg_name
= strdup(name
);
84 if (sgp
->sg_name
== NULL
) {
89 sgp
->sg_flags
= FMD_SERD_DIRTY
;
93 list_create(&sgp
->sg_list
, sizeof (fmd_serd_elem_t
),
94 offsetof(fmd_serd_elem_t
, se_list
));
100 fmd_serd_eng_free(fmd_serd_eng_t
*sgp
)
102 fmd_serd_eng_reset(sgp
);
104 list_destroy(&sgp
->sg_list
);
109 * sourced from fmd_string.c
112 fmd_strhash(const char *key
)
117 for (p
= key
; *p
!= '\0'; p
++) {
120 if ((g
= (h
& 0xf0000000)) != 0) {
130 fmd_serd_hash_create(fmd_serd_hash_t
*shp
)
132 shp
->sh_hashlen
= FMD_STR_BUCKETS
;
133 shp
->sh_hash
= calloc(shp
->sh_hashlen
, sizeof (void *));
136 if (shp
->sh_hash
== NULL
) {
144 fmd_serd_hash_destroy(fmd_serd_hash_t
*shp
)
146 fmd_serd_eng_t
*sgp
, *ngp
;
149 for (i
= 0; i
< shp
->sh_hashlen
; i
++) {
150 for (sgp
= shp
->sh_hash
[i
]; sgp
!= NULL
; sgp
= ngp
) {
152 fmd_serd_eng_free(sgp
);
157 memset(shp
, 0, sizeof (fmd_serd_hash_t
));
161 fmd_serd_hash_apply(fmd_serd_hash_t
*shp
, fmd_serd_eng_f
*func
, void *arg
)
166 for (i
= 0; i
< shp
->sh_hashlen
; i
++) {
167 for (sgp
= shp
->sh_hash
[i
]; sgp
!= NULL
; sgp
= sgp
->sg_next
)
173 fmd_serd_eng_insert(fmd_serd_hash_t
*shp
, const char *name
,
174 uint_t n
, hrtime_t t
)
176 uint_t h
= fmd_strhash(name
) % shp
->sh_hashlen
;
177 fmd_serd_eng_t
*sgp
= fmd_serd_eng_alloc(name
, n
, t
);
179 serd_log_msg(" SERD Engine: inserting %s N %d T %llu",
180 name
, (int)n
, (long long unsigned)t
);
182 sgp
->sg_next
= shp
->sh_hash
[h
];
183 shp
->sh_hash
[h
] = sgp
;
190 fmd_serd_eng_lookup(fmd_serd_hash_t
*shp
, const char *name
)
192 uint_t h
= fmd_strhash(name
) % shp
->sh_hashlen
;
195 for (sgp
= shp
->sh_hash
[h
]; sgp
!= NULL
; sgp
= sgp
->sg_next
) {
196 if (strcmp(name
, sgp
->sg_name
) == 0)
204 fmd_serd_eng_delete(fmd_serd_hash_t
*shp
, const char *name
)
206 uint_t h
= fmd_strhash(name
) % shp
->sh_hashlen
;
207 fmd_serd_eng_t
*sgp
, **pp
= &shp
->sh_hash
[h
];
209 serd_log_msg(" SERD Engine: deleting %s", name
);
211 for (sgp
= *pp
; sgp
!= NULL
; sgp
= sgp
->sg_next
) {
212 if (strcmp(sgp
->sg_name
, name
) != 0)
220 fmd_serd_eng_free(sgp
);
221 assert(shp
->sh_count
!= 0);
227 fmd_serd_eng_discard(fmd_serd_eng_t
*sgp
, fmd_serd_elem_t
*sep
)
229 list_remove(&sgp
->sg_list
, sep
);
232 serd_log_msg(" SERD Engine: discarding %s, %d remaining",
233 sgp
->sg_name
, (int)sgp
->sg_count
);
239 fmd_serd_eng_record(fmd_serd_eng_t
*sgp
, hrtime_t hrt
)
241 fmd_serd_elem_t
*sep
, *oep
;
244 * If the fired flag is already set, return false and discard the
245 * event. This means that the caller will only see the engine "fire"
246 * once until fmd_serd_eng_reset() is called. The fmd_serd_eng_fired()
247 * function can also be used in combination with fmd_serd_eng_record().
249 if (sgp
->sg_flags
& FMD_SERD_FIRED
) {
250 serd_log_msg(" SERD Engine: record %s already fired!",
255 while (sgp
->sg_count
>= sgp
->sg_n
)
256 fmd_serd_eng_discard(sgp
, list_tail(&sgp
->sg_list
));
258 sep
= malloc(sizeof (fmd_serd_elem_t
));
265 list_insert_head(&sgp
->sg_list
, sep
);
268 serd_log_msg(" SERD Engine: recording %s of %d (%llu)",
269 sgp
->sg_name
, (int)sgp
->sg_count
, (long long unsigned)hrt
);
272 * Pick up the oldest element pointer for comparison to 'sep'. We must
273 * do this after adding 'sep' because 'oep' and 'sep' can be the same.
275 oep
= list_tail(&sgp
->sg_list
);
277 if (sgp
->sg_count
>= sgp
->sg_n
&&
278 fmd_event_delta(oep
->se_hrt
, sep
->se_hrt
) <= sgp
->sg_t
) {
279 sgp
->sg_flags
|= FMD_SERD_FIRED
| FMD_SERD_DIRTY
;
280 serd_log_msg(" SERD Engine: fired %s", sgp
->sg_name
);
284 sgp
->sg_flags
|= FMD_SERD_DIRTY
;
289 fmd_serd_eng_fired(fmd_serd_eng_t
*sgp
)
291 return (sgp
->sg_flags
& FMD_SERD_FIRED
);
295 fmd_serd_eng_empty(fmd_serd_eng_t
*sgp
)
297 return (sgp
->sg_count
== 0);
301 fmd_serd_eng_reset(fmd_serd_eng_t
*sgp
)
303 serd_log_msg(" SERD Engine: resetting %s", sgp
->sg_name
);
305 while (sgp
->sg_count
!= 0)
306 fmd_serd_eng_discard(sgp
, list_head(&sgp
->sg_list
));
308 sgp
->sg_flags
&= ~FMD_SERD_FIRED
;
309 sgp
->sg_flags
|= FMD_SERD_DIRTY
;
313 fmd_serd_eng_gc(fmd_serd_eng_t
*sgp
, void *arg
)
316 fmd_serd_elem_t
*sep
, *nep
;
319 if (sgp
->sg_count
== 0 || (sgp
->sg_flags
& FMD_SERD_FIRED
))
320 return; /* no garbage collection needed if empty or fired */
322 sep
= list_head(&sgp
->sg_list
);
326 hrt
= sep
->se_hrt
- sgp
->sg_t
;
328 for (sep
= list_head(&sgp
->sg_list
); sep
!= NULL
; sep
= nep
) {
329 if (sep
->se_hrt
>= hrt
)
330 break; /* sep and subsequent events are all within T */
332 nep
= list_next(&sgp
->sg_list
, sep
);
333 fmd_serd_eng_discard(sgp
, sep
);
334 sgp
->sg_flags
|= FMD_SERD_DIRTY
;