Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : ** prcountr.c -- NSPR Instrumentation Counters
8 : **
9 : ** Implement the interface defined in prcountr.h
10 : **
11 : ** Design Notes:
12 : **
13 : ** The Counter Facility (CF) has a single anchor: qNameList.
14 : ** The anchor is a PRCList. qNameList is a list of links in QName
15 : ** structures. From qNameList any QName structure and its
16 : ** associated RName structure can be located.
17 : **
18 : ** For each QName, a list of RName structures is anchored at
19 : ** rnLink in the QName structure.
20 : **
21 : ** The counter itself is embedded in the RName structure.
22 : **
23 : ** For manipulating the counter database, single lock is used to
24 : ** protect the entire list: counterLock.
25 : **
26 : ** A PRCounterHandle, defined in prcountr.h, is really a pointer
27 : ** to a RName structure. References by PRCounterHandle are
28 : ** dead-reconed to the RName structure. The PRCounterHandle is
29 : ** "overloaded" for traversing the QName structures; only the
30 : ** function PR_FindNextQnameHandle() uses this overloading.
31 : **
32 : **
33 : ** ToDo (lth): decide on how to lock or atomically update
34 : ** individual counters. Candidates are: the global lock; a lock
35 : ** per RName structure; Atomic operations (Note that there are
36 : ** not adaquate atomic operations (yet) to achieve this goal). At
37 : ** this writing (6/19/98) , the update of the counter variable in
38 : ** a QName structure is unprotected.
39 : **
40 : */
41 :
42 : #include "prcountr.h"
43 : #include "prclist.h"
44 : #include "prlock.h"
45 : #include "prlog.h"
46 : #include "prmem.h"
47 : #include <string.h>
48 :
49 : /*
50 : **
51 : */
52 : typedef struct QName
53 : {
54 : PRCList link;
55 : PRCList rNameList;
56 : char name[PRCOUNTER_NAME_MAX+1];
57 : } QName;
58 :
59 : /*
60 : **
61 : */
62 : typedef struct RName
63 : {
64 : PRCList link;
65 : QName *qName;
66 : PRLock *lock;
67 : volatile PRUint32 counter;
68 : char name[PRCOUNTER_NAME_MAX+1];
69 : char desc[PRCOUNTER_DESC_MAX+1];
70 : } RName;
71 :
72 :
73 : /*
74 : ** Define the Counter Facility database
75 : */
76 : static PRLock *counterLock;
77 : static PRCList qNameList;
78 : static PRLogModuleInfo *lm;
79 :
80 : /*
81 : ** _PR_CounterInitialize() -- Initialize the Counter Facility
82 : **
83 : */
84 0 : static void _PR_CounterInitialize( void )
85 : {
86 : /*
87 : ** This function should be called only once
88 : */
89 0 : PR_ASSERT( counterLock == NULL );
90 :
91 0 : counterLock = PR_NewLock();
92 0 : PR_INIT_CLIST( &qNameList );
93 0 : lm = PR_NewLogModule("counters");
94 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete"));
95 :
96 0 : return;
97 : } /* end _PR_CounterInitialize() */
98 :
99 : /*
100 : ** PR_CreateCounter() -- Create a counter
101 : **
102 : ** ValidateArguments
103 : ** Lock
104 : ** if (qName not already in database)
105 : ** NewQname
106 : ** if (rName already in database )
107 : ** Assert
108 : ** else NewRname
109 : ** NewCounter
110 : ** link 'em up
111 : ** Unlock
112 : **
113 : */
114 : PR_IMPLEMENT(PRCounterHandle)
115 : PR_CreateCounter(
116 : const char *qName,
117 : const char *rName,
118 : const char *description
119 : )
120 : {
121 : QName *qnp;
122 : RName *rnp;
123 0 : PRBool matchQname = PR_FALSE;
124 :
125 : /* Self initialize, if necessary */
126 0 : if ( counterLock == NULL )
127 0 : _PR_CounterInitialize();
128 :
129 : /* Validate input arguments */
130 0 : PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX );
131 0 : PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX );
132 0 : PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX );
133 :
134 : /* Lock the Facility */
135 0 : PR_Lock( counterLock );
136 :
137 : /* Do we already have a matching QName? */
138 0 : if (!PR_CLIST_IS_EMPTY( &qNameList ))
139 : {
140 0 : qnp = (QName *) PR_LIST_HEAD( &qNameList );
141 : do {
142 0 : if ( strcmp(qnp->name, qName) == 0)
143 : {
144 0 : matchQname = PR_TRUE;
145 0 : break;
146 : }
147 0 : qnp = (QName *)PR_NEXT_LINK( &qnp->link );
148 0 : } while( qnp != (QName *)&qNameList );
149 : }
150 : /*
151 : ** If we did not find a matching QName,
152 : ** allocate one and initialize it.
153 : ** link it onto the qNameList.
154 : **
155 : */
156 0 : if ( matchQname != PR_TRUE )
157 : {
158 0 : qnp = PR_NEWZAP( QName );
159 0 : PR_ASSERT( qnp != NULL );
160 0 : PR_INIT_CLIST( &qnp->link );
161 0 : PR_INIT_CLIST( &qnp->rNameList );
162 0 : strcpy( qnp->name, qName );
163 0 : PR_APPEND_LINK( &qnp->link, &qNameList );
164 : }
165 :
166 : /* Do we already have a matching RName? */
167 0 : if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
168 : {
169 0 : rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
170 : do {
171 : /*
172 : ** No duplicate RNames are allowed within a QName
173 : **
174 : */
175 0 : PR_ASSERT( strcmp(rnp->name, rName));
176 0 : rnp = (RName *)PR_NEXT_LINK( &rnp->link );
177 0 : } while( rnp != (RName *)&qnp->rNameList );
178 : }
179 :
180 : /* Get a new RName structure; initialize its members */
181 0 : rnp = PR_NEWZAP( RName );
182 0 : PR_ASSERT( rnp != NULL );
183 0 : PR_INIT_CLIST( &rnp->link );
184 0 : strcpy( rnp->name, rName );
185 0 : strcpy( rnp->desc, description );
186 0 : rnp->lock = PR_NewLock();
187 0 : if ( rnp->lock == NULL )
188 : {
189 0 : PR_ASSERT(0);
190 : }
191 :
192 0 : PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */
193 0 : rnp->qName = qnp; /* point the RName to the QName */
194 :
195 : /* Unlock the Facility */
196 0 : PR_Unlock( counterLock );
197 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t",
198 : qName, qnp, rName, rnp ));
199 :
200 0 : return((PRCounterHandle)rnp);
201 : } /* end PR_CreateCounter() */
202 :
203 :
204 : /*
205 : **
206 : */
207 : PR_IMPLEMENT(void)
208 : PR_DestroyCounter(
209 : PRCounterHandle handle
210 : )
211 : {
212 0 : RName *rnp = (RName *)handle;
213 0 : QName *qnp = rnp->qName;
214 :
215 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s",
216 : qnp->name, rnp->name));
217 :
218 : /* Lock the Facility */
219 0 : PR_Lock( counterLock );
220 :
221 : /*
222 : ** Remove RName from the list of RNames in QName
223 : ** and free RName
224 : */
225 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p",
226 : rnp->name, rnp));
227 0 : PR_REMOVE_LINK( &rnp->link );
228 0 : PR_Free( rnp->lock );
229 0 : PR_DELETE( rnp );
230 :
231 : /*
232 : ** If this is the last RName within QName
233 : ** remove QName from the qNameList and free it
234 : */
235 0 : if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
236 : {
237 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p",
238 : qnp->name, qnp));
239 0 : PR_REMOVE_LINK( &qnp->link );
240 0 : PR_DELETE( qnp );
241 : }
242 :
243 : /* Unlock the Facility */
244 0 : PR_Unlock( counterLock );
245 0 : return;
246 : } /* end PR_DestroyCounter() */
247 :
248 : /*
249 : **
250 : */
251 : PR_IMPLEMENT(PRCounterHandle)
252 : PR_GetCounterHandleFromName(
253 : const char *qName,
254 : const char *rName
255 : )
256 : {
257 : const char *qn, *rn, *desc;
258 0 : PRCounterHandle qh, rh = NULL;
259 0 : RName *rnp = NULL;
260 :
261 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t"
262 : "QName: %s, RName: %s", qName, rName ));
263 :
264 0 : qh = PR_FindNextCounterQname( NULL );
265 0 : while (qh != NULL)
266 : {
267 0 : rh = PR_FindNextCounterRname( NULL, qh );
268 0 : while ( rh != NULL )
269 : {
270 0 : PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc );
271 0 : if ( (strcmp( qName, qn ) == 0)
272 0 : && (strcmp( rName, rn ) == 0 ))
273 : {
274 0 : rnp = (RName *)rh;
275 0 : goto foundIt;
276 : }
277 0 : rh = PR_FindNextCounterRname( rh, qh );
278 : }
279 0 : qh = PR_FindNextCounterQname( NULL );
280 : }
281 :
282 : foundIt:
283 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
284 0 : return(rh);
285 : } /* end PR_GetCounterHandleFromName() */
286 :
287 : /*
288 : **
289 : */
290 : PR_IMPLEMENT(void)
291 : PR_GetCounterNameFromHandle(
292 : PRCounterHandle handle,
293 : const char **qName,
294 : const char **rName,
295 : const char **description
296 : )
297 : {
298 0 : RName *rnp = (RName *)handle;
299 0 : QName *qnp = rnp->qName;
300 :
301 0 : *qName = qnp->name;
302 0 : *rName = rnp->name;
303 0 : *description = rnp->desc;
304 :
305 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: "
306 : "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s",
307 : qnp, rnp, qnp->name, rnp->name, rnp->desc ));
308 :
309 0 : return;
310 : } /* end PR_GetCounterNameFromHandle() */
311 :
312 :
313 : /*
314 : **
315 : */
316 : PR_IMPLEMENT(void)
317 : PR_IncrementCounter(
318 : PRCounterHandle handle
319 : )
320 : {
321 0 : PR_Lock(((RName *)handle)->lock);
322 0 : ((RName *)handle)->counter++;
323 0 : PR_Unlock(((RName *)handle)->lock);
324 :
325 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld",
326 : handle, ((RName *)handle)->counter ));
327 :
328 0 : return;
329 : } /* end PR_IncrementCounter() */
330 :
331 :
332 :
333 : /*
334 : **
335 : */
336 : PR_IMPLEMENT(void)
337 : PR_DecrementCounter(
338 : PRCounterHandle handle
339 : )
340 : {
341 0 : PR_Lock(((RName *)handle)->lock);
342 0 : ((RName *)handle)->counter--;
343 0 : PR_Unlock(((RName *)handle)->lock);
344 :
345 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld",
346 : handle, ((RName *)handle)->counter ));
347 :
348 0 : return;
349 : } /* end PR_DecrementCounter() */
350 :
351 :
352 : /*
353 : **
354 : */
355 : PR_IMPLEMENT(void)
356 : PR_AddToCounter(
357 : PRCounterHandle handle,
358 : PRUint32 value
359 : )
360 : {
361 0 : PR_Lock(((RName *)handle)->lock);
362 0 : ((RName *)handle)->counter += value;
363 0 : PR_Unlock(((RName *)handle)->lock);
364 :
365 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld",
366 : handle, ((RName *)handle)->counter ));
367 :
368 0 : return;
369 : } /* end PR_AddToCounter() */
370 :
371 :
372 : /*
373 : **
374 : */
375 : PR_IMPLEMENT(void)
376 : PR_SubtractFromCounter(
377 : PRCounterHandle handle,
378 : PRUint32 value
379 : )
380 : {
381 0 : PR_Lock(((RName *)handle)->lock);
382 0 : ((RName *)handle)->counter -= value;
383 0 : PR_Unlock(((RName *)handle)->lock);
384 :
385 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld",
386 : handle, ((RName *)handle)->counter ));
387 :
388 0 : return;
389 : } /* end PR_SubtractFromCounter() */
390 :
391 : /*
392 : **
393 : */
394 : PR_IMPLEMENT(PRUint32)
395 : PR_GetCounter(
396 : PRCounterHandle handle
397 : )
398 : {
399 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld",
400 : handle, ((RName *)handle)->counter ));
401 :
402 0 : return(((RName *)handle)->counter);
403 : } /* end PR_GetCounter() */
404 :
405 : /*
406 : **
407 : */
408 : PR_IMPLEMENT(void)
409 : PR_SetCounter(
410 : PRCounterHandle handle,
411 : PRUint32 value
412 : )
413 : {
414 0 : ((RName *)handle)->counter = value;
415 :
416 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld",
417 : handle, ((RName *)handle)->counter ));
418 :
419 0 : return;
420 : } /* end PR_SetCounter() */
421 :
422 : /*
423 : **
424 : */
425 : PR_IMPLEMENT(PRCounterHandle)
426 : PR_FindNextCounterQname(
427 : PRCounterHandle handle
428 : )
429 : {
430 0 : QName *qnp = (QName *)handle;
431 :
432 0 : if ( PR_CLIST_IS_EMPTY( &qNameList ))
433 0 : qnp = NULL;
434 0 : else if ( qnp == NULL )
435 0 : qnp = (QName *)PR_LIST_HEAD( &qNameList );
436 0 : else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList )
437 0 : qnp = NULL;
438 : else
439 0 : qnp = (QName *)PR_NEXT_LINK( &qnp->link );
440 :
441 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p",
442 : handle, qnp ));
443 :
444 0 : return((PRCounterHandle)qnp);
445 : } /* end PR_FindNextCounterQname() */
446 :
447 :
448 : /*
449 : **
450 : */
451 : PR_IMPLEMENT(PRCounterHandle)
452 : PR_FindNextCounterRname(
453 : PRCounterHandle rhandle,
454 : PRCounterHandle qhandle
455 : )
456 : {
457 0 : RName *rnp = (RName *)rhandle;
458 0 : QName *qnp = (QName *)qhandle;
459 :
460 :
461 0 : if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
462 0 : rnp = NULL;
463 0 : else if ( rnp == NULL )
464 0 : rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
465 0 : else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList )
466 0 : rnp = NULL;
467 : else
468 0 : rnp = (RName *)PR_NEXT_LINK( &rnp->link );
469 :
470 0 : PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p",
471 : rhandle, qhandle, rnp ));
472 :
473 0 : return((PRCounterHandle)rnp);
474 : } /* end PR_FindNextCounterRname() */
|