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