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