|
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 static void _PR_CounterInitialize( void ) |
|
85 { |
|
86 /* |
|
87 ** This function should be called only once |
|
88 */ |
|
89 PR_ASSERT( counterLock == NULL ); |
|
90 |
|
91 counterLock = PR_NewLock(); |
|
92 PR_INIT_CLIST( &qNameList ); |
|
93 lm = PR_NewLogModule("counters"); |
|
94 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete")); |
|
95 |
|
96 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 PRBool matchQname = PR_FALSE; |
|
124 |
|
125 /* Self initialize, if necessary */ |
|
126 if ( counterLock == NULL ) |
|
127 _PR_CounterInitialize(); |
|
128 |
|
129 /* Validate input arguments */ |
|
130 PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX ); |
|
131 PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX ); |
|
132 PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX ); |
|
133 |
|
134 /* Lock the Facility */ |
|
135 PR_Lock( counterLock ); |
|
136 |
|
137 /* Do we already have a matching QName? */ |
|
138 if (!PR_CLIST_IS_EMPTY( &qNameList )) |
|
139 { |
|
140 qnp = (QName *) PR_LIST_HEAD( &qNameList ); |
|
141 do { |
|
142 if ( strcmp(qnp->name, qName) == 0) |
|
143 { |
|
144 matchQname = PR_TRUE; |
|
145 break; |
|
146 } |
|
147 qnp = (QName *)PR_NEXT_LINK( &qnp->link ); |
|
148 } 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 if ( matchQname != PR_TRUE ) |
|
157 { |
|
158 qnp = PR_NEWZAP( QName ); |
|
159 PR_ASSERT( qnp != NULL ); |
|
160 PR_INIT_CLIST( &qnp->link ); |
|
161 PR_INIT_CLIST( &qnp->rNameList ); |
|
162 strcpy( qnp->name, qName ); |
|
163 PR_APPEND_LINK( &qnp->link, &qNameList ); |
|
164 } |
|
165 |
|
166 /* Do we already have a matching RName? */ |
|
167 if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) |
|
168 { |
|
169 rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); |
|
170 do { |
|
171 /* |
|
172 ** No duplicate RNames are allowed within a QName |
|
173 ** |
|
174 */ |
|
175 PR_ASSERT( strcmp(rnp->name, rName)); |
|
176 rnp = (RName *)PR_NEXT_LINK( &rnp->link ); |
|
177 } while( rnp != (RName *)&qnp->rNameList ); |
|
178 } |
|
179 |
|
180 /* Get a new RName structure; initialize its members */ |
|
181 rnp = PR_NEWZAP( RName ); |
|
182 PR_ASSERT( rnp != NULL ); |
|
183 PR_INIT_CLIST( &rnp->link ); |
|
184 strcpy( rnp->name, rName ); |
|
185 strcpy( rnp->desc, description ); |
|
186 rnp->lock = PR_NewLock(); |
|
187 if ( rnp->lock == NULL ) |
|
188 { |
|
189 PR_ASSERT(0); |
|
190 } |
|
191 |
|
192 PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ |
|
193 rnp->qName = qnp; /* point the RName to the QName */ |
|
194 |
|
195 /* Unlock the Facility */ |
|
196 PR_Unlock( counterLock ); |
|
197 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", |
|
198 qName, qnp, rName, rnp )); |
|
199 |
|
200 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 RName *rnp = (RName *)handle; |
|
213 QName *qnp = rnp->qName; |
|
214 |
|
215 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", |
|
216 qnp->name, rnp->name)); |
|
217 |
|
218 /* Lock the Facility */ |
|
219 PR_Lock( counterLock ); |
|
220 |
|
221 /* |
|
222 ** Remove RName from the list of RNames in QName |
|
223 ** and free RName |
|
224 */ |
|
225 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p", |
|
226 rnp->name, rnp)); |
|
227 PR_REMOVE_LINK( &rnp->link ); |
|
228 PR_Free( rnp->lock ); |
|
229 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 if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) |
|
236 { |
|
237 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p", |
|
238 qnp->name, qnp)); |
|
239 PR_REMOVE_LINK( &qnp->link ); |
|
240 PR_DELETE( qnp ); |
|
241 } |
|
242 |
|
243 /* Unlock the Facility */ |
|
244 PR_Unlock( counterLock ); |
|
245 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 PRCounterHandle qh, rh = NULL; |
|
259 RName *rnp = NULL; |
|
260 |
|
261 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t" |
|
262 "QName: %s, RName: %s", qName, rName )); |
|
263 |
|
264 qh = PR_FindNextCounterQname( NULL ); |
|
265 while (qh != NULL) |
|
266 { |
|
267 rh = PR_FindNextCounterRname( NULL, qh ); |
|
268 while ( rh != NULL ) |
|
269 { |
|
270 PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc ); |
|
271 if ( (strcmp( qName, qn ) == 0) |
|
272 && (strcmp( rName, rn ) == 0 )) |
|
273 { |
|
274 rnp = (RName *)rh; |
|
275 goto foundIt; |
|
276 } |
|
277 rh = PR_FindNextCounterRname( rh, qh ); |
|
278 } |
|
279 qh = PR_FindNextCounterQname( NULL ); |
|
280 } |
|
281 |
|
282 foundIt: |
|
283 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); |
|
284 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 RName *rnp = (RName *)handle; |
|
299 QName *qnp = rnp->qName; |
|
300 |
|
301 *qName = qnp->name; |
|
302 *rName = rnp->name; |
|
303 *description = rnp->desc; |
|
304 |
|
305 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 return; |
|
310 } /* end PR_GetCounterNameFromHandle() */ |
|
311 |
|
312 |
|
313 /* |
|
314 ** |
|
315 */ |
|
316 PR_IMPLEMENT(void) |
|
317 PR_IncrementCounter( |
|
318 PRCounterHandle handle |
|
319 ) |
|
320 { |
|
321 PR_Lock(((RName *)handle)->lock); |
|
322 ((RName *)handle)->counter++; |
|
323 PR_Unlock(((RName *)handle)->lock); |
|
324 |
|
325 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", |
|
326 handle, ((RName *)handle)->counter )); |
|
327 |
|
328 return; |
|
329 } /* end PR_IncrementCounter() */ |
|
330 |
|
331 |
|
332 |
|
333 /* |
|
334 ** |
|
335 */ |
|
336 PR_IMPLEMENT(void) |
|
337 PR_DecrementCounter( |
|
338 PRCounterHandle handle |
|
339 ) |
|
340 { |
|
341 PR_Lock(((RName *)handle)->lock); |
|
342 ((RName *)handle)->counter--; |
|
343 PR_Unlock(((RName *)handle)->lock); |
|
344 |
|
345 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", |
|
346 handle, ((RName *)handle)->counter )); |
|
347 |
|
348 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 PR_Lock(((RName *)handle)->lock); |
|
362 ((RName *)handle)->counter += value; |
|
363 PR_Unlock(((RName *)handle)->lock); |
|
364 |
|
365 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", |
|
366 handle, ((RName *)handle)->counter )); |
|
367 |
|
368 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 PR_Lock(((RName *)handle)->lock); |
|
382 ((RName *)handle)->counter -= value; |
|
383 PR_Unlock(((RName *)handle)->lock); |
|
384 |
|
385 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", |
|
386 handle, ((RName *)handle)->counter )); |
|
387 |
|
388 return; |
|
389 } /* end PR_SubtractFromCounter() */ |
|
390 |
|
391 /* |
|
392 ** |
|
393 */ |
|
394 PR_IMPLEMENT(PRUint32) |
|
395 PR_GetCounter( |
|
396 PRCounterHandle handle |
|
397 ) |
|
398 { |
|
399 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", |
|
400 handle, ((RName *)handle)->counter )); |
|
401 |
|
402 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 ((RName *)handle)->counter = value; |
|
415 |
|
416 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", |
|
417 handle, ((RName *)handle)->counter )); |
|
418 |
|
419 return; |
|
420 } /* end PR_SetCounter() */ |
|
421 |
|
422 /* |
|
423 ** |
|
424 */ |
|
425 PR_IMPLEMENT(PRCounterHandle) |
|
426 PR_FindNextCounterQname( |
|
427 PRCounterHandle handle |
|
428 ) |
|
429 { |
|
430 QName *qnp = (QName *)handle; |
|
431 |
|
432 if ( PR_CLIST_IS_EMPTY( &qNameList )) |
|
433 qnp = NULL; |
|
434 else if ( qnp == NULL ) |
|
435 qnp = (QName *)PR_LIST_HEAD( &qNameList ); |
|
436 else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) |
|
437 qnp = NULL; |
|
438 else |
|
439 qnp = (QName *)PR_NEXT_LINK( &qnp->link ); |
|
440 |
|
441 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", |
|
442 handle, qnp )); |
|
443 |
|
444 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 RName *rnp = (RName *)rhandle; |
|
458 QName *qnp = (QName *)qhandle; |
|
459 |
|
460 |
|
461 if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) |
|
462 rnp = NULL; |
|
463 else if ( rnp == NULL ) |
|
464 rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); |
|
465 else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) |
|
466 rnp = NULL; |
|
467 else |
|
468 rnp = (RName *)PR_NEXT_LINK( &rnp->link ); |
|
469 |
|
470 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", |
|
471 rhandle, qhandle, rnp )); |
|
472 |
|
473 return((PRCounterHandle)rnp); |
|
474 } /* end PR_FindNextCounterRname() */ |