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