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 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 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 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 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 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 * 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 * 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 * 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 208*f6e214c7SGavin Maltby dflt_free(void *buf, size_t sz) 209*f6e214c7SGavin Maltby { 210*f6e214c7SGavin Maltby umem_free(buf, sz); 211*f6e214c7SGavin Maltby } 212