8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fm / modules / common / eversholt / ipath.c
blobe918b1ac92e3d3e522dbfafd379269765e07d616
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
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * ipath.c -- instanced pathname module
27 * this module provides a cache of fully instantized component paths,
28 * stored in a fairly compact format.
31 #include <stdio.h>
32 #include <string.h>
33 #include "alloc.h"
34 #include "out.h"
35 #include "lut.h"
36 #include "tree.h"
37 #include "ptree.h"
38 #include "itree.h"
39 #include "ipath.h"
40 #include "ipath_impl.h"
41 #include "stats.h"
42 #include "eval.h"
43 #include "config.h"
45 static struct stats *Nipath;
46 static struct stats *Nbytes;
48 static struct lut *Ipaths; /* the ipath cache itself */
51 * ipath_init -- initialize the ipath module
53 void
54 ipath_init(void)
56 Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1);
57 Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1);
61 * ipath_cmp -- compare two ipath entries
63 * since two ipaths containing the same components and instance
64 * numbers always point to the same cache entry, they are equal
65 * if their pointers are equal, so this function is not necessary
66 * to test if two ipaths are same. but when inserting a new ipath
67 * into the cache, we must use the same lut comparison logic as when
68 * we're searching for it, so this function must always match the
69 * itree_epnamecmp() function's logic (see below) for searching the lut.
71 static int
72 ipath_cmp(struct ipath *ipp1, struct ipath *ipp2)
74 int i;
76 ASSERT(ipp1 != NULL);
77 ASSERT(ipp2 != NULL);
79 for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++)
80 if (ipp1[i].s != ipp2[i].s)
81 return (ipp2[i].s - ipp1[i].s);
82 else if (ipp1[i].i != ipp2[i].i)
83 return (ipp2[i].i - ipp1[i].i);
85 if (ipp1[i].s == NULL && ipp2[i].s == NULL)
86 return (0);
87 else if (ipp1[i].s == NULL)
88 return (1);
89 else
90 return (-1);
94 * ipath_epnamecmp -- compare an ipath with a struct node *epname list
96 * this function is used when searching the cache, allowing us to search
97 * a lut full of ipaths by looking directly at a struct node *epname
98 * (without having to convert it first). the comparison logic here must
99 * exactly match itree_cmp()'s logic (see above) so lut lookups use find
100 * the same node as lut inserts.
102 static int
103 ipath_epnamecmp(struct ipath *ipp, struct node *np)
105 int i;
107 ASSERT(np != NULL);
108 ASSERT(ipp != NULL);
110 for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) {
111 ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t));
113 if (ipp[i].s != np->u.name.s)
114 return (np->u.name.s - ipp[i].s);
115 else {
116 int inum;
118 if (np->u.name.child != NULL &&
119 np->u.name.child->t == T_NUM)
120 inum = (int)np->u.name.child->u.ull;
121 else
122 config_getcompname(np->u.name.cp, NULL, &inum);
124 if (ipp[i].i != inum)
125 return (inum - ipp[i].i);
129 if (ipp[i].s == NULL && np == NULL)
130 return (0);
131 else if (ipp[i].s == NULL)
132 return (1);
133 else
134 return (-1);
138 * The following functions are only used in the "itree_create_dummy()" first
139 * pass at itree creation. ipath_dummy() creates paths used in the itree (see
140 * comment above add_event_dummy() for details). ipath_for_usednames() creates
141 * a different set of paths using the full names from the propagations. These
142 * are only used by ipath_dummy_lut() in order to set up the Usednames lut
143 * correctly, which in turn allows conf propteries on any alement in those
144 * names to be used in constraints.
146 struct lut *Usednames;
148 void
149 ipath_dummy_lut(struct arrow *arrowp)
151 const struct ipath *ipp;
153 ipp = arrowp->head->myevent->ipp_un;
154 while (ipp->s != NULL) {
155 Usednames = lut_add(Usednames, (void *)ipp->s,
156 (void *)ipp->s, NULL);
157 ipp++;
159 ipp = arrowp->tail->myevent->ipp_un;
160 while (ipp->s != NULL) {
161 Usednames = lut_add(Usednames, (void *)ipp->s,
162 (void *)ipp->s, NULL);
163 ipp++;
167 struct ipath *
168 ipath_dummy(struct node *np, struct ipath *ipp)
170 struct ipath *ret;
172 ret = ipp;
173 while (ipp[1].s != NULL)
174 ipp++;
175 if (strcmp(ipp[0].s, np->u.name.last->u.name.s) == 0)
176 return (ret);
178 ret = MALLOC(sizeof (*ret) * 2);
179 ret[0].s = np->u.name.last->u.name.s;
180 ret[0].i = 0;
181 ret[1].s = NULL;
182 if ((ipp = lut_lookup(Ipaths, (void *)ret,
183 (lut_cmp)ipath_cmp)) != NULL) {
184 FREE(ret);
185 return (ipp);
187 Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
188 stats_counter_bump(Nipath);
189 stats_counter_add(Nbytes, 2 * sizeof (struct ipath));
190 return (ret);
193 struct ipath *
194 ipath_for_usednames(struct node *np)
196 struct ipath *ret, *ipp;
197 int i = 0;
198 struct node *np2;
200 for (np2 = np; np2 != NULL; np2 = np2->u.name.next)
201 i++;
202 ret = MALLOC(sizeof (*ret) * (i + 1));
203 for (i = 0, np2 = np; np2 != NULL; np2 = np2->u.name.next) {
204 ret[i].s = np2->u.name.s;
205 ret[i++].i = 0;
207 ret[i].s = NULL;
208 if ((ipp = lut_lookup(Ipaths, (void *)ret,
209 (lut_cmp)ipath_cmp)) != NULL) {
210 FREE(ret);
211 return (ipp);
213 Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
214 stats_counter_bump(Nipath);
215 stats_counter_add(Nbytes, (i + 1) * sizeof (struct ipath));
216 return (ret);
220 * ipath -- find instanced path in cache, or add it if necessary
222 const struct ipath *
223 ipath(struct node *np)
225 struct ipath *ret;
226 int count;
227 struct node *namep;
228 int i;
230 if ((ret = lut_lookup(Ipaths, (void *)np,
231 (lut_cmp)ipath_epnamecmp)) != NULL)
232 return (ret); /* already in cache */
235 * not in cache, make new cache entry.
236 * start by counting the length of the name.
238 count = 0;
239 namep = np;
240 while (namep != NULL) {
241 ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t));
242 count++;
243 namep = namep->u.name.next;
246 ASSERT(count > 0);
248 /* allocate array for name and last NULL entry */
249 ret = MALLOC(sizeof (*ret) * (count + 1));
250 ret[count].s = NULL;
252 /* fill in ipath entry */
253 namep = np;
254 i = 0;
255 while (namep != NULL) {
256 ASSERT(i < count);
257 ret[i].s = namep->u.name.s;
258 if (namep->u.name.child != NULL &&
259 namep->u.name.child->t == T_NUM)
260 ret[i].i = (int)namep->u.name.child->u.ull;
261 else
262 config_getcompname(namep->u.name.cp, NULL, &ret[i].i);
263 i++;
264 namep = namep->u.name.next;
267 /* add it to the cache */
268 Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret,
269 (lut_cmp)ipath_cmp);
271 stats_counter_bump(Nipath);
272 stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath));
274 return (ret);
278 * ipath2str -- convert ename and ipath to class@path string
280 * if both ename and ipp are provided (non-NULL), the resulting string
281 * will be "class@path". otherwise, the string will just contain the
282 * event class name (e.g. "ereport.io.pci.device") or just the path
283 * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending
284 * on which argument is non-NULL.
286 char *
287 ipath2str(const char *ename, const struct ipath *ipp)
289 int i;
290 size_t len = 0;
291 char *ret;
292 char *cp;
294 /* count up length of class string */
295 if (ename != NULL)
296 len += strlen(ename);
298 /* count up length of path string, including slash separators */
299 if (ipp != NULL) {
300 for (i = 0; ipp[i].s != NULL; i++) {
301 /* add slash separator, but no leading slash */
302 if (i != 0)
303 len++;
304 len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
308 if (ename != NULL && ipp != NULL)
309 len++; /* room for '@' */
311 len++; /* room for final '\0' */
313 cp = ret = MALLOC(len);
315 if (ename != NULL) {
316 /* construct class string */
317 (void) strcpy(cp, ename);
318 cp += strlen(cp);
321 /* if doing both strings, put '@' between them */
322 if (ename != NULL && ipp != NULL)
323 *cp++ = '@';
325 if (ipp != NULL) {
326 /* construct path string */
327 for (i = 0; ipp[i].s != NULL; i++) {
328 if (i != 0)
329 *cp++ = '/';
330 (void) snprintf(cp, &ret[len] - cp, "%s%d",
331 ipp[i].s, ipp[i].i);
332 cp += strlen(cp);
336 *cp++ = '\0';
338 return (ret);
341 void
342 ipathlastcomp(const struct ipath *ipp)
344 int i;
346 for (i = 0; ipp[i].s != NULL; i++)
349 out(O_ALTFP, "newfme: add %s to Usednames", ipp[i - 1].s);
350 Usednames = lut_add(Usednames, (void *)ipp[i - 1].s,
351 (void *)ipp[i - 1].s, NULL);
355 * ipath2strlen -- calculate the len of what ipath2str() would return
357 size_t
358 ipath2strlen(const char *ename, const struct ipath *ipp)
360 int i;
361 size_t len = 0;
363 /* count up length of class string */
364 if (ename != NULL)
365 len += strlen(ename);
367 /* count up length of path string, including slash separators */
368 if (ipp != NULL) {
369 for (i = 0; ipp[i].s != NULL; i++) {
370 /* add slash separator, but no leading slash */
371 if (i != 0)
372 len++;
373 len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
377 if (ename != NULL && ipp != NULL)
378 len++; /* room for '@' */
380 return (len);
384 * ipath_print -- print out an ename, ipath, or both with '@' between them
386 void
387 ipath_print(int flags, const char *ename, const struct ipath *ipp)
389 if (ename != NULL) {
390 out(flags|O_NONL, ename);
391 if (ipp != NULL)
392 out(flags|O_NONL, "@");
394 if (ipp != NULL) {
395 char *sep = "";
397 while (ipp->s != NULL) {
398 out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i);
399 ipp++;
400 sep = "/";
405 /*ARGSUSED*/
406 static void
407 ipath_destructor(void *left, void *right, void *arg)
409 struct ipath *ipp = (struct ipath *)right;
411 FREE(ipp);
415 * ipath_fini -- free the ipath cache
417 void
418 ipath_fini(void)
420 lut_free(Ipaths, ipath_destructor, NULL);
421 Ipaths = NULL;
422 lut_free(Usednames, NULL, NULL);
423 Usednames = NULL;
425 if (Nipath) {
426 stats_delete(Nipath);
427 Nipath = NULL;
430 if (Nbytes) {
431 stats_delete(Nbytes);
432 Nbytes = NULL;