#include <fmd_alloc.h>
#include <fmd_string.h>
#include <fmd_subr.h>
#include <fmd_api.h>
#include <fmd_serd.h>
#include <fmd.h>
static fmd_serd_eng_t *
fmd_serd_eng_alloc(const char *name, uint64_t n, hrtime_t t)
{
fmd_serd_eng_t *sgp = fmd_zalloc(sizeof (fmd_serd_eng_t), FMD_SLEEP);
sgp->sg_name = fmd_strdup(name, FMD_SLEEP);
sgp->sg_flags = FMD_SERD_DIRTY;
sgp->sg_n = n;
sgp->sg_t = t;
return (sgp);
}
static void
fmd_serd_eng_free(fmd_serd_eng_t *sgp)
{
fmd_serd_eng_reset(sgp);
fmd_strfree(sgp->sg_name);
fmd_free(sgp, sizeof (fmd_serd_eng_t));
}
void
fmd_serd_hash_create(fmd_serd_hash_t *shp)
{
shp->sh_hashlen = fmd.d_str_buckets;
shp->sh_hash = fmd_zalloc(sizeof (void *) * shp->sh_hashlen, FMD_SLEEP);
shp->sh_count = 0;
}
void
fmd_serd_hash_destroy(fmd_serd_hash_t *shp)
{
fmd_serd_eng_t *sgp, *ngp;
uint_t i;
for (i = 0; i < shp->sh_hashlen; i++) {
for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = ngp) {
ngp = sgp->sg_next;
fmd_serd_eng_free(sgp);
}
}
fmd_free(shp->sh_hash, sizeof (void *) * shp->sh_hashlen);
bzero(shp, sizeof (fmd_serd_hash_t));
}
void
fmd_serd_hash_apply(fmd_serd_hash_t *shp, fmd_serd_eng_f *func, void *arg)
{
fmd_serd_eng_t *sgp;
uint_t i;
for (i = 0; i < shp->sh_hashlen; i++) {
for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = sgp->sg_next)
func(sgp, arg);
}
}
uint_t
fmd_serd_hash_count(fmd_serd_hash_t *shp)
{
return (shp->sh_count);
}
int
fmd_serd_hash_contains(fmd_serd_hash_t *shp, fmd_event_t *ep)
{
fmd_serd_eng_t *sgp;
uint_t i;
for (i = 0; i < shp->sh_hashlen; i++) {
for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = sgp->sg_next) {
if (fmd_serd_eng_contains(sgp, ep)) {
fmd_event_transition(ep, FMD_EVS_ACCEPTED);
return (1);
}
}
}
return (0);
}
fmd_serd_eng_t *
fmd_serd_eng_insert(fmd_serd_hash_t *shp,
const char *name, uint_t n, hrtime_t t)
{
uint_t h = fmd_strhash(name) % shp->sh_hashlen;
fmd_serd_eng_t *sgp = fmd_serd_eng_alloc(name, n, t);
sgp->sg_next = shp->sh_hash[h];
shp->sh_hash[h] = sgp;
shp->sh_count++;
return (sgp);
}
fmd_serd_eng_t *
fmd_serd_eng_lookup(fmd_serd_hash_t *shp, const char *name)
{
uint_t h = fmd_strhash(name) % shp->sh_hashlen;
fmd_serd_eng_t *sgp;
for (sgp = shp->sh_hash[h]; sgp != NULL; sgp = sgp->sg_next) {
if (strcmp(name, sgp->sg_name) == 0)
return (sgp);
}
return (NULL);
}
void
fmd_serd_eng_delete(fmd_serd_hash_t *shp, const char *name)
{
uint_t h = fmd_strhash(name) % shp->sh_hashlen;
fmd_serd_eng_t *sgp, **pp = &shp->sh_hash[h];
for (sgp = *pp; sgp != NULL; sgp = sgp->sg_next) {
if (strcmp(sgp->sg_name, name) != 0)
pp = &sgp->sg_next;
else
break;
}
if (sgp != NULL) {
*pp = sgp->sg_next;
fmd_serd_eng_free(sgp);
ASSERT(shp->sh_count != 0);
shp->sh_count--;
}
}
static void
fmd_serd_eng_discard(fmd_serd_eng_t *sgp, fmd_serd_elem_t *sep)
{
fmd_list_delete(&sgp->sg_list, sep);
sgp->sg_count--;
fmd_event_rele(sep->se_event);
fmd_free(sep, sizeof (fmd_serd_elem_t));
}
int
fmd_serd_eng_contains(fmd_serd_eng_t *sgp, fmd_event_t *ep)
{
fmd_serd_elem_t *sep;
for (sep = fmd_list_next(&sgp->sg_list);
sep != NULL; sep = fmd_list_next(sep)) {
if (fmd_event_equal(sep->se_event, ep))
return (1);
}
return (0);
}
int
fmd_serd_eng_record(void *ptr, fmd_event_t *ep)
{
fmd_serd_eng_t *sgp = ptr;
fmd_serd_elem_t *sep, *oep;
if (sgp->sg_flags & FMD_SERD_FIRED)
return (FMD_B_FALSE);
while (sgp->sg_count > sgp->sg_n)
fmd_serd_eng_discard(sgp, fmd_list_next(&sgp->sg_list));
fmd_event_hold(ep);
fmd_event_transition(ep, FMD_EVS_ACCEPTED);
sep = fmd_alloc(sizeof (fmd_serd_elem_t), FMD_SLEEP);
sep->se_event = ep;
fmd_list_append(&sgp->sg_list, sep);
sgp->sg_count++;
oep = fmd_list_next(&sgp->sg_list);
if (sgp->sg_count > sgp->sg_n &&
fmd_event_delta(oep->se_event, sep->se_event) <= sgp->sg_t) {
sgp->sg_flags |= FMD_SERD_FIRED | FMD_SERD_DIRTY;
return (FMD_B_TRUE);
}
sgp->sg_flags |= FMD_SERD_DIRTY;
return (FMD_B_FALSE);
}
int
fmd_serd_eng_fired(fmd_serd_eng_t *sgp)
{
return (sgp->sg_flags & FMD_SERD_FIRED);
}
int
fmd_serd_eng_empty(fmd_serd_eng_t *sgp)
{
return (sgp->sg_count == 0);
}
void
fmd_serd_eng_reset(fmd_serd_eng_t *sgp)
{
while (sgp->sg_count != 0)
fmd_serd_eng_discard(sgp, fmd_list_next(&sgp->sg_list));
sgp->sg_flags &= ~FMD_SERD_FIRED;
sgp->sg_flags |= FMD_SERD_DIRTY;
}
void
fmd_serd_eng_gc(fmd_serd_eng_t *sgp, void *arg __unused)
{
fmd_serd_elem_t *sep, *nep;
hrtime_t hrt;
if (sgp->sg_count == 0 || (sgp->sg_flags & FMD_SERD_FIRED))
return;
sep = fmd_list_prev(&sgp->sg_list);
hrt = fmd_event_hrtime(sep->se_event) - sgp->sg_t;
for (sep = fmd_list_next(&sgp->sg_list); sep != NULL; sep = nep) {
if (fmd_event_hrtime(sep->se_event) >= hrt)
break;
nep = fmd_list_next(sep);
fmd_serd_eng_discard(sgp, sep);
sgp->sg_flags |= FMD_SERD_DIRTY;
}
}
void
fmd_serd_eng_commit(fmd_serd_eng_t *sgp, void *arg __unused)
{
fmd_serd_elem_t *sep;
if (!(sgp->sg_flags & FMD_SERD_DIRTY))
return;
for (sep = fmd_list_next(&sgp->sg_list); sep != NULL;
sep = fmd_list_next(sep))
fmd_event_commit(sep->se_event);
sgp->sg_flags &= ~FMD_SERD_DIRTY;
}
void
fmd_serd_eng_clrdirty(fmd_serd_eng_t *sgp, void *arg __unused)
{
sgp->sg_flags &= ~FMD_SERD_DIRTY;
}