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/. */
7 ** prcountr.c -- NSPR Instrumentation Counters
9 ** Implement the interface defined in prcountr.h
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.
18 ** For each QName, a list of RName structures is anchored at
19 ** rnLink in the QName structure.
21 ** The counter itself is embedded in the RName structure.
23 ** For manipulating the counter database, single lock is used to
24 ** protect the entire list: counterLock.
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.
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.
52 typedef struct QName
{
55 char name
[PRCOUNTER_NAME_MAX
+ 1];
61 typedef struct RName
{
65 volatile PRUint32 counter
;
66 char name
[PRCOUNTER_NAME_MAX
+ 1];
67 char desc
[PRCOUNTER_DESC_MAX
+ 1];
71 ** Define the Counter Facility database
73 static PRLock
* counterLock
;
74 static PRCList qNameList
;
75 static PRLogModuleInfo
* lm
;
78 ** _PR_CounterInitialize() -- Initialize the Counter Facility
81 static void _PR_CounterInitialize(void) {
83 ** This function should be called only once
85 PR_ASSERT(counterLock
== NULL
);
87 counterLock
= PR_NewLock();
88 PR_INIT_CLIST(&qNameList
);
89 lm
= PR_NewLogModule("counters");
90 PR_LOG(lm
, PR_LOG_DEBUG
, ("PR_Counter: Initialization complete"));
93 } /* end _PR_CounterInitialize() */
96 ** PR_CreateCounter() -- Create a counter
100 ** if (qName not already in database)
102 ** if (rName already in database )
110 PR_IMPLEMENT(PRCounterHandle
)
111 PR_CreateCounter(const char* qName
, const char* rName
,
112 const char* description
) {
115 PRBool matchQname
= PR_FALSE
;
117 /* Self initialize, if necessary */
118 if (counterLock
== NULL
) {
119 _PR_CounterInitialize();
122 /* Validate input arguments */
123 PR_ASSERT(strlen(qName
) <= PRCOUNTER_NAME_MAX
);
124 PR_ASSERT(strlen(rName
) <= PRCOUNTER_NAME_MAX
);
125 PR_ASSERT(strlen(description
) <= PRCOUNTER_DESC_MAX
);
127 /* Lock the Facility */
128 PR_Lock(counterLock
);
130 /* Do we already have a matching QName? */
131 if (!PR_CLIST_IS_EMPTY(&qNameList
)) {
132 qnp
= (QName
*)PR_LIST_HEAD(&qNameList
);
134 if (strcmp(qnp
->name
, qName
) == 0) {
135 matchQname
= PR_TRUE
;
138 qnp
= (QName
*)PR_NEXT_LINK(&qnp
->link
);
139 } while (qnp
!= (QName
*)&qNameList
);
142 ** If we did not find a matching QName,
143 ** allocate one and initialize it.
144 ** link it onto the qNameList.
147 if (matchQname
!= PR_TRUE
) {
148 qnp
= PR_NEWZAP(QName
);
149 PR_ASSERT(qnp
!= NULL
);
150 PR_INIT_CLIST(&qnp
->link
);
151 PR_INIT_CLIST(&qnp
->rNameList
);
152 strcpy(qnp
->name
, qName
);
153 PR_APPEND_LINK(&qnp
->link
, &qNameList
);
156 /* Do we already have a matching RName? */
157 if (!PR_CLIST_IS_EMPTY(&qnp
->rNameList
)) {
158 rnp
= (RName
*)PR_LIST_HEAD(&qnp
->rNameList
);
161 ** No duplicate RNames are allowed within a QName
164 PR_ASSERT(strcmp(rnp
->name
, rName
));
165 rnp
= (RName
*)PR_NEXT_LINK(&rnp
->link
);
166 } while (rnp
!= (RName
*)&qnp
->rNameList
);
169 /* Get a new RName structure; initialize its members */
170 rnp
= PR_NEWZAP(RName
);
171 PR_ASSERT(rnp
!= NULL
);
172 PR_INIT_CLIST(&rnp
->link
);
173 strcpy(rnp
->name
, rName
);
174 strcpy(rnp
->desc
, description
);
175 rnp
->lock
= PR_NewLock();
176 if (rnp
->lock
== NULL
) {
180 PR_APPEND_LINK(&rnp
->link
, &qnp
->rNameList
); /* add RName to QName's rnList */
181 rnp
->qName
= qnp
; /* point the RName to the QName */
183 /* Unlock the Facility */
184 PR_Unlock(counterLock
);
185 PR_LOG(lm
, PR_LOG_DEBUG
,
186 ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", qName
, qnp
,
189 return ((PRCounterHandle
)rnp
);
190 } /* end PR_CreateCounter() */
196 PR_DestroyCounter(PRCounterHandle handle
) {
197 RName
* rnp
= (RName
*)handle
;
198 QName
* qnp
= rnp
->qName
;
200 PR_LOG(lm
, PR_LOG_DEBUG
,
201 ("PR_Counter: Deleting: QName: %s, RName: %s", qnp
->name
, rnp
->name
));
203 /* Lock the Facility */
204 PR_Lock(counterLock
);
207 ** Remove RName from the list of RNames in QName
210 PR_LOG(lm
, PR_LOG_DEBUG
,
211 ("PR_Counter: Deleting RName: %s, %p", rnp
->name
, rnp
));
212 PR_REMOVE_LINK(&rnp
->link
);
217 ** If this is the last RName within QName
218 ** remove QName from the qNameList and free it
220 if (PR_CLIST_IS_EMPTY(&qnp
->rNameList
)) {
221 PR_LOG(lm
, PR_LOG_DEBUG
,
222 ("PR_Counter: Deleting unused QName: %s, %p", qnp
->name
, qnp
));
223 PR_REMOVE_LINK(&qnp
->link
);
227 /* Unlock the Facility */
228 PR_Unlock(counterLock
);
230 } /* end PR_DestroyCounter() */
235 PR_IMPLEMENT(PRCounterHandle
)
236 PR_GetCounterHandleFromName(const char* qName
, const char* rName
) {
237 const char *qn
, *rn
, *desc
;
238 PRCounterHandle qh
, rh
= NULL
;
241 PR_LOG(lm
, PR_LOG_DEBUG
,
242 ("PR_Counter: GetCounterHandleFromName:\n\t"
243 "QName: %s, RName: %s",
246 qh
= PR_FindNextCounterQname(NULL
);
248 rh
= PR_FindNextCounterRname(NULL
, qh
);
250 PR_GetCounterNameFromHandle(rh
, &qn
, &rn
, &desc
);
251 if ((strcmp(qName
, qn
) == 0) && (strcmp(rName
, rn
) == 0)) {
255 rh
= PR_FindNextCounterRname(rh
, qh
);
257 qh
= PR_FindNextCounterQname(NULL
);
261 PR_LOG(lm
, PR_LOG_DEBUG
, ("PR_Counter: GetConterHandleFromName: %p", rnp
));
263 } /* end PR_GetCounterHandleFromName() */
269 PR_GetCounterNameFromHandle(PRCounterHandle handle
, const char** qName
,
270 const char** rName
, const char** description
) {
271 RName
* rnp
= (RName
*)handle
;
272 QName
* qnp
= rnp
->qName
;
276 *description
= rnp
->desc
;
278 PR_LOG(lm
, PR_LOG_DEBUG
,
279 ("PR_Counter: GetConterNameFromHandle: "
280 "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s",
281 qnp
, rnp
, qnp
->name
, rnp
->name
, rnp
->desc
));
284 } /* end PR_GetCounterNameFromHandle() */
290 PR_IncrementCounter(PRCounterHandle handle
) {
291 PR_Lock(((RName
*)handle
)->lock
);
292 ((RName
*)handle
)->counter
++;
293 PR_Unlock(((RName
*)handle
)->lock
);
295 PR_LOG(lm
, PR_LOG_DEBUG
,
296 ("PR_Counter: Increment: %p, %ld", handle
, ((RName
*)handle
)->counter
));
299 } /* end PR_IncrementCounter() */
305 PR_DecrementCounter(PRCounterHandle handle
) {
306 PR_Lock(((RName
*)handle
)->lock
);
307 ((RName
*)handle
)->counter
--;
308 PR_Unlock(((RName
*)handle
)->lock
);
310 PR_LOG(lm
, PR_LOG_DEBUG
,
311 ("PR_Counter: Decrement: %p, %ld", handle
, ((RName
*)handle
)->counter
));
314 } /* end PR_DecrementCounter() */
320 PR_AddToCounter(PRCounterHandle handle
, PRUint32 value
) {
321 PR_Lock(((RName
*)handle
)->lock
);
322 ((RName
*)handle
)->counter
+= value
;
323 PR_Unlock(((RName
*)handle
)->lock
);
327 ("PR_Counter: AddToCounter: %p, %ld", handle
, ((RName
*)handle
)->counter
));
330 } /* end PR_AddToCounter() */
336 PR_SubtractFromCounter(PRCounterHandle handle
, PRUint32 value
) {
337 PR_Lock(((RName
*)handle
)->lock
);
338 ((RName
*)handle
)->counter
-= value
;
339 PR_Unlock(((RName
*)handle
)->lock
);
341 PR_LOG(lm
, PR_LOG_DEBUG
,
342 ("PR_Counter: SubtractFromCounter: %p, %ld", handle
,
343 ((RName
*)handle
)->counter
));
346 } /* end PR_SubtractFromCounter() */
351 PR_IMPLEMENT(PRUint32
)
352 PR_GetCounter(PRCounterHandle handle
) {
355 ("PR_Counter: GetCounter: %p, %ld", handle
, ((RName
*)handle
)->counter
));
357 return (((RName
*)handle
)->counter
);
358 } /* end PR_GetCounter() */
364 PR_SetCounter(PRCounterHandle handle
, PRUint32 value
) {
365 ((RName
*)handle
)->counter
= value
;
369 ("PR_Counter: SetCounter: %p, %ld", handle
, ((RName
*)handle
)->counter
));
372 } /* end PR_SetCounter() */
377 PR_IMPLEMENT(PRCounterHandle
)
378 PR_FindNextCounterQname(PRCounterHandle handle
) {
379 QName
* qnp
= (QName
*)handle
;
381 if (PR_CLIST_IS_EMPTY(&qNameList
)) {
383 } else if (qnp
== NULL
) {
384 qnp
= (QName
*)PR_LIST_HEAD(&qNameList
);
385 } else if (PR_NEXT_LINK(&qnp
->link
) == &qNameList
) {
388 qnp
= (QName
*)PR_NEXT_LINK(&qnp
->link
);
391 PR_LOG(lm
, PR_LOG_DEBUG
,
392 ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", handle
, qnp
));
394 return ((PRCounterHandle
)qnp
);
395 } /* end PR_FindNextCounterQname() */
400 PR_IMPLEMENT(PRCounterHandle
)
401 PR_FindNextCounterRname(PRCounterHandle rhandle
, PRCounterHandle qhandle
) {
402 RName
* rnp
= (RName
*)rhandle
;
403 QName
* qnp
= (QName
*)qhandle
;
405 if (PR_CLIST_IS_EMPTY(&qnp
->rNameList
)) {
407 } else if (rnp
== NULL
) {
408 rnp
= (RName
*)PR_LIST_HEAD(&qnp
->rNameList
);
409 } else if (PR_NEXT_LINK(&rnp
->link
) == &qnp
->rNameList
) {
412 rnp
= (RName
*)PR_NEXT_LINK(&rnp
->link
);
415 PR_LOG(lm
, PR_LOG_DEBUG
,
416 ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p",
417 rhandle
, qhandle
, rnp
));
419 return ((PRCounterHandle
)rnp
);
420 } /* end PR_FindNextCounterRname() */