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