xref: /titanic_52/usr/src/cmd/fm/fmd/common/fmd_dispq.c (revision cbf75e67acb6c32a2f4884f28a839d59f7988d37)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
525c6ff4bSstephh  * Common Development and Distribution License (the "License").
625c6ff4bSstephh  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21dde64cd7Smws 
227c478bd9Sstevel@tonic-gate /*
23*cbf75e67SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
28d9638e54Smws #include <sys/bitmap.h>
29d9638e54Smws 
307c478bd9Sstevel@tonic-gate #include <strings.h>
31d9638e54Smws #include <limits.h>
327c478bd9Sstevel@tonic-gate #include <alloca.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <fmd_alloc.h>
357c478bd9Sstevel@tonic-gate #include <fmd_string.h>
36d9638e54Smws #include <fmd_module.h>
377c478bd9Sstevel@tonic-gate #include <fmd_dispq.h>
387c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
39d9638e54Smws 
407c478bd9Sstevel@tonic-gate #include <fmd.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate static fmd_dispqelem_t *
437c478bd9Sstevel@tonic-gate fmd_dispqelem_create(const char *name)
447c478bd9Sstevel@tonic-gate {
457c478bd9Sstevel@tonic-gate 	fmd_dispqelem_t *dep = fmd_alloc(sizeof (fmd_dispqelem_t), FMD_SLEEP);
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	dep->dq_name = fmd_strdup(name, FMD_SLEEP);
487c478bd9Sstevel@tonic-gate 	dep->dq_link = NULL;
497c478bd9Sstevel@tonic-gate 	dep->dq_hashlen = fmd.d_str_buckets;
507c478bd9Sstevel@tonic-gate 	dep->dq_hash = fmd_zalloc(sizeof (void *) * dep->dq_hashlen, FMD_SLEEP);
517c478bd9Sstevel@tonic-gate 	dep->dq_list = NULL;
527c478bd9Sstevel@tonic-gate 	dep->dq_refs = 0;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 	return (dep);
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static void
587c478bd9Sstevel@tonic-gate fmd_dispqelem_destroy(fmd_dispqelem_t *dep)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate 	fmd_dispqlist_t *dlp, *nlp;
617c478bd9Sstevel@tonic-gate 	fmd_dispqelem_t *p, *q;
627c478bd9Sstevel@tonic-gate 	uint_t i;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	for (dlp = dep->dq_list; dlp != NULL; dlp = nlp) {
657c478bd9Sstevel@tonic-gate 		nlp = dlp->dq_next;
667c478bd9Sstevel@tonic-gate 		fmd_free(dlp, sizeof (fmd_dispqlist_t));
677c478bd9Sstevel@tonic-gate 	}
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	for (i = 0; i < dep->dq_hashlen; i++) {
707c478bd9Sstevel@tonic-gate 		for (p = dep->dq_hash[i]; p != NULL; p = q) {
717c478bd9Sstevel@tonic-gate 			q = p->dq_link;
727c478bd9Sstevel@tonic-gate 			fmd_dispqelem_destroy(p);
737c478bd9Sstevel@tonic-gate 		}
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	fmd_free(dep->dq_hash, sizeof (void *) * dep->dq_hashlen);
777c478bd9Sstevel@tonic-gate 	fmd_strfree(dep->dq_name);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	fmd_free(dep, sizeof (fmd_dispqelem_t));
807c478bd9Sstevel@tonic-gate }
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static fmd_dispqelem_t *
837c478bd9Sstevel@tonic-gate fmd_dispqelem_lookup(fmd_dispqelem_t *dep, const char *name)
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate 	uint_t h = fmd_strhash(name) % dep->dq_hashlen;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	for (dep = dep->dq_hash[h]; dep != NULL; dep = dep->dq_link) {
887c478bd9Sstevel@tonic-gate 		if (strcmp(dep->dq_name, name) == 0)
897c478bd9Sstevel@tonic-gate 			break;
907c478bd9Sstevel@tonic-gate 	}
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	return (dep);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate fmd_dispq_t *
967c478bd9Sstevel@tonic-gate fmd_dispq_create(void)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	fmd_dispq_t *dqp = fmd_alloc(sizeof (fmd_dispq_t), FMD_SLEEP);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_init(&dqp->dq_lock, NULL);
1017c478bd9Sstevel@tonic-gate 	dqp->dq_root = fmd_dispqelem_create(NULL);
102d9638e54Smws 	dqp->dq_gids = fmd_idspace_create("dispq_gids", 1, INT_MAX);
103d9638e54Smws 	dqp->dq_gmax = 0;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	return (dqp);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate void
1097c478bd9Sstevel@tonic-gate fmd_dispq_destroy(fmd_dispq_t *dqp)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	fmd_dispqelem_destroy(dqp->dq_root);
112d9638e54Smws 	fmd_idspace_destroy(dqp->dq_gids);
1137c478bd9Sstevel@tonic-gate 	fmd_free(dqp, sizeof (fmd_dispq_t));
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static fmd_dispqelem_t *
1177c478bd9Sstevel@tonic-gate fmd_dispq_insert_one(fmd_dispqelem_t *dep, const char *name)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	uint_t h = fmd_strhash(name) % dep->dq_hashlen;
1207c478bd9Sstevel@tonic-gate 	fmd_dispqelem_t *ep;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	for (ep = dep->dq_hash[h]; ep != NULL; ep = ep->dq_link) {
1237c478bd9Sstevel@tonic-gate 		if (strcmp(ep->dq_name, name) == 0)
1247c478bd9Sstevel@tonic-gate 			break;
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
1287c478bd9Sstevel@tonic-gate 		ep = fmd_dispqelem_create(name);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 		ep->dq_link = dep->dq_hash[h];
1317c478bd9Sstevel@tonic-gate 		dep->dq_hash[h] = ep;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		dep->dq_refs++;
1347c478bd9Sstevel@tonic-gate 		ASSERT(dep->dq_refs != 0);
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	return (ep);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate void
141d9638e54Smws fmd_dispq_insert(fmd_dispq_t *dqp, fmd_eventq_t *eqp, const char *pattern)
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	char *p, *q, *s = fmd_strdup(pattern, FMD_SLEEP);
1447c478bd9Sstevel@tonic-gate 	size_t len = strlen(s);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	fmd_dispqlist_t *dlp = fmd_alloc(sizeof (fmd_dispqlist_t), FMD_SLEEP);
1477c478bd9Sstevel@tonic-gate 	fmd_dispqelem_t *dep;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&dqp->dq_lock);
1507c478bd9Sstevel@tonic-gate 	dep = dqp->dq_root;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	for (p = strtok_r(s, ".", &q); p != NULL; p = strtok_r(NULL, ".", &q))
1537c478bd9Sstevel@tonic-gate 		dep = fmd_dispq_insert_one(dep, p);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	dlp->dq_next = dep->dq_list;
156d9638e54Smws 	dlp->dq_eventq = eqp;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	dep->dq_list = dlp;
1597c478bd9Sstevel@tonic-gate 	dep->dq_refs++;
1607c478bd9Sstevel@tonic-gate 	ASSERT(dep->dq_refs != 0);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&dqp->dq_lock);
1637c478bd9Sstevel@tonic-gate 	fmd_free(s, len + 1);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static void
1677c478bd9Sstevel@tonic-gate fmd_dispq_delete_one(fmd_dispqelem_t *dep,
168d9638e54Smws     fmd_eventq_t *eqp, int patc, char *patv[])
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	fmd_dispqlist_t *lp, **lpp;
1717c478bd9Sstevel@tonic-gate 	fmd_dispqelem_t *ep, **epp;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	uint_t h = fmd_strhash(patv[0]) % dep->dq_hashlen;
1747c478bd9Sstevel@tonic-gate 	epp = &dep->dq_hash[h];
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	for (ep = *epp; ep != NULL; ep = ep->dq_link) {
1777c478bd9Sstevel@tonic-gate 		if (strcmp(ep->dq_name, patv[0]) != 0)
1787c478bd9Sstevel@tonic-gate 			epp = &ep->dq_link;
1797c478bd9Sstevel@tonic-gate 		else
1807c478bd9Sstevel@tonic-gate 			break;
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	ASSERT(ep != NULL);
1847c478bd9Sstevel@tonic-gate 	lpp = &ep->dq_list;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (patc > 1) {
187d9638e54Smws 		fmd_dispq_delete_one(ep, eqp, patc - 1, patv + 1);
1887c478bd9Sstevel@tonic-gate 	} else {
1897c478bd9Sstevel@tonic-gate 		for (lp = *lpp; lp != NULL; lp = lp->dq_next) {
190d9638e54Smws 			if (lp->dq_eventq != eqp)
1917c478bd9Sstevel@tonic-gate 				lpp = &lp->dq_next;
1927c478bd9Sstevel@tonic-gate 			else
1937c478bd9Sstevel@tonic-gate 				break;
1947c478bd9Sstevel@tonic-gate 		}
1957c478bd9Sstevel@tonic-gate 
196d9638e54Smws 		if (lp != NULL) {
1977c478bd9Sstevel@tonic-gate 			*lpp = lp->dq_next;
1987c478bd9Sstevel@tonic-gate 			fmd_free(lp, sizeof (fmd_dispqlist_t));
1997c478bd9Sstevel@tonic-gate 			ASSERT(ep->dq_refs != 0);
2007c478bd9Sstevel@tonic-gate 			ep->dq_refs--;
2017c478bd9Sstevel@tonic-gate 		}
202d9638e54Smws 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if (ep->dq_refs == 0) {
2057c478bd9Sstevel@tonic-gate 		*epp = ep->dq_link;
2067c478bd9Sstevel@tonic-gate 		fmd_dispqelem_destroy(ep);
2077c478bd9Sstevel@tonic-gate 		ASSERT(dep->dq_refs != 0);
2087c478bd9Sstevel@tonic-gate 		dep->dq_refs--;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate void
213d9638e54Smws fmd_dispq_delete(fmd_dispq_t *dqp, fmd_eventq_t *eqp, const char *pattern)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	char *p, *q, *s = fmd_strdup(pattern, FMD_SLEEP);
2167c478bd9Sstevel@tonic-gate 	size_t len = strlen(s);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	char **patv = fmd_zalloc(sizeof (char *) * (len / 2 + 1), FMD_SLEEP);
2197c478bd9Sstevel@tonic-gate 	int patc = 0;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	for (p = strtok_r(s, ".", &q); p != NULL; p = strtok_r(NULL, ".", &q))
2227c478bd9Sstevel@tonic-gate 		patv[patc++] = p;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (patc != 0) {
2257c478bd9Sstevel@tonic-gate 		(void) pthread_rwlock_wrlock(&dqp->dq_lock);
226d9638e54Smws 		fmd_dispq_delete_one(dqp->dq_root, eqp, patc, patv);
2277c478bd9Sstevel@tonic-gate 		(void) pthread_rwlock_unlock(&dqp->dq_lock);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	fmd_free(patv, sizeof (char *) * (len / 2 + 1));
2317c478bd9Sstevel@tonic-gate 	fmd_free(s, len + 1);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static uint_t
235d9638e54Smws fmd_dispq_dispatch_one(fmd_dispqelem_t *dep, ulong_t *gids,
236d9638e54Smws     fmd_event_t *ep, const char *class)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate 	fmd_dispqlist_t *dlp;
2397c478bd9Sstevel@tonic-gate 	uint_t n = 0;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	for (dlp = dep->dq_list; dlp != NULL; dlp = dlp->dq_next, n++) {
242d9638e54Smws 		id_t gid = dlp->dq_eventq->eq_sgid;
2437c478bd9Sstevel@tonic-gate 
244d9638e54Smws 		if (BT_TEST(gids, gid) != 0)
245d9638e54Smws 			continue; /* event already queued for this group ID */
246d9638e54Smws 
247d9638e54Smws 		TRACE((FMD_DBG_DISP, "queue %p (%s) for %s (%d)", (void *)ep,
248d9638e54Smws 		    class, dlp->dq_eventq->eq_mod->mod_name, (int)gid));
249d9638e54Smws 
250d9638e54Smws 		fmd_eventq_insert_at_time(dlp->dq_eventq, ep);
251d9638e54Smws 		BT_SET(gids, gid);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	return (n);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * This function handles the descent of the dispatch queue hash tree on behalf
2597c478bd9Sstevel@tonic-gate  * of fmd_dispq_dispatch().  We recursively descend the tree along two paths:
2607c478bd9Sstevel@tonic-gate  * one using the next component of the split class string (stored in cv[0]) and
2617c478bd9Sstevel@tonic-gate  * one using the wildcard "*" in place of cv[0].  If we can't find either one,
2627c478bd9Sstevel@tonic-gate  * our descent stops.  If we descend far enough to consume cv[] (i.e. cc == 0),
2637c478bd9Sstevel@tonic-gate  * then we have a match and we dispatch the event to all modules at that level.
2647c478bd9Sstevel@tonic-gate  * We also dispatch the event to modules found at any interior "*" element,
2657c478bd9Sstevel@tonic-gate  * allowing a subscription to "a.*" to match "a.b", "a.b.c", and so on.
2667c478bd9Sstevel@tonic-gate  */
2677c478bd9Sstevel@tonic-gate static uint_t
268d9638e54Smws fmd_dispq_dispatchv(fmd_dispqelem_t *root, ulong_t *gids,
2697c478bd9Sstevel@tonic-gate     fmd_event_t *ep, const char *class, uint_t cc, char *cv[])
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	fmd_dispqelem_t *dep;
2727c478bd9Sstevel@tonic-gate 	uint_t n = 0;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if (cc == 0)
275d9638e54Smws 		return (fmd_dispq_dispatch_one(root, gids, ep, class));
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if ((dep = fmd_dispqelem_lookup(root, cv[0])) != NULL)
278d9638e54Smws 		n += fmd_dispq_dispatchv(dep, gids, ep, class, cc - 1, cv + 1);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	if ((dep = fmd_dispqelem_lookup(root, "*")) != NULL)
281d9638e54Smws 		n += fmd_dispq_dispatchv(dep, gids, ep, class, cc - 1, cv + 1);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (dep != NULL && cc > 1)
284d9638e54Smws 		n += fmd_dispq_dispatch_one(dep, gids, ep, class);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	return (n);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
289d9638e54Smws static uint_t
290d9638e54Smws fmd_dispq_tokenize(const char *class,
291d9638e54Smws     char *buf, size_t buflen, char **cv, uint_t cvlen)
2927c478bd9Sstevel@tonic-gate {
293d9638e54Smws 	uint_t cc = 0;
294d9638e54Smws 	char *p, *q;
2957c478bd9Sstevel@tonic-gate 
296d9638e54Smws 	(void) strlcpy(buf, class, buflen);
297d9638e54Smws 
298d9638e54Smws 	for (p = strtok_r(buf, ".", &q); p != NULL; p = strtok_r(NULL, ".", &q))
299d9638e54Smws 		cv[cc++] = p;
300d9638e54Smws 
301d9638e54Smws 	if (cc > cvlen)
302d9638e54Smws 		fmd_panic("fmd_dispq_tokenize() cc=%u > cv[%u]\n", cc, cvlen);
303d9638e54Smws 
304d9638e54Smws 	return (cc);
305d9638e54Smws }
306d9638e54Smws 
307d9638e54Smws void
308d9638e54Smws fmd_dispq_dispatch_gid(fmd_dispq_t *dqp,
309d9638e54Smws     fmd_event_t *ep, const char *class, id_t gid)
310d9638e54Smws {
311dde64cd7Smws 	size_t cvbuflen = strlen(class) + 1;
312d9638e54Smws 	uint_t cc, cvlen, n = 0;
313d9638e54Smws 	char *c, *cvbuf, **cv;
314d9638e54Smws 
315d9638e54Smws 	ulong_t *gids;
316d9638e54Smws 	uint_t glen, i;
317d9638e54Smws 
318d9638e54Smws 	nvlist_t **nva;
319d9638e54Smws 	uint_t nvi, nvc = 0;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	fmd_event_hold(ep);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	/*
3247c478bd9Sstevel@tonic-gate 	 * If the event is a protocol list.suspect event with one or more
325d9638e54Smws 	 * events contained inside of it, determine the maximum length of all
326d9638e54Smws 	 * class strings that will be used in this dispatch operation.
3277c478bd9Sstevel@tonic-gate 	 */
32825c6ff4bSstephh 	if (FMD_EVENT_TYPE(ep) == FMD_EVT_PROTOCOL &&
32925c6ff4bSstephh 	    (strcmp(class, FM_LIST_SUSPECT_CLASS) == 0 ||
33025c6ff4bSstephh 	    strcmp(class, FM_LIST_REPAIRED_CLASS) == 0 ||
331*cbf75e67SStephen Hanson 	    strcmp(class, FM_LIST_RESOLVED_CLASS) == 0 ||
33225c6ff4bSstephh 	    strcmp(class, FM_LIST_UPDATED_CLASS) == 0) &&
33325c6ff4bSstephh 	    nvlist_lookup_nvlist_array(FMD_EVENT_NVL(ep), FM_SUSPECT_FAULT_LIST,
33425c6ff4bSstephh 	    &nva, &nvc) == 0) {
335d9638e54Smws 		for (nvi = 0; nvi < nvc; nvi++) {
336d9638e54Smws 			if (nvlist_lookup_string(nva[nvi], FM_CLASS, &c) == 0) {
337dde64cd7Smws 				size_t len = strlen(c) + 1;
338d9638e54Smws 				cvbuflen = MAX(cvbuflen, len);
3397c478bd9Sstevel@tonic-gate 			}
3407c478bd9Sstevel@tonic-gate 		}
341d9638e54Smws 	}
342d9638e54Smws 
343dde64cd7Smws 	cvbuf = alloca(cvbuflen);
344d9638e54Smws 	cvlen = cvbuflen / 2 + 1;
345d9638e54Smws 	cv = alloca(sizeof (char *) * cvlen);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/*
348d9638e54Smws 	 * With dq_lock held as reader, allocate a bitmap on the stack for
349d9638e54Smws 	 * group IDs for this dispatch, zero it, and then do the dispatch.
3507c478bd9Sstevel@tonic-gate 	 */
3517c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&dqp->dq_lock);
352d9638e54Smws 
353d9638e54Smws 	glen = BT_BITOUL(dqp->dq_gmax);
354d9638e54Smws 	gids = alloca(sizeof (ulong_t) * glen);
355d9638e54Smws 	bzero(gids, sizeof (ulong_t) * glen);
356d9638e54Smws 
357d9638e54Smws 	/*
358d9638e54Smws 	 * If we are dispatching to only a single gid, set all bits in the
359d9638e54Smws 	 * group IDs mask and then clear only the bit for the specified gid.
360d9638e54Smws 	 */
361d9638e54Smws 	if (gid >= 0) {
362d9638e54Smws 		for (i = 0; i < glen; i++)
363d9638e54Smws 			gids[i] = BT_ULMAXMASK;
364d9638e54Smws 		BT_CLEAR(gids, gid);
365d9638e54Smws 	}
366d9638e54Smws 
367d9638e54Smws 	for (nvi = 0; nvi < nvc; nvi++) {
368d9638e54Smws 		if (nvlist_lookup_string(nva[nvi], FM_CLASS, &c) == 0) {
369d9638e54Smws 			cc = fmd_dispq_tokenize(c, cvbuf, cvbuflen, cv, cvlen);
370d9638e54Smws 			n += fmd_dispq_dispatchv(dqp->dq_root,
371d9638e54Smws 			    gids, ep, c, cc, cv);
372d9638e54Smws 		}
373d9638e54Smws 	}
374d9638e54Smws 
375d9638e54Smws 	cc = fmd_dispq_tokenize(class, cvbuf, cvbuflen, cv, cvlen);
376d9638e54Smws 	n += fmd_dispq_dispatchv(dqp->dq_root, gids, ep, class, cc, cv);
377d9638e54Smws 
3787c478bd9Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&dqp->dq_lock);
379d9638e54Smws 	fmd_dprintf(FMD_DBG_DISP, "%s dispatched to %u queues\n", class, n);
3807c478bd9Sstevel@tonic-gate 
381d9638e54Smws 	/*
382d9638e54Smws 	 * If the total subscriptions matched (n) was zero and we're not being
383d9638e54Smws 	 * called for a single gid, send the event to the self-diagnosis module.
384d9638e54Smws 	 */
385d9638e54Smws 	if (n == 0 && gid < 0 && fmd.d_self != NULL)
3867c478bd9Sstevel@tonic-gate 		fmd_eventq_insert_at_time(fmd.d_self->mod_queue, ep);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	fmd_event_rele(ep);
3897c478bd9Sstevel@tonic-gate }
390d9638e54Smws 
391d9638e54Smws void
392d9638e54Smws fmd_dispq_dispatch(fmd_dispq_t *dqp, fmd_event_t *ep, const char *class)
393d9638e54Smws {
394d9638e54Smws 	fmd_dispq_dispatch_gid(dqp, ep, class, -1);
395d9638e54Smws }
396d9638e54Smws 
397d9638e54Smws id_t
398d9638e54Smws fmd_dispq_getgid(fmd_dispq_t *dqp, void *cookie)
399d9638e54Smws {
400d9638e54Smws 	id_t gid;
401d9638e54Smws 
402d9638e54Smws 	(void) pthread_rwlock_wrlock(&dqp->dq_lock);
403d9638e54Smws 
404d9638e54Smws 	gid = fmd_idspace_alloc_min(dqp->dq_gids, cookie);
405d9638e54Smws 	dqp->dq_gmax = MAX(dqp->dq_gmax, gid);
406d9638e54Smws 
407d9638e54Smws 	(void) pthread_rwlock_unlock(&dqp->dq_lock);
408d9638e54Smws 
409d9638e54Smws 	return (gid);
410d9638e54Smws }
411d9638e54Smws 
412d9638e54Smws void
413d9638e54Smws fmd_dispq_delgid(fmd_dispq_t *dqp, id_t gid)
414d9638e54Smws {
415d9638e54Smws 	(void) pthread_rwlock_wrlock(&dqp->dq_lock);
416d9638e54Smws 
417d9638e54Smws 	ASSERT(fmd_idspace_contains(dqp->dq_gids, gid));
418d9638e54Smws 	(void) fmd_idspace_free(dqp->dq_gids, gid);
419d9638e54Smws 
420d9638e54Smws 	(void) pthread_rwlock_unlock(&dqp->dq_lock);
421d9638e54Smws }
422