49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * CDDL HEADER START
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby *
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * The contents of this file are subject to the terms of the
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Common Development and Distribution License (the "License").
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * You may not use this file except in compliance with the License.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby *
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * or http://www.opensolaris.org/os/licensing.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * See the License for the specific language governing permissions
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * and limitations under the License.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby *
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * When distributing Covered Code, include this CDDL HEADER in each
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * If applicable, add the following below this CDDL HEADER, with the
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * fields enclosed by brackets "[]" replaced with your own identifying
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * information: Portions Copyright [yyyy] [name of copyright owner]
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby *
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * CDDL HEADER END
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Subscription event access interfaces.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#include <sys/types.h>
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#include <pthread.h>
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#include <umem.h>
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#include <fm/libfmevent.h>
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby#include "fmev_impl.h"
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbystatic pthread_key_t fmev_tsdkey = PTHREAD_ONCE_KEY_NP;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbystatic int key_inited;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Thread and handle specific data.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbystruct fmev_tsd {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby fmev_err_t ts_lasterr;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby};
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbystatic void
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_tsd_destructor(void *data)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby{
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby umem_free(data, sizeof (struct fmev_tsd));
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby}
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Called only from fmev_shdl_init. Check we are opening a valid version
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * of the ABI.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyint
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_api_init(struct fmev_hdl_cmn *hc)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby{
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby uint32_t v = hc->hc_api_vers;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby int rc;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (!fmev_api_enter((struct fmev_hdl_cmn *)fmev_api_init, 0))
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (0);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby switch (v) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby case LIBFMEVENT_VERSION_1:
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby case LIBFMEVENT_VERSION_2:
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby rc = 1;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby break;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby default:
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (key_inited)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) fmev_seterr(FMEVERR_VERSION_MISMATCH);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby rc = 0;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby break;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (rc);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby}
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * On entry to other libfmevent API members we call fmev_api_enter.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Some thread-specific data is used to keep a per-thread error value.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * The version opened must be no greater than the latest version but can
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * be older. The ver_intro is the api version at which the interface
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * was added - the caller must have opened at least this version.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyint
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_api_enter(struct fmev_hdl_cmn *hc, uint32_t ver_intro)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby{
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby uint32_t v;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby struct fmev_tsd *tsd;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby /* Initialize key on first visit */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (!key_inited) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) pthread_key_create_once_np(&fmev_tsdkey,
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby fmev_tsd_destructor);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby key_inited = 1;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby /*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Allocate TSD for error value for this thread. It is only
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * freed if/when the thread exits.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((tsd = umem_alloc(sizeof (*tsd), UMEM_DEFAULT)) == NULL ||
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby pthread_setspecific(fmev_tsdkey, (const void *)tsd) != 0) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (tsd)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby umem_free(tsd, sizeof (*tsd));
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (0); /* no error set, but what can we do */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby tsd->ts_lasterr = 0;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (hc == (struct fmev_hdl_cmn *)fmev_api_init)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (1); /* special case from fmev_api_init only */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (hc == NULL || hc->hc_magic != _FMEV_SHMAGIC) {
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby tsd->ts_lasterr = FMEVERR_API;
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (0);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby v = hc->hc_api_vers; /* API version opened */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby /* Enforce version adherence. */
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby if (ver_intro > v || v > LIBFMEVENT_VERSION_LATEST ||
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby ver_intro > LIBFMEVENT_VERSION_LATEST) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby tsd->ts_lasterr = FMEVERR_VERSION_MISMATCH;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (0);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (1);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby}
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * Called on any fmev_shdl_fini. Free the TSD for this thread. If this
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * thread makes other API calls for other open handles, or opens a new
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * handle, then TSD will be allocated again in fmev_api_enter.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyvoid
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_api_freetsd(void)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby{
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby struct fmev_tsd *tsd;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL) {
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby (void) pthread_setspecific(fmev_tsdkey, NULL);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby fmev_tsd_destructor((void *)tsd);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby }
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby}
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * To return an error condition an API member first sets the error type
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * with a call to fmev_seterr and then returns NULL or whatever it wants.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * The caller can then retrieve the per-thread error type using fmev_errno
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * or format it with fmev_strerr.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_err_t
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyfmev_seterr(fmev_err_t error)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby{
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby struct fmev_tsd *tsd;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby ASSERT(key_inited);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby tsd->ts_lasterr = error;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (error);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby}
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby/*
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * fmev_errno is a macro defined in terms of the following function. It
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * can be used to dereference the last error value on the current thread;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby * it must not be used to assign to fmev_errno.
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby */
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyconst fmev_err_t apierr = FMEVERR_API;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyconst fmev_err_t unknownerr = FMEVERR_UNKNOWN;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltbyconst fmev_err_t *
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby__fmev_errno(void)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby{
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby struct fmev_tsd *tsd;
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if (!key_inited)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (&apierr);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL)
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return (&unknownerr);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby return ((const fmev_err_t *)&tsd->ts_lasterr);
49b225e1cfa7bbf7738d4df0a03f18e3283426ebGavin Maltby}
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbyvoid *
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbydflt_alloc(size_t sz)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby{
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (umem_alloc(sz, UMEM_DEFAULT));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby}
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbyvoid *
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbydflt_zalloc(size_t sz)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby{
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby return (umem_zalloc(sz, UMEM_DEFAULT));
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby}
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbyvoid
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltbydflt_free(void *buf, size_t sz)
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby{
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby umem_free(buf, sz);
f6e214c7418f43af38bd8c3a557e3d0a1d311cfaGavin Maltby}