1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 /* dbus-resources.c Resource tracking/limits 3 * 4 * Copyright (C) 2003 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #include <config.h> 25 #include <dbus/dbus-resources.h> 26 #include <dbus/dbus-internals.h> 27 28 /** 29 * @defgroup DBusResources Resource limits related code 30 * @ingroup DBusInternals 31 * @brief DBusCounter and other stuff related to resource limits 32 * 33 * Types and functions related to tracking resource limits, 34 * such as the maximum amount of memory/unix fds a connection can use 35 * for messages, etc. 36 */ 37 38 /** 39 * @defgroup DBusResourcesInternals Resource limits implementation details 40 * @ingroup DBusInternals 41 * @brief Resource limits implementation details 42 * 43 * Implementation details of resource limits code. 44 * 45 * @{ 46 */ 47 48 /** 49 * @brief Internals of DBusCounter. 50 * 51 * DBusCounter internals. DBusCounter is an opaque object, it must be 52 * used via accessor functions. 53 */ 54 struct DBusCounter 55 { 56 int refcount; /**< reference count */ 57 58 long size_value; /**< current size counter value */ 59 long unix_fd_value; /**< current unix fd counter value */ 60 61 #ifdef DBUS_ENABLE_STATS 62 long peak_size_value; /**< largest ever size counter value */ 63 long peak_unix_fd_value; /**< largest ever unix fd counter value */ 64 #endif 65 66 long notify_size_guard_value; /**< call notify function when crossing this size value */ 67 long notify_unix_fd_guard_value; /**< call notify function when crossing this unix fd value */ 68 69 DBusCounterNotifyFunction notify_function; /**< notify function */ 70 void *notify_data; /**< data for notify function */ 71 dbus_bool_t notify_pending : 1; /**< TRUE if the guard value has been crossed */ 72 }; 73 74 /** @} */ /* end of resource limits internals docs */ 75 76 /** 77 * @addtogroup DBusResources 78 * @{ 79 */ 80 81 /** 82 * Creates a new DBusCounter. DBusCounter is used 83 * to count usage of some resource such as memory. 84 * 85 * @returns new counter or #NULL on failure 86 */ 87 DBusCounter* 88 _dbus_counter_new (void) 89 { 90 DBusCounter *counter; 91 92 counter = dbus_new0 (DBusCounter, 1); 93 if (counter == NULL) 94 return NULL; 95 96 counter->refcount = 1; 97 98 return counter; 99 } 100 101 /** 102 * Increments refcount of the counter 103 * 104 * @param counter the counter 105 * @returns the counter 106 */ 107 DBusCounter * 108 _dbus_counter_ref (DBusCounter *counter) 109 { 110 _dbus_assert (counter->refcount > 0); 111 112 counter->refcount += 1; 113 114 return counter; 115 } 116 117 /** 118 * Decrements refcount of the counter and possibly 119 * finalizes the counter. 120 * 121 * @param counter the counter 122 */ 123 void 124 _dbus_counter_unref (DBusCounter *counter) 125 { 126 _dbus_assert (counter->refcount > 0); 127 128 counter->refcount -= 1; 129 130 if (counter->refcount == 0) 131 { 132 133 dbus_free (counter); 134 } 135 } 136 137 /** 138 * Adjusts the value of the size counter by the given 139 * delta which may be positive or negative. 140 * 141 * This function may be called with locks held. After calling it, when 142 * any relevant locks are no longer held you must call _dbus_counter_notify(). 143 * 144 * @param counter the counter 145 * @param delta value to add to the size counter's current value 146 */ 147 void 148 _dbus_counter_adjust_size (DBusCounter *counter, 149 long delta) 150 { 151 long old = counter->size_value; 152 153 counter->size_value += delta; 154 155 #ifdef DBUS_ENABLE_STATS 156 if (counter->peak_size_value < counter->size_value) 157 counter->peak_size_value = counter->size_value; 158 #endif 159 160 #if 0 161 _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n", 162 old, delta, counter->size_value); 163 #endif 164 165 if (counter->notify_function != NULL && 166 ((old < counter->notify_size_guard_value && 167 counter->size_value >= counter->notify_size_guard_value) || 168 (old >= counter->notify_size_guard_value && 169 counter->size_value < counter->notify_size_guard_value))) 170 counter->notify_pending = TRUE; 171 } 172 173 /** 174 * Calls the notify function from _dbus_counter_set_notify(), 175 * if that function has been specified and the counter has crossed the 176 * guard value (in either direction) since the last call to this function. 177 * 178 * This function must not be called with locks held, since it can call out 179 * to user code. 180 */ 181 void 182 _dbus_counter_notify (DBusCounter *counter) 183 { 184 if (counter->notify_pending) 185 { 186 counter->notify_pending = FALSE; 187 (* counter->notify_function) (counter, counter->notify_data); 188 } 189 } 190 191 /** 192 * Adjusts the value of the unix fd counter by the given 193 * delta which may be positive or negative. 194 * 195 * This function may be called with locks held. After calling it, when 196 * any relevant locks are no longer held you must call _dbus_counter_notify(). 197 * 198 * @param counter the counter 199 * @param delta value to add to the unix fds counter's current value 200 */ 201 void 202 _dbus_counter_adjust_unix_fd (DBusCounter *counter, 203 long delta) 204 { 205 long old = counter->unix_fd_value; 206 207 counter->unix_fd_value += delta; 208 209 #ifdef DBUS_ENABLE_STATS 210 if (counter->peak_unix_fd_value < counter->unix_fd_value) 211 counter->peak_unix_fd_value = counter->unix_fd_value; 212 #endif 213 214 #if 0 215 _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n", 216 old, delta, counter->unix_fd_value); 217 #endif 218 219 if (counter->notify_function != NULL && 220 ((old < counter->notify_unix_fd_guard_value && 221 counter->unix_fd_value >= counter->notify_unix_fd_guard_value) || 222 (old >= counter->notify_unix_fd_guard_value && 223 counter->unix_fd_value < counter->notify_unix_fd_guard_value))) 224 counter->notify_pending = TRUE; 225 } 226 227 /** 228 * Gets the current value of the size counter. 229 * 230 * @param counter the counter 231 * @returns its current size value 232 */ 233 long 234 _dbus_counter_get_size_value (DBusCounter *counter) 235 { 236 return counter->size_value; 237 } 238 239 /** 240 * Gets the current value of the unix fd counter. 241 * 242 * @param counter the counter 243 * @returns its current unix fd value 244 */ 245 long 246 _dbus_counter_get_unix_fd_value (DBusCounter *counter) 247 { 248 return counter->unix_fd_value; 249 } 250 251 /** 252 * Sets the notify function for this counter; the notify function is 253 * called whenever the counter's values cross the guard values in 254 * either direction (moving up, or moving down). 255 * 256 * @param counter the counter 257 * @param size_guard_value the value we're notified if the size counter crosses 258 * @param unix_fd_guard_value the value we're notified if the unix fd counter crosses 259 * @param function function to call in order to notify 260 * @param user_data data to pass to the function 261 */ 262 void 263 _dbus_counter_set_notify (DBusCounter *counter, 264 long size_guard_value, 265 long unix_fd_guard_value, 266 DBusCounterNotifyFunction function, 267 void *user_data) 268 { 269 counter->notify_size_guard_value = size_guard_value; 270 counter->notify_unix_fd_guard_value = unix_fd_guard_value; 271 counter->notify_function = function; 272 counter->notify_data = user_data; 273 counter->notify_pending = FALSE; 274 } 275 276 #ifdef DBUS_ENABLE_STATS 277 long 278 _dbus_counter_get_peak_size_value (DBusCounter *counter) 279 { 280 return counter->peak_size_value; 281 } 282 283 long 284 _dbus_counter_get_peak_unix_fd_value (DBusCounter *counter) 285 { 286 return counter->peak_unix_fd_value; 287 } 288 #endif 289 290 /** @} */ /* end of resource limits exported API */ 291