1*6712Stomee /*
2*6712Stomee  * CDDL HEADER START
3*6712Stomee  *
4*6712Stomee  * The contents of this file are subject to the terms of the
5*6712Stomee  * Common Development and Distribution License (the "License").
6*6712Stomee  * You may not use this file except in compliance with the License.
7*6712Stomee  *
8*6712Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6712Stomee  * or http://www.opensolaris.org/os/licensing.
10*6712Stomee  * See the License for the specific language governing permissions
11*6712Stomee  * and limitations under the License.
12*6712Stomee  *
13*6712Stomee  * When distributing Covered Code, include this CDDL HEADER in each
14*6712Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6712Stomee  * If applicable, add the following below this CDDL HEADER, with the
16*6712Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
17*6712Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6712Stomee  *
19*6712Stomee  * CDDL HEADER END
20*6712Stomee  */
21*6712Stomee /*
22*6712Stomee  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*6712Stomee  * Use is subject to license terms.
24*6712Stomee  */
25*6712Stomee 
26*6712Stomee #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*6712Stomee 
28*6712Stomee #include <mdb/mdb_modapi.h>
29*6712Stomee 
30*6712Stomee typedef struct combined_walk {
31*6712Stomee 	int (*cw_init)(mdb_walk_state_t *);
32*6712Stomee 	int (*cw_step)(mdb_walk_state_t *);
33*6712Stomee 	void (*cw_fini)(mdb_walk_state_t *);
34*6712Stomee 	struct combined_walk *cw_next;
35*6712Stomee 	void *cw_data;
36*6712Stomee 	boolean_t cw_initialized;
37*6712Stomee } combined_walk_t;
38*6712Stomee 
39*6712Stomee typedef struct combined_walk_data {
40*6712Stomee 	uintptr_t cwd_initial_walk_addr;	/* to init each walk */
41*6712Stomee 	combined_walk_t *cwd_current_walk;
42*6712Stomee 	combined_walk_t *cwd_final_walk;	/* tail pointer */
43*6712Stomee } combined_walk_data_t;
44*6712Stomee 
45*6712Stomee /*
46*6712Stomee  * Initialize a combined walk to
47*6712Stomee  * A) present a single concatenated series of elements from different
48*6712Stomee  *    structures, or
49*6712Stomee  * B) select from several possible walks at runtime.
50*6712Stomee  * Multiple walks are done in the same order passed to combined_walk_add(). Each
51*6712Stomee  * walk is initialized with the same wsp->walk_addr.
52*6712Stomee  */
53*6712Stomee void
54*6712Stomee combined_walk_init(mdb_walk_state_t *wsp)
55*6712Stomee {
56*6712Stomee 	combined_walk_data_t *cwd;
57*6712Stomee 
58*6712Stomee 	cwd = mdb_alloc(sizeof (combined_walk_data_t), UM_SLEEP);
59*6712Stomee 
60*6712Stomee 	cwd->cwd_initial_walk_addr = wsp->walk_addr;
61*6712Stomee 	cwd->cwd_current_walk = cwd->cwd_final_walk = NULL;
62*6712Stomee 	wsp->walk_data = cwd;
63*6712Stomee }
64*6712Stomee 
65*6712Stomee static void
66*6712Stomee combined_walk_append(combined_walk_data_t *cwd, combined_walk_t *cw)
67*6712Stomee {
68*6712Stomee 	if (cwd->cwd_final_walk == NULL) {
69*6712Stomee 		cwd->cwd_current_walk = cwd->cwd_final_walk = cw;
70*6712Stomee 	} else {
71*6712Stomee 		cwd->cwd_final_walk->cw_next = cw;
72*6712Stomee 		cwd->cwd_final_walk = cw;
73*6712Stomee 	}
74*6712Stomee }
75*6712Stomee 
76*6712Stomee static combined_walk_t *
77*6712Stomee combined_walk_remove_current(combined_walk_data_t *cwd)
78*6712Stomee {
79*6712Stomee 	combined_walk_t *cw = cwd->cwd_current_walk;
80*6712Stomee 	if (cw == NULL) {
81*6712Stomee 		return (NULL);
82*6712Stomee 	}
83*6712Stomee 	if (cw == cwd->cwd_final_walk) {
84*6712Stomee 		cwd->cwd_final_walk = cw->cw_next;
85*6712Stomee 	}
86*6712Stomee 	cwd->cwd_current_walk = cw->cw_next;
87*6712Stomee 	cw->cw_next = NULL;
88*6712Stomee 	return (cw);
89*6712Stomee }
90*6712Stomee 
91*6712Stomee void
92*6712Stomee combined_walk_add(mdb_walk_state_t *wsp,
93*6712Stomee 	int (*walk_init)(mdb_walk_state_t *),
94*6712Stomee 	int (*walk_step)(mdb_walk_state_t *),
95*6712Stomee 	void (*walk_fini)(mdb_walk_state_t *))
96*6712Stomee {
97*6712Stomee 	combined_walk_data_t *cwd = wsp->walk_data;
98*6712Stomee 	combined_walk_t *cw;
99*6712Stomee 
100*6712Stomee 	cw = mdb_alloc(sizeof (combined_walk_t), UM_SLEEP);
101*6712Stomee 
102*6712Stomee 	cw->cw_init = walk_init;
103*6712Stomee 	cw->cw_step = walk_step;
104*6712Stomee 	cw->cw_fini = walk_fini;
105*6712Stomee 	cw->cw_next = NULL;
106*6712Stomee 	cw->cw_data = NULL;
107*6712Stomee 	cw->cw_initialized = B_FALSE;
108*6712Stomee 
109*6712Stomee 	combined_walk_append(cwd, cw);
110*6712Stomee }
111*6712Stomee 
112*6712Stomee int
113*6712Stomee combined_walk_step(mdb_walk_state_t *wsp)
114*6712Stomee {
115*6712Stomee 	combined_walk_data_t *cwd = wsp->walk_data;
116*6712Stomee 	combined_walk_t *cw = cwd->cwd_current_walk;
117*6712Stomee 	int status;
118*6712Stomee 
119*6712Stomee 	if (cw == NULL) {
120*6712Stomee 		return (WALK_DONE);
121*6712Stomee 	}
122*6712Stomee 
123*6712Stomee 	if (cw->cw_initialized) {
124*6712Stomee 		wsp->walk_data = cw->cw_data;
125*6712Stomee 	} else {
126*6712Stomee 		wsp->walk_addr = cwd->cwd_initial_walk_addr;
127*6712Stomee 		status = cw->cw_init(wsp);
128*6712Stomee 		cw->cw_data = wsp->walk_data;
129*6712Stomee 		cw->cw_initialized = B_TRUE;
130*6712Stomee 		if (status != WALK_NEXT) {
131*6712Stomee 			wsp->walk_data = cwd;
132*6712Stomee 			return (status);
133*6712Stomee 		}
134*6712Stomee 	}
135*6712Stomee 
136*6712Stomee 	status = cw->cw_step(wsp);
137*6712Stomee 
138*6712Stomee 	if (status == WALK_DONE) {
139*6712Stomee 		(void) combined_walk_remove_current(cwd);
140*6712Stomee 		cw->cw_fini(wsp);
141*6712Stomee 		mdb_free(cw, sizeof (combined_walk_t));
142*6712Stomee 		wsp->walk_data = cwd;
143*6712Stomee 		return (combined_walk_step(wsp));
144*6712Stomee 	}
145*6712Stomee 
146*6712Stomee 	wsp->walk_data = cwd;
147*6712Stomee 	return (status);
148*6712Stomee }
149*6712Stomee 
150*6712Stomee void
151*6712Stomee combined_walk_fini(mdb_walk_state_t *wsp)
152*6712Stomee {
153*6712Stomee 	combined_walk_data_t *cwd = wsp->walk_data;
154*6712Stomee 	combined_walk_t *cw;
155*6712Stomee 
156*6712Stomee 	while ((cw = combined_walk_remove_current(cwd)) != NULL) {
157*6712Stomee 		if (cw->cw_initialized) {
158*6712Stomee 			wsp->walk_data = cw->cw_data;
159*6712Stomee 			cw->cw_fini(wsp);
160*6712Stomee 		}
161*6712Stomee 		mdb_free(cw, sizeof (combined_walk_t));
162*6712Stomee 	}
163*6712Stomee 
164*6712Stomee 	mdb_free(cwd, sizeof (combined_walk_data_t));
165*6712Stomee }
166