xref: /onnv-gate/usr/src/cmd/rcap/rcapd/rcapd_collection.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <stdlib.h>
31*0Sstevel@tonic-gate #include <strings.h>
32*0Sstevel@tonic-gate #include "rcapd.h"
33*0Sstevel@tonic-gate #include "utils.h"
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate /*
36*0Sstevel@tonic-gate  * An abstract "collection" of processes.  Multiple types of collections can
37*0Sstevel@tonic-gate  * exist, one of which is selected at run-time.  Currently, the only one
38*0Sstevel@tonic-gate  * defined corresponds to project(4)s.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #define	MAX(x, y) (((x) > (y)) ? (x) : (y))
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate typedef struct {
44*0Sstevel@tonic-gate 	rcid_t		lfa_colid;
45*0Sstevel@tonic-gate 	lcollection_t	*lfa_found;
46*0Sstevel@tonic-gate } lcollection_find_arg_t;
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate extern void lcollection_update_project(lcollection_update_type_t,
49*0Sstevel@tonic-gate     void(*)(char *, int, uint64_t, int));
50*0Sstevel@tonic-gate extern void lcollection_set_type_project();
51*0Sstevel@tonic-gate static void lcollection_update_notification_cb(char *, int, uint64_t, int);
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate rcid_t(*rc_getidbypsinfo)(psinfo_t *);
54*0Sstevel@tonic-gate uint64_t phys_total = 0;
55*0Sstevel@tonic-gate static lcollection_t *lcollection_head = NULL;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate void
58*0Sstevel@tonic-gate lcollection_update(lcollection_update_type_t ut)
59*0Sstevel@tonic-gate {
60*0Sstevel@tonic-gate 	if (rcfg.rcfg_mode == rctype_project)
61*0Sstevel@tonic-gate 		lcollection_update_project(ut,
62*0Sstevel@tonic-gate 		    lcollection_update_notification_cb);
63*0Sstevel@tonic-gate 	else
64*0Sstevel@tonic-gate 		die(gettext("unknown mode %s\n"), rcfg.rcfg_mode_name);
65*0Sstevel@tonic-gate }
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate /*
68*0Sstevel@tonic-gate  * Configure which collection type will be used.
69*0Sstevel@tonic-gate  */
70*0Sstevel@tonic-gate void
71*0Sstevel@tonic-gate lcollection_set_type(rctype_t type)
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate 	switch (type) {
74*0Sstevel@tonic-gate 	case rctype_project:
75*0Sstevel@tonic-gate 		lcollection_set_type_project();
76*0Sstevel@tonic-gate 		break;
77*0Sstevel@tonic-gate 	default:
78*0Sstevel@tonic-gate 		/* can't happen */
79*0Sstevel@tonic-gate 		die(gettext("unknown mode %d\n"), type);
80*0Sstevel@tonic-gate 		/*NOTREACHED*/
81*0Sstevel@tonic-gate 	}
82*0Sstevel@tonic-gate }
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate /*
85*0Sstevel@tonic-gate  * Inserts a collection with the supplied identity, or updates the caps of an
86*0Sstevel@tonic-gate  * existing one.  The return value will have these bits set, depending on the
87*0Sstevel@tonic-gate  * previous and new cap values.  If no cap was displaced, and the requested cap
88*0Sstevel@tonic-gate  * is 0, no collection will be added, and the applicable *ZERO flags will be
89*0Sstevel@tonic-gate  * set.
90*0Sstevel@tonic-gate  *
91*0Sstevel@tonic-gate  *	LCST_CAP_CHANGED
92*0Sstevel@tonic-gate  *	LCST_CAP_REMOVED
93*0Sstevel@tonic-gate  *	LCSS_CAP_ZERO
94*0Sstevel@tonic-gate  */
95*0Sstevel@tonic-gate lcollection_t *
96*0Sstevel@tonic-gate lcollection_insert_update(rcid_t colid, uint64_t rss_cap, char *name,
97*0Sstevel@tonic-gate     int *changes)
98*0Sstevel@tonic-gate {
99*0Sstevel@tonic-gate 	lcollection_t *lcol;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	*changes = 0;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	if (rss_cap == 0)
104*0Sstevel@tonic-gate 		*changes |= LCST_CAP_ZERO;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	lcol = lcollection_find(colid);
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 	/*
109*0Sstevel@tonic-gate 	 * If the specified collection is capped, add it to lcollection.
110*0Sstevel@tonic-gate 	 */
111*0Sstevel@tonic-gate 	if (lcol == NULL) {
112*0Sstevel@tonic-gate 		/*
113*0Sstevel@tonic-gate 		 * If the cap has been zeroed and the collection doesn't exist,
114*0Sstevel@tonic-gate 		 * don't create the collection just to remvoe the cap later.
115*0Sstevel@tonic-gate 		 */
116*0Sstevel@tonic-gate 		if (rss_cap == 0)
117*0Sstevel@tonic-gate 			return (NULL);
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 		*changes |= LCST_CAP_CHANGED;
120*0Sstevel@tonic-gate 		lcol = malloc(sizeof (*lcol));
121*0Sstevel@tonic-gate 		if (lcol == NULL) {
122*0Sstevel@tonic-gate 			debug("not enough memory to monitor %s %s",
123*0Sstevel@tonic-gate 			    rcfg.rcfg_mode_name, name);
124*0Sstevel@tonic-gate 			return (NULL);
125*0Sstevel@tonic-gate 		}
126*0Sstevel@tonic-gate 		(void) bzero(lcol, sizeof (*lcol));
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 		lcol->lcol_id = colid;
129*0Sstevel@tonic-gate 		debug("added collection %s\n", name);
130*0Sstevel@tonic-gate 		lcol->lcol_prev = NULL;
131*0Sstevel@tonic-gate 		lcol->lcol_next = lcollection_head;
132*0Sstevel@tonic-gate 		lcol->lcol_stat.lcols_min_rss = (uint64_t)-1;
133*0Sstevel@tonic-gate 		if (lcollection_head != NULL)
134*0Sstevel@tonic-gate 			lcollection_head->lcol_prev = lcol;
135*0Sstevel@tonic-gate 		lcollection_head = lcol;
136*0Sstevel@tonic-gate 	}
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	/*
139*0Sstevel@tonic-gate 	 * Set/update the collection's name.
140*0Sstevel@tonic-gate 	 */
141*0Sstevel@tonic-gate 	(void) strlcpy(lcol->lcol_name, name, sizeof (lcol->lcol_name));
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	/*
144*0Sstevel@tonic-gate 	 * Set cap flags.
145*0Sstevel@tonic-gate 	 */
146*0Sstevel@tonic-gate 	if (rss_cap != lcol->lcol_rss_cap) {
147*0Sstevel@tonic-gate 		*changes |= LCST_CAP_CHANGED;
148*0Sstevel@tonic-gate 		lcol->lcol_rss_cap = rss_cap;
149*0Sstevel@tonic-gate 		if (lcol->lcol_rss_cap == 0)
150*0Sstevel@tonic-gate 			*changes |= LCST_CAP_REMOVED;
151*0Sstevel@tonic-gate 	}
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	if (rss_cap > 0)
154*0Sstevel@tonic-gate 		lcol->lcol_mark++;
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	return (lcol);
157*0Sstevel@tonic-gate }
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate static void
160*0Sstevel@tonic-gate lcollection_update_notification_cb(char *name, int changes, uint64_t rss_cap,
161*0Sstevel@tonic-gate     int mark)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	/*
164*0Sstevel@tonic-gate 	 * Assume the collection has been updated redundantly if its mark count
165*0Sstevel@tonic-gate 	 * exceeds 1, and that another notification is unnecessary.
166*0Sstevel@tonic-gate 	 */
167*0Sstevel@tonic-gate 	if (mark > 1)
168*0Sstevel@tonic-gate 		return;
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	if (changes & LCST_CAP_ZERO)
171*0Sstevel@tonic-gate 		debug("%s %s: %s\n", rcfg.rcfg_mode_name, name,
172*0Sstevel@tonic-gate 		    (changes & LCST_CAP_REMOVED) ? "cap removed" : "uncapped");
173*0Sstevel@tonic-gate 	else
174*0Sstevel@tonic-gate 		debug("%s %s: cap: %llukB\n", rcfg.rcfg_mode_name, name,
175*0Sstevel@tonic-gate 		    (unsigned long long)rss_cap);
176*0Sstevel@tonic-gate }
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate /*
179*0Sstevel@tonic-gate  * Function to walk list of collections and invoke the specified callback with
180*0Sstevel@tonic-gate  * the specified argument.  Callbacks are allowed to change the linkage of the
181*0Sstevel@tonic-gate  * collection on which they act.
182*0Sstevel@tonic-gate  */
183*0Sstevel@tonic-gate void
184*0Sstevel@tonic-gate list_walk_collection(int (*cb)(lcollection_t *, void *), void *arg)
185*0Sstevel@tonic-gate {
186*0Sstevel@tonic-gate 	lcollection_t *lcol;
187*0Sstevel@tonic-gate 	lcollection_t *next;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	lcol = lcollection_head;
190*0Sstevel@tonic-gate 	while (lcol != NULL) {
191*0Sstevel@tonic-gate 		next = lcol->lcol_next;
192*0Sstevel@tonic-gate 		if (cb(lcol, arg) != 0)
193*0Sstevel@tonic-gate 			return;
194*0Sstevel@tonic-gate 		lcol = next;
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate /*
199*0Sstevel@tonic-gate  * Returns a nonzero value if an lprocess_t is still a valid member of a given
200*0Sstevel@tonic-gate  * collection.
201*0Sstevel@tonic-gate  */
202*0Sstevel@tonic-gate int
203*0Sstevel@tonic-gate lcollection_member(lcollection_t *lcol, lprocess_t *lpc)
204*0Sstevel@tonic-gate {
205*0Sstevel@tonic-gate 	lprocess_t *cur = lcol->lcol_lprocess;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	while (cur != NULL)
208*0Sstevel@tonic-gate 		if (cur == lpc)
209*0Sstevel@tonic-gate 			return (1);
210*0Sstevel@tonic-gate 		else
211*0Sstevel@tonic-gate 			cur = cur->lpc_next;
212*0Sstevel@tonic-gate 	return (0);
213*0Sstevel@tonic-gate }
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate static int
216*0Sstevel@tonic-gate lcollection_find_cb(lcollection_t *lcol, void *arg)
217*0Sstevel@tonic-gate {
218*0Sstevel@tonic-gate 	if (lcol->lcol_id == ((lcollection_find_arg_t *)arg)->lfa_colid) {
219*0Sstevel@tonic-gate 		((lcollection_find_arg_t *)arg)->lfa_found = lcol;
220*0Sstevel@tonic-gate 		return (1);
221*0Sstevel@tonic-gate 	} else
222*0Sstevel@tonic-gate 		return (0);
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate lcollection_t *
226*0Sstevel@tonic-gate lcollection_find(id_t colid)
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	lcollection_find_arg_t lfa;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	lfa.lfa_colid = colid;
231*0Sstevel@tonic-gate 	lfa.lfa_found = NULL;
232*0Sstevel@tonic-gate 	list_walk_collection(lcollection_find_cb, &lfa);
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	return (lfa.lfa_found);
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate /*
238*0Sstevel@tonic-gate  * Unlinks a collection from lcollection.
239*0Sstevel@tonic-gate  */
240*0Sstevel@tonic-gate void
241*0Sstevel@tonic-gate lcollection_free(lcollection_t *lcol)
242*0Sstevel@tonic-gate {
243*0Sstevel@tonic-gate 	lprocess_t *lpc;
244*0Sstevel@tonic-gate 	lprocess_t *next;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	lpc = lcol->lcol_lprocess;
247*0Sstevel@tonic-gate 	while (lpc != NULL) {
248*0Sstevel@tonic-gate 		next = lpc->lpc_next;
249*0Sstevel@tonic-gate 		if (lpc->lpc_collection == lcol)
250*0Sstevel@tonic-gate 			lprocess_free(lpc);
251*0Sstevel@tonic-gate 		lpc = next;
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	/*
255*0Sstevel@tonic-gate 	 * Unlink the collection.
256*0Sstevel@tonic-gate 	 */
257*0Sstevel@tonic-gate 	if (lcol->lcol_prev != NULL)
258*0Sstevel@tonic-gate 		lcol->lcol_prev->lcol_next = lcol->lcol_next;
259*0Sstevel@tonic-gate 	if (lcol->lcol_next != NULL)
260*0Sstevel@tonic-gate 		lcol->lcol_next->lcol_prev = lcol->lcol_prev;
261*0Sstevel@tonic-gate 	if (lcollection_head == lcol)
262*0Sstevel@tonic-gate 		lcollection_head = lcol->lcol_next;
263*0Sstevel@tonic-gate 	lcol->lcol_next = lcol->lcol_prev = NULL;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	free(lcol);
266*0Sstevel@tonic-gate }
267