Merge branch 'dbus-1.4'
[platform/upstream/dbus.git] / dbus / dbus-resources.c
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_new (DBusCounter, 1);
93   if (counter == NULL)
94     return NULL;
95   
96   counter->refcount = 1;
97   counter->size_value = 0;
98   counter->unix_fd_value = 0;
99
100 #ifdef DBUS_ENABLE_STATS
101   counter->peak_size_value = 0;
102   counter->peak_unix_fd_value = 0;
103 #endif
104
105   counter->notify_size_guard_value = 0;
106   counter->notify_unix_fd_guard_value = 0;
107   counter->notify_function = NULL;
108   counter->notify_data = NULL;
109   counter->notify_pending = FALSE;
110   
111   return counter;
112 }
113
114 /**
115  * Increments refcount of the counter
116  *
117  * @param counter the counter
118  * @returns the counter
119  */
120 DBusCounter *
121 _dbus_counter_ref (DBusCounter *counter)
122 {
123   _dbus_assert (counter->refcount > 0);
124   
125   counter->refcount += 1;
126
127   return counter;
128 }
129
130 /**
131  * Decrements refcount of the counter and possibly
132  * finalizes the counter.
133  *
134  * @param counter the counter
135  */
136 void
137 _dbus_counter_unref (DBusCounter *counter)
138 {
139   _dbus_assert (counter->refcount > 0);
140
141   counter->refcount -= 1;
142
143   if (counter->refcount == 0)
144     {
145       
146       dbus_free (counter);
147     }
148 }
149
150 /**
151  * Adjusts the value of the size counter by the given
152  * delta which may be positive or negative.
153  *
154  * This function may be called with locks held. After calling it, when
155  * any relevant locks are no longer held you must call _dbus_counter_notify().
156  *
157  * @param counter the counter
158  * @param delta value to add to the size counter's current value
159  */
160 void
161 _dbus_counter_adjust_size (DBusCounter *counter,
162                            long         delta)
163 {
164   long old = counter->size_value;
165
166   counter->size_value += delta;
167
168 #ifdef DBUS_ENABLE_STATS
169   if (counter->peak_size_value < counter->size_value)
170     counter->peak_size_value = counter->size_value;
171 #endif
172
173 #if 0
174   _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
175                  old, delta, counter->size_value);
176 #endif
177
178   if (counter->notify_function != NULL &&
179       ((old < counter->notify_size_guard_value &&
180         counter->size_value >= counter->notify_size_guard_value) ||
181        (old >= counter->notify_size_guard_value &&
182         counter->size_value < counter->notify_size_guard_value)))
183     counter->notify_pending = TRUE;
184 }
185
186 /**
187  * Calls the notify function from _dbus_counter_set_notify(),
188  * if that function has been specified and the counter has crossed the
189  * guard value (in either direction) since the last call to this function.
190  *
191  * This function must not be called with locks held, since it can call out
192  * to user code.
193  */
194 void
195 _dbus_counter_notify (DBusCounter *counter)
196 {
197   if (counter->notify_pending)
198     {
199       counter->notify_pending = FALSE;
200       (* counter->notify_function) (counter, counter->notify_data);
201     }
202 }
203
204 /**
205  * Adjusts the value of the unix fd counter by the given
206  * delta which may be positive or negative.
207  *
208  * This function may be called with locks held. After calling it, when
209  * any relevant locks are no longer held you must call _dbus_counter_notify().
210  *
211  * @param counter the counter
212  * @param delta value to add to the unix fds counter's current value
213  */
214 void
215 _dbus_counter_adjust_unix_fd (DBusCounter *counter,
216                               long         delta)
217 {
218   long old = counter->unix_fd_value;
219   
220   counter->unix_fd_value += delta;
221
222 #ifdef DBUS_ENABLE_STATS
223   if (counter->peak_unix_fd_value < counter->unix_fd_value)
224     counter->peak_unix_fd_value = counter->unix_fd_value;
225 #endif
226
227 #if 0
228   _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
229                  old, delta, counter->unix_fd_value);
230 #endif
231   
232   if (counter->notify_function != NULL &&
233       ((old < counter->notify_unix_fd_guard_value &&
234         counter->unix_fd_value >= counter->notify_unix_fd_guard_value) ||
235        (old >= counter->notify_unix_fd_guard_value &&
236         counter->unix_fd_value < counter->notify_unix_fd_guard_value)))
237     counter->notify_pending = TRUE;
238 }
239
240 /**
241  * Gets the current value of the size counter.
242  *
243  * @param counter the counter
244  * @returns its current size value
245  */
246 long
247 _dbus_counter_get_size_value (DBusCounter *counter)
248 {
249   return counter->size_value;
250 }
251
252 /**
253  * Gets the current value of the unix fd counter.
254  *
255  * @param counter the counter
256  * @returns its current unix fd value
257  */
258 long
259 _dbus_counter_get_unix_fd_value (DBusCounter *counter)
260 {
261   return counter->unix_fd_value;
262 }
263
264 /**
265  * Sets the notify function for this counter; the notify function is
266  * called whenever the counter's values cross the guard values in
267  * either direction (moving up, or moving down).
268  *
269  * @param counter the counter
270  * @param size_guard_value the value we're notified if the size counter crosses
271  * @param unix_fd_guard_value the value we're notified if the unix fd counter crosses
272  * @param function function to call in order to notify
273  * @param user_data data to pass to the function
274  */
275 void
276 _dbus_counter_set_notify (DBusCounter               *counter,
277                           long                       size_guard_value,
278                           long                       unix_fd_guard_value,
279                           DBusCounterNotifyFunction  function,
280                           void                      *user_data)
281 {
282   counter->notify_size_guard_value = size_guard_value;
283   counter->notify_unix_fd_guard_value = unix_fd_guard_value;
284   counter->notify_function = function;
285   counter->notify_data = user_data;
286   counter->notify_pending = FALSE;
287 }
288
289 #ifdef DBUS_ENABLE_STATS
290 long
291 _dbus_counter_get_peak_size_value (DBusCounter *counter)
292 {
293   return counter->peak_size_value;
294 }
295
296 long
297 _dbus_counter_get_peak_unix_fd_value (DBusCounter *counter)
298 {
299   return counter->peak_unix_fd_value;
300 }
301 #endif
302
303 /** @} */  /* end of resource limits exported API */