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 /*
23*f6e214c7SGavin Maltby  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2449b225e1SGavin Maltby  */
2549b225e1SGavin Maltby 
2649b225e1SGavin Maltby /*
2749b225e1SGavin Maltby  * Subscription event access interfaces.
2849b225e1SGavin Maltby  */
2949b225e1SGavin Maltby 
3049b225e1SGavin Maltby #include <sys/types.h>
3149b225e1SGavin Maltby #include <pthread.h>
3249b225e1SGavin Maltby #include <umem.h>
3349b225e1SGavin Maltby #include <fm/libfmevent.h>
3449b225e1SGavin Maltby 
3549b225e1SGavin Maltby #include "fmev_impl.h"
3649b225e1SGavin Maltby 
3749b225e1SGavin Maltby static pthread_key_t fmev_tsdkey = PTHREAD_ONCE_KEY_NP;
3849b225e1SGavin Maltby static int key_inited;
3949b225e1SGavin Maltby 
4049b225e1SGavin Maltby /*
4149b225e1SGavin Maltby  * Thread and handle specific data.
4249b225e1SGavin Maltby  */
4349b225e1SGavin Maltby struct fmev_tsd {
4449b225e1SGavin Maltby 	fmev_err_t ts_lasterr;
4549b225e1SGavin Maltby };
4649b225e1SGavin Maltby 
4749b225e1SGavin Maltby static void
fmev_tsd_destructor(void * data)4849b225e1SGavin Maltby fmev_tsd_destructor(void *data)
4949b225e1SGavin Maltby {
5049b225e1SGavin Maltby 	umem_free(data, sizeof (struct fmev_tsd));
5149b225e1SGavin Maltby }
5249b225e1SGavin Maltby 
5349b225e1SGavin Maltby /*
5449b225e1SGavin Maltby  * Called only from fmev_shdl_init.  Check we are opening a valid version
5549b225e1SGavin Maltby  * of the ABI.
5649b225e1SGavin Maltby  */
5749b225e1SGavin Maltby int
fmev_api_init(struct fmev_hdl_cmn * hc)5849b225e1SGavin Maltby fmev_api_init(struct fmev_hdl_cmn *hc)
5949b225e1SGavin Maltby {
60*f6e214c7SGavin Maltby 	uint32_t v = hc->hc_api_vers;
61*f6e214c7SGavin Maltby 	int rc;
62*f6e214c7SGavin Maltby 
63*f6e214c7SGavin Maltby 	if (!fmev_api_enter((struct fmev_hdl_cmn *)fmev_api_init, 0))
6449b225e1SGavin Maltby 		return (0);
65*f6e214c7SGavin Maltby 
66*f6e214c7SGavin Maltby 	switch (v) {
67*f6e214c7SGavin Maltby 	case LIBFMEVENT_VERSION_1:
68*f6e214c7SGavin Maltby 	case LIBFMEVENT_VERSION_2:
69*f6e214c7SGavin Maltby 		rc = 1;
70*f6e214c7SGavin Maltby 		break;
71*f6e214c7SGavin Maltby 
72*f6e214c7SGavin Maltby 	default:
7349b225e1SGavin Maltby 		if (key_inited)
7449b225e1SGavin Maltby 			(void) fmev_seterr(FMEVERR_VERSION_MISMATCH);
75*f6e214c7SGavin Maltby 		rc = 0;
76*f6e214c7SGavin Maltby 		break;
7749b225e1SGavin Maltby 	}
7849b225e1SGavin Maltby 
79*f6e214c7SGavin Maltby 	return (rc);
8049b225e1SGavin Maltby }
8149b225e1SGavin Maltby 
8249b225e1SGavin Maltby /*
8349b225e1SGavin Maltby  * On entry to other libfmevent API members we call fmev_api_enter.
8449b225e1SGavin Maltby  * Some thread-specific data is used to keep a per-thread error value.
8549b225e1SGavin Maltby  * The version opened must be no greater than the latest version but can
8649b225e1SGavin Maltby  * be older.  The ver_intro is the api version at which the interface
8749b225e1SGavin Maltby  * was added - the caller must have opened at least this version.
8849b225e1SGavin Maltby  */
8949b225e1SGavin Maltby int
fmev_api_enter(struct fmev_hdl_cmn * hc,uint32_t ver_intro)9049b225e1SGavin Maltby fmev_api_enter(struct fmev_hdl_cmn *hc, uint32_t ver_intro)
9149b225e1SGavin Maltby {
92*f6e214c7SGavin Maltby 	uint32_t v;
9349b225e1SGavin Maltby 	struct fmev_tsd *tsd;
9449b225e1SGavin Maltby 
9549b225e1SGavin Maltby 	/* Initialize key on first visit */
9649b225e1SGavin Maltby 	if (!key_inited) {
9749b225e1SGavin Maltby 		(void) pthread_key_create_once_np(&fmev_tsdkey,
9849b225e1SGavin Maltby 		    fmev_tsd_destructor);
9949b225e1SGavin Maltby 		key_inited = 1;
10049b225e1SGavin Maltby 	}
10149b225e1SGavin Maltby 
10249b225e1SGavin Maltby 	/*
10349b225e1SGavin Maltby 	 * Allocate TSD for error value for this thread.  It is only
10449b225e1SGavin Maltby 	 * freed if/when the thread exits.
10549b225e1SGavin Maltby 	 */
10649b225e1SGavin Maltby 	if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL) {
10749b225e1SGavin Maltby 		if ((tsd = umem_alloc(sizeof (*tsd), UMEM_DEFAULT)) == NULL ||
10849b225e1SGavin Maltby 		    pthread_setspecific(fmev_tsdkey, (const void *)tsd) != 0) {
10949b225e1SGavin Maltby 			if (tsd)
11049b225e1SGavin Maltby 				umem_free(tsd, sizeof (*tsd));
11149b225e1SGavin Maltby 			return (0);	/* no error set, but what can we do */
11249b225e1SGavin Maltby 		}
11349b225e1SGavin Maltby 	}
11449b225e1SGavin Maltby 
11549b225e1SGavin Maltby 	tsd->ts_lasterr = 0;
11649b225e1SGavin Maltby 
117*f6e214c7SGavin Maltby 	if (hc == (struct fmev_hdl_cmn *)fmev_api_init)
118*f6e214c7SGavin Maltby 		return (1);	/* special case from fmev_api_init only */
119*f6e214c7SGavin Maltby 
120*f6e214c7SGavin Maltby 	if (hc == NULL || hc->hc_magic != _FMEV_SHMAGIC) {
121*f6e214c7SGavin Maltby 		tsd->ts_lasterr = FMEVERR_API;
122*f6e214c7SGavin Maltby 		return (0);
12349b225e1SGavin Maltby 	}
12449b225e1SGavin Maltby 
125*f6e214c7SGavin Maltby 	v = hc->hc_api_vers;	/* API version opened */
126*f6e214c7SGavin Maltby 
12749b225e1SGavin Maltby 	/* Enforce version adherence. */
128*f6e214c7SGavin Maltby 	if (ver_intro > v || v > LIBFMEVENT_VERSION_LATEST ||
12949b225e1SGavin Maltby 	    ver_intro > LIBFMEVENT_VERSION_LATEST) {
13049b225e1SGavin Maltby 		tsd->ts_lasterr = FMEVERR_VERSION_MISMATCH;
13149b225e1SGavin Maltby 		return (0);
13249b225e1SGavin Maltby 	}
13349b225e1SGavin Maltby 
13449b225e1SGavin Maltby 	return (1);
13549b225e1SGavin Maltby }
13649b225e1SGavin Maltby 
13749b225e1SGavin Maltby /*
13849b225e1SGavin Maltby  * Called on any fmev_shdl_fini.  Free the TSD for this thread.  If this
13949b225e1SGavin Maltby  * thread makes other API calls for other open handles, or opens a new
14049b225e1SGavin Maltby  * handle, then TSD will be allocated again in fmev_api_enter.
14149b225e1SGavin Maltby  */
14249b225e1SGavin Maltby void
fmev_api_freetsd(void)14349b225e1SGavin Maltby fmev_api_freetsd(void)
14449b225e1SGavin Maltby {
14549b225e1SGavin Maltby 	struct fmev_tsd *tsd;
14649b225e1SGavin Maltby 
14749b225e1SGavin Maltby 	if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL) {
14849b225e1SGavin Maltby 		(void) pthread_setspecific(fmev_tsdkey, NULL);
14949b225e1SGavin Maltby 		fmev_tsd_destructor((void *)tsd);
15049b225e1SGavin Maltby 	}
15149b225e1SGavin Maltby }
15249b225e1SGavin Maltby 
15349b225e1SGavin Maltby /*
15449b225e1SGavin Maltby  * To return an error condition an API member first sets the error type
15549b225e1SGavin Maltby  * with a call to fmev_seterr and then returns NULL or whatever it wants.
15649b225e1SGavin Maltby  * The caller can then retrieve the per-thread error type using fmev_errno
15749b225e1SGavin Maltby  * or format it with fmev_strerr.
15849b225e1SGavin Maltby  */
15949b225e1SGavin Maltby fmev_err_t
fmev_seterr(fmev_err_t error)16049b225e1SGavin Maltby fmev_seterr(fmev_err_t error)
16149b225e1SGavin Maltby {
16249b225e1SGavin Maltby 	struct fmev_tsd *tsd;
16349b225e1SGavin Maltby 
16449b225e1SGavin Maltby 	ASSERT(key_inited);
16549b225e1SGavin Maltby 
16649b225e1SGavin Maltby 	if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL)
16749b225e1SGavin Maltby 		tsd->ts_lasterr = error;
16849b225e1SGavin Maltby 
16949b225e1SGavin Maltby 	return (error);
17049b225e1SGavin Maltby }
17149b225e1SGavin Maltby 
17249b225e1SGavin Maltby /*
17349b225e1SGavin Maltby  * fmev_errno is a macro defined in terms of the following function.  It
17449b225e1SGavin Maltby  * can be used to dereference the last error value on the current thread;
17549b225e1SGavin Maltby  * it must not be used to assign to fmev_errno.
17649b225e1SGavin Maltby  */
17749b225e1SGavin Maltby 
17849b225e1SGavin Maltby const fmev_err_t apierr = FMEVERR_API;
17949b225e1SGavin Maltby const fmev_err_t unknownerr = FMEVERR_UNKNOWN;
18049b225e1SGavin Maltby 
18149b225e1SGavin Maltby const fmev_err_t *
__fmev_errno(void)18249b225e1SGavin Maltby __fmev_errno(void)
18349b225e1SGavin Maltby {
18449b225e1SGavin Maltby 	struct fmev_tsd *tsd;
18549b225e1SGavin Maltby 
18649b225e1SGavin Maltby 	if (!key_inited)
18749b225e1SGavin Maltby 		return (&apierr);
18849b225e1SGavin Maltby 
18949b225e1SGavin Maltby 	if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL)
19049b225e1SGavin Maltby 		return (&unknownerr);
19149b225e1SGavin Maltby 
19249b225e1SGavin Maltby 	return ((const fmev_err_t *)&tsd->ts_lasterr);
19349b225e1SGavin Maltby }
194*f6e214c7SGavin Maltby 
195*f6e214c7SGavin Maltby void *
dflt_alloc(size_t sz)196*f6e214c7SGavin Maltby dflt_alloc(size_t sz)
197*f6e214c7SGavin Maltby {
198*f6e214c7SGavin Maltby 	return (umem_alloc(sz, UMEM_DEFAULT));
199*f6e214c7SGavin Maltby }
200*f6e214c7SGavin Maltby 
201*f6e214c7SGavin Maltby void *
dflt_zalloc(size_t sz)202*f6e214c7SGavin Maltby dflt_zalloc(size_t sz)
203*f6e214c7SGavin Maltby {
204*f6e214c7SGavin Maltby 	return (umem_zalloc(sz, UMEM_DEFAULT));
205*f6e214c7SGavin Maltby }
206*f6e214c7SGavin Maltby 
207*f6e214c7SGavin Maltby void
dflt_free(void * buf,size_t sz)208*f6e214c7SGavin Maltby dflt_free(void *buf, size_t sz)
209*f6e214c7SGavin Maltby {
210*f6e214c7SGavin Maltby 	umem_free(buf, sz);
211*f6e214c7SGavin Maltby }
212