xref: /illumos-gate/usr/src/lib/fm/libfmevent/common/fmev_subscribe.c (revision 0627591eb8261c55a48bc3b17ff3dfe0d0568939)
149b225e1SGavin Maltby /*
249b225e1SGavin Maltby  * CDDL HEADER START
349b225e1SGavin Maltby  *
449b225e1SGavin Maltby  * The contents of this file are subject to the terms of the
549b225e1SGavin Maltby  * Common Development and Distribution License (the "License").
649b225e1SGavin Maltby  * You may not use this file except in compliance with the License.
749b225e1SGavin Maltby  *
849b225e1SGavin Maltby  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
949b225e1SGavin Maltby  * or http://www.opensolaris.org/os/licensing.
1049b225e1SGavin Maltby  * See the License for the specific language governing permissions
1149b225e1SGavin Maltby  * and limitations under the License.
1249b225e1SGavin Maltby  *
1349b225e1SGavin Maltby  * When distributing Covered Code, include this CDDL HEADER in each
1449b225e1SGavin Maltby  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1549b225e1SGavin Maltby  * If applicable, add the following below this CDDL HEADER, with the
1649b225e1SGavin Maltby  * fields enclosed by brackets "[]" replaced with your own identifying
1749b225e1SGavin Maltby  * information: Portions Copyright [yyyy] [name of copyright owner]
1849b225e1SGavin Maltby  *
1949b225e1SGavin Maltby  * CDDL HEADER END
2049b225e1SGavin Maltby  */
2149b225e1SGavin Maltby 
2249b225e1SGavin Maltby /*
23f6e214c7SGavin Maltby  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2449b225e1SGavin Maltby  */
2549b225e1SGavin Maltby 
2649b225e1SGavin Maltby /*
27*0627591eSJohn Levon  * Copyright (c) 2018, Joyent, Inc.
28*0627591eSJohn Levon  */
29*0627591eSJohn Levon 
30*0627591eSJohn Levon /*
3149b225e1SGavin Maltby  * FMA event subscription interfaces - subscribe to FMA protocol
3249b225e1SGavin Maltby  * from outside the fault manager.
3349b225e1SGavin Maltby  */
3449b225e1SGavin Maltby 
3549b225e1SGavin Maltby #include <sys/types.h>
3649b225e1SGavin Maltby #include <atomic.h>
3749b225e1SGavin Maltby #include <libsysevent.h>
3849b225e1SGavin Maltby #include <libuutil.h>
3949b225e1SGavin Maltby #include <pthread.h>
4049b225e1SGavin Maltby #include <stdarg.h>
4149b225e1SGavin Maltby #include <stdlib.h>
4249b225e1SGavin Maltby #include <string.h>
4349b225e1SGavin Maltby #include <strings.h>
4449b225e1SGavin Maltby #include <unistd.h>
45f6e214c7SGavin Maltby #include <fm/libtopo.h>
4649b225e1SGavin Maltby 
4749b225e1SGavin Maltby #include <fm/libfmevent.h>
4849b225e1SGavin Maltby 
4949b225e1SGavin Maltby #include "fmev_impl.h"
50f6e214c7SGavin Maltby 
51f6e214c7SGavin Maltby static topo_hdl_t *g_topohdl;
5249b225e1SGavin Maltby 
5349b225e1SGavin Maltby typedef struct {
5449b225e1SGavin Maltby 	struct fmev_hdl_cmn sh_cmn;
5549b225e1SGavin Maltby 	evchan_t *sh_binding;
5649b225e1SGavin Maltby 	uu_avl_pool_t *sh_pool;
5749b225e1SGavin Maltby 	uu_avl_t *sh_avl;
5849b225e1SGavin Maltby 	uint32_t sh_subcnt;
5949b225e1SGavin Maltby 	uint32_t sh_flags;
6049b225e1SGavin Maltby 	sysevent_subattr_t *sh_attr;
6149b225e1SGavin Maltby 	pthread_mutex_t sh_lock;
6249b225e1SGavin Maltby 	pthread_mutex_t sh_srlz_lock;
6349b225e1SGavin Maltby } fmev_shdl_impl_t;
6449b225e1SGavin Maltby 
6549b225e1SGavin Maltby #define	HDL2IHDL(hdl)	((fmev_shdl_impl_t *)(hdl))
6649b225e1SGavin Maltby #define	IHDL2HDL(ihdl)	((fmev_shdl_t)(ihdl))
6749b225e1SGavin Maltby 
6849b225e1SGavin Maltby #define	_FMEV_SHMAGIC	0x5368446c	/* ShDl */
6949b225e1SGavin Maltby #define	FMEV_SHDL_VALID(ihdl)	((ihdl)->sh_cmn.hc_magic == _FMEV_SHMAGIC)
7049b225e1SGavin Maltby 
7149b225e1SGavin Maltby #define	SHDL_FL_SERIALIZE	0x1
7249b225e1SGavin Maltby 
73f6e214c7SGavin Maltby #define	FMEV_API_ENTER(hdl, v) \
74f6e214c7SGavin Maltby 	fmev_api_enter(&HDL2IHDL(hdl)->sh_cmn, LIBFMEVENT_VERSION_##v)
7549b225e1SGavin Maltby 
7649b225e1SGavin Maltby /*
7749b225e1SGavin Maltby  * For each subscription on a handle we add a node to an avl tree
7849b225e1SGavin Maltby  * to track subscriptions.
7949b225e1SGavin Maltby  */
8049b225e1SGavin Maltby 
8149b225e1SGavin Maltby #define	FMEV_SID_SZ	(16 + 1)	/* Matches MAX_SUBID_LEN */
8249b225e1SGavin Maltby 
8349b225e1SGavin Maltby struct fmev_subinfo {
8449b225e1SGavin Maltby 	uu_avl_node_t si_node;
8549b225e1SGavin Maltby 	fmev_shdl_impl_t *si_ihdl;
8649b225e1SGavin Maltby 	char si_pat[FMEV_MAX_CLASS];
8749b225e1SGavin Maltby 	char si_sid[FMEV_SID_SZ];
8849b225e1SGavin Maltby 	fmev_cbfunc_t *si_cb;
8949b225e1SGavin Maltby 	void *si_cbarg;
9049b225e1SGavin Maltby };
9149b225e1SGavin Maltby 
9249b225e1SGavin Maltby struct fmev_hdl_cmn *
fmev_shdl_cmn(fmev_shdl_t hdl)9349b225e1SGavin Maltby fmev_shdl_cmn(fmev_shdl_t hdl)
9449b225e1SGavin Maltby {
9549b225e1SGavin Maltby 	return (&HDL2IHDL(hdl)->sh_cmn);
9649b225e1SGavin Maltby }
9749b225e1SGavin Maltby 
9849b225e1SGavin Maltby static int
shdlctl_start(fmev_shdl_impl_t * ihdl)9949b225e1SGavin Maltby shdlctl_start(fmev_shdl_impl_t *ihdl)
10049b225e1SGavin Maltby {
10149b225e1SGavin Maltby 	(void) pthread_mutex_lock(&ihdl->sh_lock);
10249b225e1SGavin Maltby 
10349b225e1SGavin Maltby 	if (ihdl->sh_subcnt == 0) {
10449b225e1SGavin Maltby 		return (1);	/* lock still held */
10549b225e1SGavin Maltby 	} else {
10649b225e1SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
10749b225e1SGavin Maltby 		return (0);
10849b225e1SGavin Maltby 	}
10949b225e1SGavin Maltby }
11049b225e1SGavin Maltby 
11149b225e1SGavin Maltby static void
shdlctl_end(fmev_shdl_impl_t * ihdl)11249b225e1SGavin Maltby shdlctl_end(fmev_shdl_impl_t *ihdl)
11349b225e1SGavin Maltby {
11449b225e1SGavin Maltby 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
11549b225e1SGavin Maltby }
11649b225e1SGavin Maltby 
11749b225e1SGavin Maltby fmev_err_t
fmev_shdlctl_serialize(fmev_shdl_t hdl)11849b225e1SGavin Maltby fmev_shdlctl_serialize(fmev_shdl_t hdl)
11949b225e1SGavin Maltby {
12049b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
12149b225e1SGavin Maltby 
122f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
12349b225e1SGavin Maltby 		return (fmev_errno);
12449b225e1SGavin Maltby 
12549b225e1SGavin Maltby 	if (!shdlctl_start(ihdl))
12649b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BUSY));
12749b225e1SGavin Maltby 
12849b225e1SGavin Maltby 	if (!(ihdl->sh_flags & SHDL_FL_SERIALIZE)) {
12949b225e1SGavin Maltby 		(void) pthread_mutex_init(&ihdl->sh_srlz_lock, NULL);
13049b225e1SGavin Maltby 		ihdl->sh_flags |= SHDL_FL_SERIALIZE;
13149b225e1SGavin Maltby 	}
13249b225e1SGavin Maltby 
13349b225e1SGavin Maltby 	shdlctl_end(ihdl);
13449b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
13549b225e1SGavin Maltby }
13649b225e1SGavin Maltby 
13749b225e1SGavin Maltby fmev_err_t
fmev_shdlctl_thrattr(fmev_shdl_t hdl,pthread_attr_t * attr)13849b225e1SGavin Maltby fmev_shdlctl_thrattr(fmev_shdl_t hdl, pthread_attr_t *attr)
13949b225e1SGavin Maltby {
14049b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
14149b225e1SGavin Maltby 
142f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
14349b225e1SGavin Maltby 		return (fmev_errno);
14449b225e1SGavin Maltby 
14549b225e1SGavin Maltby 	if (!shdlctl_start(ihdl))
14649b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BUSY));
14749b225e1SGavin Maltby 
14849b225e1SGavin Maltby 	sysevent_subattr_thrattr(ihdl->sh_attr, attr);
14949b225e1SGavin Maltby 
15049b225e1SGavin Maltby 	shdlctl_end(ihdl);
15149b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
15249b225e1SGavin Maltby }
15349b225e1SGavin Maltby 
15449b225e1SGavin Maltby fmev_err_t
fmev_shdlctl_sigmask(fmev_shdl_t hdl,sigset_t * set)15549b225e1SGavin Maltby fmev_shdlctl_sigmask(fmev_shdl_t hdl, sigset_t *set)
15649b225e1SGavin Maltby {
15749b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
15849b225e1SGavin Maltby 
159f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
16049b225e1SGavin Maltby 		return (fmev_errno);
16149b225e1SGavin Maltby 
16249b225e1SGavin Maltby 	if (!shdlctl_start(ihdl))
16349b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BUSY));
16449b225e1SGavin Maltby 
16549b225e1SGavin Maltby 	sysevent_subattr_sigmask(ihdl->sh_attr, set);
16649b225e1SGavin Maltby 
16749b225e1SGavin Maltby 	shdlctl_end(ihdl);
16849b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
16949b225e1SGavin Maltby }
17049b225e1SGavin Maltby 
17149b225e1SGavin Maltby fmev_err_t
fmev_shdlctl_thrsetup(fmev_shdl_t hdl,door_xcreate_thrsetup_func_t * func,void * cookie)17249b225e1SGavin Maltby fmev_shdlctl_thrsetup(fmev_shdl_t hdl, door_xcreate_thrsetup_func_t *func,
17349b225e1SGavin Maltby     void *cookie)
17449b225e1SGavin Maltby {
17549b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
17649b225e1SGavin Maltby 
177f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
17849b225e1SGavin Maltby 		return (fmev_errno);
17949b225e1SGavin Maltby 
18049b225e1SGavin Maltby 	if (!shdlctl_start(ihdl))
18149b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BUSY));
18249b225e1SGavin Maltby 
18349b225e1SGavin Maltby 	sysevent_subattr_thrsetup(ihdl->sh_attr, func, cookie);
18449b225e1SGavin Maltby 
18549b225e1SGavin Maltby 	shdlctl_end(ihdl);
18649b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
18749b225e1SGavin Maltby }
18849b225e1SGavin Maltby 
18949b225e1SGavin Maltby fmev_err_t
fmev_shdlctl_thrcreate(fmev_shdl_t hdl,door_xcreate_server_func_t * func,void * cookie)19049b225e1SGavin Maltby fmev_shdlctl_thrcreate(fmev_shdl_t hdl, door_xcreate_server_func_t *func,
19149b225e1SGavin Maltby     void *cookie)
19249b225e1SGavin Maltby {
19349b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
19449b225e1SGavin Maltby 
195f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
19649b225e1SGavin Maltby 		return (fmev_errno);
19749b225e1SGavin Maltby 
19849b225e1SGavin Maltby 	if (!shdlctl_start(ihdl))
19949b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BUSY));
20049b225e1SGavin Maltby 
20149b225e1SGavin Maltby 	sysevent_subattr_thrcreate(ihdl->sh_attr, func, cookie);
20249b225e1SGavin Maltby 
20349b225e1SGavin Maltby 	shdlctl_end(ihdl);
20449b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
20549b225e1SGavin Maltby }
20649b225e1SGavin Maltby 
20749b225e1SGavin Maltby /*
20849b225e1SGavin Maltby  * Our door service function.  We return 0 regardless so that the kernel
20949b225e1SGavin Maltby  * does not keep either retrying (EAGAIN) or bleat to cmn_err.
21049b225e1SGavin Maltby  */
21149b225e1SGavin Maltby 
21249b225e1SGavin Maltby uint64_t fmev_proxy_cb_enomem;
21349b225e1SGavin Maltby 
214*0627591eSJohn Levon static int
fmev_proxy_cb(sysevent_t * sep,void * arg)21549b225e1SGavin Maltby fmev_proxy_cb(sysevent_t *sep, void *arg)
21649b225e1SGavin Maltby {
21749b225e1SGavin Maltby 	struct fmev_subinfo *sip = arg;
21849b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = sip->si_ihdl;
21949b225e1SGavin Maltby 	nvlist_t *nvl;
22049b225e1SGavin Maltby 	char *class;
22149b225e1SGavin Maltby 	fmev_t ev;
22249b225e1SGavin Maltby 
22349b225e1SGavin Maltby 	if ((ev = fmev_sysev2fmev(IHDL2HDL(ihdl), sep, &class, &nvl)) == NULL) {
22449b225e1SGavin Maltby 		fmev_proxy_cb_enomem++;
22549b225e1SGavin Maltby 		return (0);
22649b225e1SGavin Maltby 	}
22749b225e1SGavin Maltby 
22849b225e1SGavin Maltby 	if (ihdl->sh_flags & SHDL_FL_SERIALIZE)
22949b225e1SGavin Maltby 		(void) pthread_mutex_lock(&ihdl->sh_srlz_lock);
23049b225e1SGavin Maltby 
23149b225e1SGavin Maltby 	sip->si_cb(ev, class, nvl, sip->si_cbarg);
23249b225e1SGavin Maltby 
23349b225e1SGavin Maltby 	if (ihdl->sh_flags & SHDL_FL_SERIALIZE)
23449b225e1SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_srlz_lock);
23549b225e1SGavin Maltby 
23649b225e1SGavin Maltby 	fmev_rele(ev);	/* release hold obtained in fmev_sysev2fmev */
23749b225e1SGavin Maltby 
23849b225e1SGavin Maltby 	return (0);
23949b225e1SGavin Maltby }
24049b225e1SGavin Maltby 
24149b225e1SGavin Maltby static volatile uint32_t fmev_subid;
24249b225e1SGavin Maltby 
24349b225e1SGavin Maltby fmev_err_t
fmev_shdl_subscribe(fmev_shdl_t hdl,const char * pat,fmev_cbfunc_t func,void * funcarg)24449b225e1SGavin Maltby fmev_shdl_subscribe(fmev_shdl_t hdl, const char *pat, fmev_cbfunc_t func,
24549b225e1SGavin Maltby     void *funcarg)
24649b225e1SGavin Maltby {
24749b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
24849b225e1SGavin Maltby 	struct fmev_subinfo *sip;
24949b225e1SGavin Maltby 	uu_avl_index_t idx;
25049b225e1SGavin Maltby 	uint64_t nsid;
25149b225e1SGavin Maltby 	int serr;
25249b225e1SGavin Maltby 
253f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
25449b225e1SGavin Maltby 		return (fmev_errno);
25549b225e1SGavin Maltby 
25649b225e1SGavin Maltby 	if (pat == NULL || func == NULL)
25749b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_API));
25849b225e1SGavin Maltby 
25949b225e1SGavin Maltby 	/*
26049b225e1SGavin Maltby 	 * Empty class patterns are illegal, as is the sysevent magic for
26149b225e1SGavin Maltby 	 * all classes.  Also validate class length.
26249b225e1SGavin Maltby 	 */
26349b225e1SGavin Maltby 	if (*pat == '\0' || strncmp(pat, EC_ALL, sizeof (EC_ALL)) == 0 ||
26449b225e1SGavin Maltby 	    strncmp(pat, EC_SUB_ALL, sizeof (EC_SUB_ALL)) == 0 ||
26549b225e1SGavin Maltby 	    strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS)
26649b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BADCLASS));
26749b225e1SGavin Maltby 
26849b225e1SGavin Maltby 	if ((sip = fmev_shdl_zalloc(hdl, sizeof (*sip))) == NULL)
26949b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_ALLOC));
27049b225e1SGavin Maltby 
27149b225e1SGavin Maltby 	(void) strncpy(sip->si_pat, pat, sizeof (sip->si_pat));
27249b225e1SGavin Maltby 
27349b225e1SGavin Maltby 	uu_avl_node_init(sip, &sip->si_node, ihdl->sh_pool);
27449b225e1SGavin Maltby 
27549b225e1SGavin Maltby 	(void) pthread_mutex_lock(&ihdl->sh_lock);
27649b225e1SGavin Maltby 
27749b225e1SGavin Maltby 	if (uu_avl_find(ihdl->sh_avl, sip, NULL, &idx) != NULL) {
27849b225e1SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
27949b225e1SGavin Maltby 		fmev_shdl_free(hdl, sip, sizeof (*sip));
28049b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_DUPLICATE));
28149b225e1SGavin Maltby 	}
28249b225e1SGavin Maltby 
28349b225e1SGavin Maltby 	/*
28449b225e1SGavin Maltby 	 * Generate a subscriber id for GPEC that is unique to this
28549b225e1SGavin Maltby 	 * subscription.  There is no provision for persistent
28649b225e1SGavin Maltby 	 * subscribers.  The subscriber id must be unique within
28749b225e1SGavin Maltby 	 * this zone.
28849b225e1SGavin Maltby 	 */
28949b225e1SGavin Maltby 	nsid = (uint64_t)getpid() << 32 | atomic_inc_32_nv(&fmev_subid);
29049b225e1SGavin Maltby 	(void) snprintf(sip->si_sid, sizeof (sip->si_sid), "%llx", nsid);
29149b225e1SGavin Maltby 
29249b225e1SGavin Maltby 	sip->si_ihdl = ihdl;
29349b225e1SGavin Maltby 	sip->si_cb = func;
29449b225e1SGavin Maltby 	sip->si_cbarg = funcarg;
29549b225e1SGavin Maltby 
29649b225e1SGavin Maltby 	if ((serr = sysevent_evc_xsubscribe(ihdl->sh_binding, sip->si_sid,
29749b225e1SGavin Maltby 	    sip->si_pat, fmev_proxy_cb, sip, 0, ihdl->sh_attr)) != 0) {
29849b225e1SGavin Maltby 		fmev_err_t err;
29949b225e1SGavin Maltby 
30049b225e1SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
30149b225e1SGavin Maltby 		fmev_shdl_free(hdl, sip, sizeof (*sip));
30249b225e1SGavin Maltby 
30349b225e1SGavin Maltby 		switch (serr) {
30449b225e1SGavin Maltby 		case ENOMEM:
30549b225e1SGavin Maltby 			err = FMEVERR_MAX_SUBSCRIBERS;
30649b225e1SGavin Maltby 			break;
30749b225e1SGavin Maltby 
30849b225e1SGavin Maltby 		default:
30949b225e1SGavin Maltby 			err = FMEVERR_INTERNAL;
31049b225e1SGavin Maltby 			break;
31149b225e1SGavin Maltby 		}
31249b225e1SGavin Maltby 
31349b225e1SGavin Maltby 		return (fmev_seterr(err));
31449b225e1SGavin Maltby 	}
31549b225e1SGavin Maltby 
31649b225e1SGavin Maltby 	uu_avl_insert(ihdl->sh_avl, sip, idx);
31749b225e1SGavin Maltby 	ihdl->sh_subcnt++;
31849b225e1SGavin Maltby 
31949b225e1SGavin Maltby 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
32049b225e1SGavin Maltby 
32149b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
32249b225e1SGavin Maltby }
32349b225e1SGavin Maltby 
32449b225e1SGavin Maltby static int
fmev_subinfo_fini(fmev_shdl_impl_t * ihdl,struct fmev_subinfo * sip,boolean_t doavl)32549b225e1SGavin Maltby fmev_subinfo_fini(fmev_shdl_impl_t *ihdl, struct fmev_subinfo *sip,
32649b225e1SGavin Maltby     boolean_t doavl)
32749b225e1SGavin Maltby {
32849b225e1SGavin Maltby 	int err;
32949b225e1SGavin Maltby 
33049b225e1SGavin Maltby 	ASSERT(sip->si_ihdl == ihdl);
33149b225e1SGavin Maltby 
33249b225e1SGavin Maltby 	err = sysevent_evc_unsubscribe(ihdl->sh_binding, sip->si_sid);
33349b225e1SGavin Maltby 
33449b225e1SGavin Maltby 	if (err == 0) {
33549b225e1SGavin Maltby 		if (doavl) {
33649b225e1SGavin Maltby 			uu_avl_remove(ihdl->sh_avl, sip);
33749b225e1SGavin Maltby 			uu_avl_node_fini(sip, &sip->si_node, ihdl->sh_pool);
33849b225e1SGavin Maltby 		}
33949b225e1SGavin Maltby 		fmev_shdl_free(IHDL2HDL(ihdl), sip, sizeof (*sip));
34049b225e1SGavin Maltby 		ihdl->sh_subcnt--;
34149b225e1SGavin Maltby 	}
34249b225e1SGavin Maltby 
34349b225e1SGavin Maltby 	return (err);
34449b225e1SGavin Maltby }
34549b225e1SGavin Maltby 
34649b225e1SGavin Maltby fmev_err_t
fmev_shdl_unsubscribe(fmev_shdl_t hdl,const char * pat)34749b225e1SGavin Maltby fmev_shdl_unsubscribe(fmev_shdl_t hdl, const char *pat)
34849b225e1SGavin Maltby {
34949b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
35049b225e1SGavin Maltby 	fmev_err_t rv = FMEVERR_NOMATCH;
35149b225e1SGavin Maltby 	struct fmev_subinfo *sip;
35249b225e1SGavin Maltby 	struct fmev_subinfo si;
35349b225e1SGavin Maltby 	int err;
35449b225e1SGavin Maltby 
355f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
35649b225e1SGavin Maltby 		return (fmev_errno);
35749b225e1SGavin Maltby 
35849b225e1SGavin Maltby 	if (pat == NULL)
35949b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_API));
36049b225e1SGavin Maltby 
36149b225e1SGavin Maltby 	if (*pat == '\0' || strncmp(pat, EVCH_ALLSUB, sizeof (EC_ALL)) == 0 ||
36249b225e1SGavin Maltby 	    strnlen(pat, FMEV_MAX_CLASS) == FMEV_MAX_CLASS)
36349b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_BADCLASS));
36449b225e1SGavin Maltby 
36549b225e1SGavin Maltby 	(void) strncpy(si.si_pat, pat, sizeof (si.si_pat));
36649b225e1SGavin Maltby 
36749b225e1SGavin Maltby 	(void) pthread_mutex_lock(&ihdl->sh_lock);
36849b225e1SGavin Maltby 
36949b225e1SGavin Maltby 	if ((sip = uu_avl_find(ihdl->sh_avl, &si, NULL, NULL)) != NULL) {
37049b225e1SGavin Maltby 		if ((err = fmev_subinfo_fini(ihdl, sip, B_TRUE)) == 0) {
37149b225e1SGavin Maltby 			rv = FMEV_SUCCESS;
37249b225e1SGavin Maltby 		} else {
37349b225e1SGavin Maltby 			/*
37449b225e1SGavin Maltby 			 * Return an API error if the unsubscribe was
37549b225e1SGavin Maltby 			 * attempted from within a door callback invocation;
37649b225e1SGavin Maltby 			 * other errors should not happen.
37749b225e1SGavin Maltby 			 */
37849b225e1SGavin Maltby 			rv = (err == EDEADLK) ? FMEVERR_API : FMEVERR_INTERNAL;
37949b225e1SGavin Maltby 		}
38049b225e1SGavin Maltby 	}
38149b225e1SGavin Maltby 
38249b225e1SGavin Maltby 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
38349b225e1SGavin Maltby 
38449b225e1SGavin Maltby 	return (fmev_seterr(rv));
38549b225e1SGavin Maltby }
38649b225e1SGavin Maltby 
38749b225e1SGavin Maltby void *
fmev_shdl_alloc(fmev_shdl_t hdl,size_t sz)38849b225e1SGavin Maltby fmev_shdl_alloc(fmev_shdl_t hdl, size_t sz)
38949b225e1SGavin Maltby {
39049b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
39149b225e1SGavin Maltby 
392f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
393f6e214c7SGavin Maltby 		return (NULL);
39449b225e1SGavin Maltby 
39549b225e1SGavin Maltby 	return (ihdl->sh_cmn.hc_alloc(sz));
39649b225e1SGavin Maltby }
39749b225e1SGavin Maltby 
39849b225e1SGavin Maltby void *
fmev_shdl_zalloc(fmev_shdl_t hdl,size_t sz)39949b225e1SGavin Maltby fmev_shdl_zalloc(fmev_shdl_t hdl, size_t sz)
40049b225e1SGavin Maltby {
40149b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
40249b225e1SGavin Maltby 
403f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
404f6e214c7SGavin Maltby 		return (NULL);
40549b225e1SGavin Maltby 
40649b225e1SGavin Maltby 	return (ihdl->sh_cmn.hc_zalloc(sz));
40749b225e1SGavin Maltby }
40849b225e1SGavin Maltby 
40949b225e1SGavin Maltby void
fmev_shdl_free(fmev_shdl_t hdl,void * buf,size_t sz)41049b225e1SGavin Maltby fmev_shdl_free(fmev_shdl_t hdl, void *buf, size_t sz)
41149b225e1SGavin Maltby {
41249b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
41349b225e1SGavin Maltby 
414f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
415f6e214c7SGavin Maltby 		return;
41649b225e1SGavin Maltby 
41749b225e1SGavin Maltby 	ihdl->sh_cmn.hc_free(buf, sz);
41849b225e1SGavin Maltby }
41949b225e1SGavin Maltby 
420f6e214c7SGavin Maltby char *
fmev_shdl_strdup(fmev_shdl_t hdl,char * src)421f6e214c7SGavin Maltby fmev_shdl_strdup(fmev_shdl_t hdl, char *src)
422f6e214c7SGavin Maltby {
423f6e214c7SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
424f6e214c7SGavin Maltby 	size_t srclen;
425f6e214c7SGavin Maltby 	char *dst;
426f6e214c7SGavin Maltby 
427f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 2))
428f6e214c7SGavin Maltby 		return (NULL);
429f6e214c7SGavin Maltby 
430f6e214c7SGavin Maltby 	srclen = strlen(src);
431f6e214c7SGavin Maltby 
432f6e214c7SGavin Maltby 	if ((dst = ihdl->sh_cmn.hc_alloc(srclen + 1)) == NULL) {
433f6e214c7SGavin Maltby 		(void) fmev_seterr(FMEVERR_ALLOC);
434f6e214c7SGavin Maltby 		return (NULL);
435f6e214c7SGavin Maltby 	}
436f6e214c7SGavin Maltby 
437f6e214c7SGavin Maltby 	(void) strncpy(dst, src, srclen);
438f6e214c7SGavin Maltby 	dst[srclen] = '\0';
439f6e214c7SGavin Maltby 	return (dst);
440f6e214c7SGavin Maltby }
441f6e214c7SGavin Maltby 
442f6e214c7SGavin Maltby void
fmev_shdl_strfree(fmev_shdl_t hdl,char * buf)443f6e214c7SGavin Maltby fmev_shdl_strfree(fmev_shdl_t hdl, char *buf)
444f6e214c7SGavin Maltby {
445f6e214c7SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
446f6e214c7SGavin Maltby 
447f6e214c7SGavin Maltby 	(void) FMEV_API_ENTER(hdl, 2);
448f6e214c7SGavin Maltby 
449f6e214c7SGavin Maltby 	ihdl->sh_cmn.hc_free(buf, strlen(buf) + 1);
450f6e214c7SGavin Maltby }
451f6e214c7SGavin Maltby 
45249b225e1SGavin Maltby int
fmev_shdl_valid(fmev_shdl_t hdl)45349b225e1SGavin Maltby fmev_shdl_valid(fmev_shdl_t hdl)
45449b225e1SGavin Maltby {
45549b225e1SGavin Maltby 	return (FMEV_SHDL_VALID(HDL2IHDL(hdl)));
45649b225e1SGavin Maltby }
45749b225e1SGavin Maltby 
45849b225e1SGavin Maltby /*ARGSUSED*/
45949b225e1SGavin Maltby static int
fmev_keycmp(const void * l,const void * r,void * arg)46049b225e1SGavin Maltby fmev_keycmp(const void *l, const void *r, void *arg)
46149b225e1SGavin Maltby {
46249b225e1SGavin Maltby 	struct fmev_subinfo *left = (struct fmev_subinfo *)l;
46349b225e1SGavin Maltby 	struct fmev_subinfo *right = (struct fmev_subinfo *)r;
46449b225e1SGavin Maltby 
46549b225e1SGavin Maltby 	return (strncmp(left->si_pat, right->si_pat, FMEV_MAX_CLASS));
46649b225e1SGavin Maltby }
46749b225e1SGavin Maltby 
46849b225e1SGavin Maltby fmev_shdl_t
fmev_shdl_init(uint32_t caller_version,void * (* hdlalloc)(size_t),void * (* hdlzalloc)(size_t),void (* hdlfree)(void *,size_t))46949b225e1SGavin Maltby fmev_shdl_init(uint32_t caller_version, void *(*hdlalloc)(size_t),
47049b225e1SGavin Maltby     void *(*hdlzalloc)(size_t), void (*hdlfree)(void *, size_t))
47149b225e1SGavin Maltby {
47249b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl;
47349b225e1SGavin Maltby 	struct fmev_hdl_cmn hc;
47449b225e1SGavin Maltby 	const char *chan_name;
47549b225e1SGavin Maltby 	int err;
47649b225e1SGavin Maltby 
47749b225e1SGavin Maltby 	hc.hc_magic = _FMEV_SHMAGIC;
47849b225e1SGavin Maltby 	hc.hc_api_vers = caller_version;
47949b225e1SGavin Maltby 	hc.hc_alloc = hdlalloc ? hdlalloc : dflt_alloc;
48049b225e1SGavin Maltby 	hc.hc_zalloc = hdlzalloc ? hdlzalloc : dflt_zalloc;
48149b225e1SGavin Maltby 	hc.hc_free = hdlfree ? hdlfree : dflt_free;
48249b225e1SGavin Maltby 
48349b225e1SGavin Maltby 	if (!fmev_api_init(&hc))
48449b225e1SGavin Maltby 		return (NULL);	/* error type set */
48549b225e1SGavin Maltby 
48649b225e1SGavin Maltby 	if (!((hdlalloc == NULL && hdlzalloc == NULL && hdlfree == NULL) ||
48749b225e1SGavin Maltby 	    (hdlalloc != NULL && hdlzalloc != NULL && hdlfree != NULL))) {
48849b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_API);
48949b225e1SGavin Maltby 		return (NULL);
49049b225e1SGavin Maltby 	}
49149b225e1SGavin Maltby 
49249b225e1SGavin Maltby 	if (hdlzalloc == NULL)
49349b225e1SGavin Maltby 		ihdl = dflt_zalloc(sizeof (*ihdl));
49449b225e1SGavin Maltby 	else
49549b225e1SGavin Maltby 		ihdl = hdlzalloc(sizeof (*ihdl));
49649b225e1SGavin Maltby 
49749b225e1SGavin Maltby 	if (ihdl == NULL) {
49849b225e1SGavin Maltby 		(void) fmev_seterr(FMEVERR_ALLOC);
49949b225e1SGavin Maltby 		return (NULL);
50049b225e1SGavin Maltby 	}
50149b225e1SGavin Maltby 
50249b225e1SGavin Maltby 	ihdl->sh_cmn = hc;
50349b225e1SGavin Maltby 
50449b225e1SGavin Maltby 	if ((ihdl->sh_attr = sysevent_subattr_alloc()) == NULL) {
50549b225e1SGavin Maltby 		err = FMEVERR_ALLOC;
50649b225e1SGavin Maltby 		goto error;
50749b225e1SGavin Maltby 	}
50849b225e1SGavin Maltby 
50949b225e1SGavin Maltby 	(void) pthread_mutex_init(&ihdl->sh_lock, NULL);
51049b225e1SGavin Maltby 
51149b225e1SGavin Maltby 	/*
51249b225e1SGavin Maltby 	 * For simulation purposes we allow an environment variable
51349b225e1SGavin Maltby 	 * to provide a different channel name.
51449b225e1SGavin Maltby 	 */
51549b225e1SGavin Maltby 	if ((chan_name = getenv("FMD_SNOOP_CHANNEL")) == NULL)
51649b225e1SGavin Maltby 		chan_name = FMD_SNOOP_CHANNEL;
51749b225e1SGavin Maltby 
51849b225e1SGavin Maltby 	/*
51949b225e1SGavin Maltby 	 * Try to bind to the event channel. If it's not already present,
52049b225e1SGavin Maltby 	 * attempt to create the channel so that we can startup before
52149b225e1SGavin Maltby 	 * the event producer (who will also apply choices such as
52249b225e1SGavin Maltby 	 * channel depth when they bind to the channel).
52349b225e1SGavin Maltby 	 */
52449b225e1SGavin Maltby 	if (sysevent_evc_bind(chan_name, &ihdl->sh_binding,
52549b225e1SGavin Maltby 	    EVCH_CREAT | EVCH_HOLD_PEND_INDEF) != 0) {
52649b225e1SGavin Maltby 		switch (errno) {
52749b225e1SGavin Maltby 		case EINVAL:
52849b225e1SGavin Maltby 		default:
52949b225e1SGavin Maltby 			err = FMEVERR_INTERNAL;
53049b225e1SGavin Maltby 			break;
53149b225e1SGavin Maltby 		case ENOMEM:
53249b225e1SGavin Maltby 			err = FMEVERR_ALLOC;
53349b225e1SGavin Maltby 			break;
53449b225e1SGavin Maltby 		case EPERM:
53549b225e1SGavin Maltby 			err = FMEVERR_NOPRIV;
53649b225e1SGavin Maltby 			break;
53749b225e1SGavin Maltby 		}
53849b225e1SGavin Maltby 		goto error;
53949b225e1SGavin Maltby 	}
54049b225e1SGavin Maltby 
54149b225e1SGavin Maltby 	if ((ihdl->sh_pool = uu_avl_pool_create("subinfo_pool",
54249b225e1SGavin Maltby 	    sizeof (struct fmev_subinfo),
54349b225e1SGavin Maltby 	    offsetof(struct fmev_subinfo, si_node), fmev_keycmp,
54449b225e1SGavin Maltby 	    UU_AVL_POOL_DEBUG)) == NULL) {
54549b225e1SGavin Maltby 		err = FMEVERR_INTERNAL;
54649b225e1SGavin Maltby 		goto error;
54749b225e1SGavin Maltby 	}
54849b225e1SGavin Maltby 
54949b225e1SGavin Maltby 	if ((ihdl->sh_avl = uu_avl_create(ihdl->sh_pool, NULL,
55049b225e1SGavin Maltby 	    UU_DEFAULT)) == NULL) {
55149b225e1SGavin Maltby 		err = FMEVERR_INTERNAL;
55249b225e1SGavin Maltby 		goto error;
55349b225e1SGavin Maltby 	}
55449b225e1SGavin Maltby 
55549b225e1SGavin Maltby 	return (IHDL2HDL(ihdl));
55649b225e1SGavin Maltby 
55749b225e1SGavin Maltby error:
55849b225e1SGavin Maltby 	(void) fmev_shdl_fini(IHDL2HDL(ihdl));
55949b225e1SGavin Maltby 	(void) fmev_seterr(err);
56049b225e1SGavin Maltby 	return (NULL);
56149b225e1SGavin Maltby }
56249b225e1SGavin Maltby 
56349b225e1SGavin Maltby fmev_err_t
fmev_shdl_getauthority(fmev_shdl_t hdl,nvlist_t ** nvlp)564f6e214c7SGavin Maltby fmev_shdl_getauthority(fmev_shdl_t hdl, nvlist_t **nvlp)
565f6e214c7SGavin Maltby {
566f6e214c7SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
567f6e214c7SGavin Maltby 	nvlist_t *propnvl;
568f6e214c7SGavin Maltby 	fmev_err_t rc;
569f6e214c7SGavin Maltby 
570f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 2))
571f6e214c7SGavin Maltby 		return (fmev_errno);
572f6e214c7SGavin Maltby 
573f6e214c7SGavin Maltby 	(void) pthread_mutex_lock(&ihdl->sh_lock);
574f6e214c7SGavin Maltby 
575f6e214c7SGavin Maltby 	if (sysevent_evc_getpropnvl(ihdl->sh_binding, &propnvl) != 0) {
576f6e214c7SGavin Maltby 		*nvlp = NULL;
577f6e214c7SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
578f6e214c7SGavin Maltby 		return (fmev_seterr(FMEVERR_UNKNOWN));
579f6e214c7SGavin Maltby 	}
580f6e214c7SGavin Maltby 
581f6e214c7SGavin Maltby 	if (propnvl == NULL) {
582f6e214c7SGavin Maltby 		rc = FMEVERR_BUSY;	/* Other end has not bound */
583f6e214c7SGavin Maltby 	} else {
584f6e214c7SGavin Maltby 		nvlist_t *auth;
585f6e214c7SGavin Maltby 
586f6e214c7SGavin Maltby 		if (nvlist_lookup_nvlist(propnvl, "fmdauth", &auth) == 0) {
587f6e214c7SGavin Maltby 			rc = (nvlist_dup(auth, nvlp, 0) == 0) ? FMEV_SUCCESS :
588f6e214c7SGavin Maltby 			    FMEVERR_ALLOC;
589f6e214c7SGavin Maltby 		} else {
590f6e214c7SGavin Maltby 			rc = FMEVERR_INTERNAL;
591f6e214c7SGavin Maltby 		}
592f6e214c7SGavin Maltby 		nvlist_free(propnvl);
593f6e214c7SGavin Maltby 	}
594f6e214c7SGavin Maltby 
595f6e214c7SGavin Maltby 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
596f6e214c7SGavin Maltby 
597f6e214c7SGavin Maltby 	if (rc != FMEV_SUCCESS) {
598f6e214c7SGavin Maltby 		*nvlp = NULL;
599f6e214c7SGavin Maltby 		(void) fmev_seterr(rc);
600f6e214c7SGavin Maltby 	}
601f6e214c7SGavin Maltby 
602f6e214c7SGavin Maltby 	return (rc);
603f6e214c7SGavin Maltby }
604f6e214c7SGavin Maltby 
605f6e214c7SGavin Maltby char *
fmev_shdl_nvl2str(fmev_shdl_t hdl,nvlist_t * nvl)606f6e214c7SGavin Maltby fmev_shdl_nvl2str(fmev_shdl_t hdl, nvlist_t *nvl)
607f6e214c7SGavin Maltby {
608f6e214c7SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
609f6e214c7SGavin Maltby 	char *fmri, *fmricp;
610f6e214c7SGavin Maltby 	fmev_err_t err;
611f6e214c7SGavin Maltby 	int topoerr;
612f6e214c7SGavin Maltby 
613f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 2))
614f6e214c7SGavin Maltby 		return (NULL);
615f6e214c7SGavin Maltby 
616f6e214c7SGavin Maltby 	if (g_topohdl == NULL) {
617f6e214c7SGavin Maltby 		(void) pthread_mutex_lock(&ihdl->sh_lock);
618f6e214c7SGavin Maltby 		if (g_topohdl == NULL)
619f6e214c7SGavin Maltby 			g_topohdl = topo_open(TOPO_VERSION, NULL, &topoerr);
620f6e214c7SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
621f6e214c7SGavin Maltby 
622f6e214c7SGavin Maltby 		if (g_topohdl == NULL) {
623f6e214c7SGavin Maltby 			(void) fmev_seterr(FMEVERR_INTERNAL);
624f6e214c7SGavin Maltby 			return (NULL);
625f6e214c7SGavin Maltby 		}
626f6e214c7SGavin Maltby 	}
627f6e214c7SGavin Maltby 
628f6e214c7SGavin Maltby 	if (topo_fmri_nvl2str(g_topohdl, nvl, &fmri, &topoerr) == 0) {
629f6e214c7SGavin Maltby 		fmricp = fmev_shdl_strdup(hdl, fmri);
630f6e214c7SGavin Maltby 		topo_hdl_strfree(g_topohdl, fmri);
631f6e214c7SGavin Maltby 		return (fmricp);	/* fmev_errno set if strdup failed */
632f6e214c7SGavin Maltby 	}
633f6e214c7SGavin Maltby 
634f6e214c7SGavin Maltby 	switch (topoerr) {
635f6e214c7SGavin Maltby 	case ETOPO_FMRI_NOMEM:
636f6e214c7SGavin Maltby 		err = FMEVERR_ALLOC;
637f6e214c7SGavin Maltby 		break;
638f6e214c7SGavin Maltby 
639f6e214c7SGavin Maltby 	case ETOPO_FMRI_MALFORM:
640f6e214c7SGavin Maltby 	case ETOPO_METHOD_NOTSUP:
641f6e214c7SGavin Maltby 	case ETOPO_METHOD_INVAL:
642f6e214c7SGavin Maltby 	default:
643f6e214c7SGavin Maltby 		err = FMEVERR_INVALIDARG;
644f6e214c7SGavin Maltby 		break;
645f6e214c7SGavin Maltby 	}
646f6e214c7SGavin Maltby 
647f6e214c7SGavin Maltby 	(void) fmev_seterr(err);
648f6e214c7SGavin Maltby 	return (NULL);
649f6e214c7SGavin Maltby }
650f6e214c7SGavin Maltby 
651f6e214c7SGavin Maltby fmev_err_t
fmev_shdl_fini(fmev_shdl_t hdl)65249b225e1SGavin Maltby fmev_shdl_fini(fmev_shdl_t hdl)
65349b225e1SGavin Maltby {
65449b225e1SGavin Maltby 	fmev_shdl_impl_t *ihdl = HDL2IHDL(hdl);
65549b225e1SGavin Maltby 
656f6e214c7SGavin Maltby 	if (!FMEV_API_ENTER(hdl, 1))
657f6e214c7SGavin Maltby 		return (fmev_errno);
65849b225e1SGavin Maltby 
65949b225e1SGavin Maltby 	(void) pthread_mutex_lock(&ihdl->sh_lock);
66049b225e1SGavin Maltby 
66149b225e1SGavin Maltby 	/*
66249b225e1SGavin Maltby 	 * Verify that we are not in callback context - return an API
66349b225e1SGavin Maltby 	 * error if we are.
66449b225e1SGavin Maltby 	 */
66549b225e1SGavin Maltby 	if (sysevent_evc_unsubscribe(ihdl->sh_binding, "invalidsid") ==
66649b225e1SGavin Maltby 	    EDEADLK) {
66749b225e1SGavin Maltby 		(void) pthread_mutex_unlock(&ihdl->sh_lock);
66849b225e1SGavin Maltby 		return (fmev_seterr(FMEVERR_API));
66949b225e1SGavin Maltby 	}
67049b225e1SGavin Maltby 
67149b225e1SGavin Maltby 	if (ihdl->sh_avl) {
67249b225e1SGavin Maltby 		void *cookie = NULL;
67349b225e1SGavin Maltby 		struct fmev_subinfo *sip;
67449b225e1SGavin Maltby 
67549b225e1SGavin Maltby 		while ((sip = uu_avl_teardown(ihdl->sh_avl, &cookie)) != NULL)
67649b225e1SGavin Maltby 			(void) fmev_subinfo_fini(ihdl, sip, B_FALSE);
67749b225e1SGavin Maltby 
67849b225e1SGavin Maltby 		uu_avl_destroy(ihdl->sh_avl);
67949b225e1SGavin Maltby 		ihdl->sh_avl = NULL;
68049b225e1SGavin Maltby 	}
68149b225e1SGavin Maltby 
68249b225e1SGavin Maltby 	ASSERT(ihdl->sh_subcnt == 0);
68349b225e1SGavin Maltby 
68449b225e1SGavin Maltby 	if (ihdl->sh_binding) {
68549b225e1SGavin Maltby 		(void) sysevent_evc_unbind(ihdl->sh_binding);
68649b225e1SGavin Maltby 		ihdl->sh_binding = NULL;
68749b225e1SGavin Maltby 	}
68849b225e1SGavin Maltby 
68949b225e1SGavin Maltby 	if (ihdl->sh_pool) {
69049b225e1SGavin Maltby 		uu_avl_pool_destroy(ihdl->sh_pool);
69149b225e1SGavin Maltby 		ihdl->sh_pool = NULL;
69249b225e1SGavin Maltby 	}
69349b225e1SGavin Maltby 
69449b225e1SGavin Maltby 	if (ihdl->sh_attr) {
69549b225e1SGavin Maltby 		sysevent_subattr_free(ihdl->sh_attr);
69649b225e1SGavin Maltby 		ihdl->sh_attr = NULL;
69749b225e1SGavin Maltby 	}
69849b225e1SGavin Maltby 
69949b225e1SGavin Maltby 	ihdl->sh_cmn.hc_magic = 0;
70049b225e1SGavin Maltby 
701f6e214c7SGavin Maltby 	if (g_topohdl) {
702f6e214c7SGavin Maltby 		topo_close(g_topohdl);
703f6e214c7SGavin Maltby 		g_topohdl = NULL;
704f6e214c7SGavin Maltby 	}
705f6e214c7SGavin Maltby 
70649b225e1SGavin Maltby 	(void) pthread_mutex_unlock(&ihdl->sh_lock);
70749b225e1SGavin Maltby 	(void) pthread_mutex_destroy(&ihdl->sh_lock);
70849b225e1SGavin Maltby 
70949b225e1SGavin Maltby 	fmev_shdl_free(hdl, hdl, sizeof (*ihdl));
71049b225e1SGavin Maltby 
71149b225e1SGavin Maltby 	fmev_api_freetsd();
71249b225e1SGavin Maltby 
71349b225e1SGavin Maltby 	return (fmev_seterr(FMEV_SUCCESS));
71449b225e1SGavin Maltby }
715