import less(1)
[unleashed/tickless.git] / usr / src / lib / fm / libfmevent / common / fmev_util.c
blob7eec8ad0db90602f4582a4a05bea1ddc2098c103
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Subscription event access interfaces.
30 #include <sys/types.h>
31 #include <pthread.h>
32 #include <umem.h>
33 #include <fm/libfmevent.h>
35 #include "fmev_impl.h"
37 static pthread_key_t fmev_tsdkey = PTHREAD_ONCE_KEY_NP;
38 static int key_inited;
41 * Thread and handle specific data.
43 struct fmev_tsd {
44 fmev_err_t ts_lasterr;
47 static void
48 fmev_tsd_destructor(void *data)
50 umem_free(data, sizeof (struct fmev_tsd));
54 * Called only from fmev_shdl_init. Check we are opening a valid version
55 * of the ABI.
57 int
58 fmev_api_init(struct fmev_hdl_cmn *hc)
60 uint32_t v = hc->hc_api_vers;
61 int rc;
63 if (!fmev_api_enter((struct fmev_hdl_cmn *)fmev_api_init, 0))
64 return (0);
66 switch (v) {
67 case LIBFMEVENT_VERSION_1:
68 case LIBFMEVENT_VERSION_2:
69 rc = 1;
70 break;
72 default:
73 if (key_inited)
74 (void) fmev_seterr(FMEVERR_VERSION_MISMATCH);
75 rc = 0;
76 break;
79 return (rc);
83 * On entry to other libfmevent API members we call fmev_api_enter.
84 * Some thread-specific data is used to keep a per-thread error value.
85 * The version opened must be no greater than the latest version but can
86 * be older. The ver_intro is the api version at which the interface
87 * was added - the caller must have opened at least this version.
89 int
90 fmev_api_enter(struct fmev_hdl_cmn *hc, uint32_t ver_intro)
92 uint32_t v;
93 struct fmev_tsd *tsd;
95 /* Initialize key on first visit */
96 if (!key_inited) {
97 (void) pthread_key_create_once_np(&fmev_tsdkey,
98 fmev_tsd_destructor);
99 key_inited = 1;
103 * Allocate TSD for error value for this thread. It is only
104 * freed if/when the thread exits.
106 if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL) {
107 if ((tsd = umem_alloc(sizeof (*tsd), UMEM_DEFAULT)) == NULL ||
108 pthread_setspecific(fmev_tsdkey, (const void *)tsd) != 0) {
109 if (tsd)
110 umem_free(tsd, sizeof (*tsd));
111 return (0); /* no error set, but what can we do */
115 tsd->ts_lasterr = 0;
117 if (hc == (struct fmev_hdl_cmn *)fmev_api_init)
118 return (1); /* special case from fmev_api_init only */
120 if (hc == NULL || hc->hc_magic != _FMEV_SHMAGIC) {
121 tsd->ts_lasterr = FMEVERR_API;
122 return (0);
125 v = hc->hc_api_vers; /* API version opened */
127 /* Enforce version adherence. */
128 if (ver_intro > v || v > LIBFMEVENT_VERSION_LATEST ||
129 ver_intro > LIBFMEVENT_VERSION_LATEST) {
130 tsd->ts_lasterr = FMEVERR_VERSION_MISMATCH;
131 return (0);
134 return (1);
138 * Called on any fmev_shdl_fini. Free the TSD for this thread. If this
139 * thread makes other API calls for other open handles, or opens a new
140 * handle, then TSD will be allocated again in fmev_api_enter.
142 void
143 fmev_api_freetsd(void)
145 struct fmev_tsd *tsd;
147 if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL) {
148 (void) pthread_setspecific(fmev_tsdkey, NULL);
149 fmev_tsd_destructor((void *)tsd);
154 * To return an error condition an API member first sets the error type
155 * with a call to fmev_seterr and then returns NULL or whatever it wants.
156 * The caller can then retrieve the per-thread error type using fmev_errno
157 * or format it with fmev_strerr.
159 fmev_err_t
160 fmev_seterr(fmev_err_t error)
162 struct fmev_tsd *tsd;
164 ASSERT(key_inited);
166 if ((tsd = pthread_getspecific(fmev_tsdkey)) != NULL)
167 tsd->ts_lasterr = error;
169 return (error);
173 * fmev_errno is a macro defined in terms of the following function. It
174 * can be used to dereference the last error value on the current thread;
175 * it must not be used to assign to fmev_errno.
178 const fmev_err_t apierr = FMEVERR_API;
179 const fmev_err_t unknownerr = FMEVERR_UNKNOWN;
181 const fmev_err_t *
182 __fmev_errno(void)
184 struct fmev_tsd *tsd;
186 if (!key_inited)
187 return (&apierr);
189 if ((tsd = pthread_getspecific(fmev_tsdkey)) == NULL)
190 return (&unknownerr);
192 return ((const fmev_err_t *)&tsd->ts_lasterr);
195 void *
196 dflt_alloc(size_t sz)
198 return (umem_alloc(sz, UMEM_DEFAULT));
201 void *
202 dflt_zalloc(size_t sz)
204 return (umem_zalloc(sz, UMEM_DEFAULT));
207 void
208 dflt_free(void *buf, size_t sz)
210 umem_free(buf, sz);