[nss] Import Firefox 3.0 beta 5 tarball
[mozilla-nss.git] / security / nss / lib / base / tracker.c
blob3e628968c20ac5f46c039db272a6e5758c262467
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef DEBUG
38 static const char CVS_ID[] = "@(#) $RCSfile: tracker.c,v $ $Revision: 1.7 $ $Date: 2008/02/23 05:29:24 $";
39 #endif /* DEBUG */
42 * tracker.c
44 * This file contains the code used by the pointer-tracking calls used
45 * in the debug builds to catch bad pointers. The entire contents are
46 * only available in debug builds (both internal and external builds).
49 #ifndef BASE_H
50 #include "base.h"
51 #endif /* BASE_H */
53 #ifdef DEBUG
55 * identity_hash
57 * This static callback is a PLHashFunction as defined in plhash.h
58 * It merely returns the value of the object pointer as its hash.
59 * There are no possible errors.
62 static PLHashNumber PR_CALLBACK
63 identity_hash
65 const void *key
68 return (PLHashNumber)key;
72 * trackerOnceFunc
74 * This function is called once, using the nssCallOnce function above.
75 * It creates a new pointer tracker object; initialising its hash
76 * table and protective lock.
79 static PRStatus
80 trackerOnceFunc
82 void *arg
85 nssPointerTracker *tracker = (nssPointerTracker *)arg;
87 tracker->lock = PZ_NewLock(nssILockOther);
88 if( (PZLock *)NULL == tracker->lock ) {
89 return PR_FAILURE;
92 tracker->table = PL_NewHashTable(0,
93 identity_hash,
94 PL_CompareValues,
95 PL_CompareValues,
96 (PLHashAllocOps *)NULL,
97 (void *)NULL);
98 if( (PLHashTable *)NULL == tracker->table ) {
99 PZ_DestroyLock(tracker->lock);
100 tracker->lock = (PZLock *)NULL;
101 return PR_FAILURE;
104 return PR_SUCCESS;
108 * nssPointerTracker_initialize
110 * This method is only present in debug builds.
112 * This routine initializes an nssPointerTracker object. Note that
113 * the object must have been declared *static* to guarantee that it
114 * is in a zeroed state initially. This routine is idempotent, and
115 * may even be safely called by multiple threads simultaneously with
116 * the same argument. This routine returns a PRStatus value; if
117 * successful, it will return PR_SUCCESS. On failure it will set an
118 * error on the error stack and return PR_FAILURE.
120 * The error may be one of the following values:
121 * NSS_ERROR_NO_MEMORY
123 * Return value:
124 * PR_SUCCESS
125 * PR_FAILURE
128 NSS_IMPLEMENT PRStatus
129 nssPointerTracker_initialize
131 nssPointerTracker *tracker
134 PRStatus rv = PR_CallOnceWithArg(&tracker->once, trackerOnceFunc, tracker);
135 if( PR_SUCCESS != rv ) {
136 nss_SetError(NSS_ERROR_NO_MEMORY);
139 return rv;
142 #ifdef DONT_DESTROY_EMPTY_TABLES
143 /* See same #ifdef below */
145 * count_entries
147 * This static routine is a PLHashEnumerator, as defined in plhash.h.
148 * It merely causes the enumeration function to count the number of
149 * entries.
152 static PRIntn PR_CALLBACK
153 count_entries
155 PLHashEntry *he,
156 PRIntn index,
157 void *arg
160 return HT_ENUMERATE_NEXT;
162 #endif /* DONT_DESTROY_EMPTY_TABLES */
165 * zero_once
167 * This is a guaranteed zeroed once block. It's used to help clear
168 * the tracker.
171 static const PRCallOnceType zero_once;
174 * nssPointerTracker_finalize
176 * This method is only present in debug builds.
178 * This routine returns the nssPointerTracker object to the pre-
179 * initialized state, releasing all resources used by the object.
180 * It will *NOT* destroy the objects being tracked by the pointer
181 * (should any remain), and therefore cannot be used to "sweep up"
182 * remaining objects. This routine returns a PRStatus value; if
183 * successful, it will return PR_SUCCES. On failure it will set an
184 * error on the error stack and return PR_FAILURE. If any objects
185 * remain in the tracker when it is finalized, that will be treated
186 * as an error.
188 * The error may be one of the following values:
189 * NSS_ERROR_INVALID_POINTER
190 * NSS_ERROR_TRACKER_NOT_INITIALIZED
191 * NSS_ERROR_TRACKER_NOT_EMPTY
193 * Return value:
194 * PR_SUCCESS
195 * PR_FAILURE
198 NSS_IMPLEMENT PRStatus
199 nssPointerTracker_finalize
201 nssPointerTracker *tracker
204 PZLock *lock;
206 if( (nssPointerTracker *)NULL == tracker ) {
207 nss_SetError(NSS_ERROR_INVALID_POINTER);
208 return PR_FAILURE;
211 if( (PZLock *)NULL == tracker->lock ) {
212 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
213 return PR_FAILURE;
216 lock = tracker->lock;
217 PZ_Lock(lock);
219 if( (PLHashTable *)NULL == tracker->table ) {
220 PZ_Unlock(lock);
221 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
222 return PR_FAILURE;
225 #ifdef DONT_DESTROY_EMPTY_TABLES
227 * I changed my mind; I think we don't want this after all.
228 * Comments?
230 count = PL_HashTableEnumerateEntries(tracker->table,
231 count_entries,
232 (void *)NULL);
234 if( 0 != count ) {
235 PZ_Unlock(lock);
236 nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY);
237 return PR_FAILURE;
239 #endif /* DONT_DESTROY_EMPTY_TABLES */
241 PL_HashTableDestroy(tracker->table);
242 /* memset(tracker, 0, sizeof(nssPointerTracker)); */
243 tracker->once = zero_once;
244 tracker->lock = (PZLock *)NULL;
245 tracker->table = (PLHashTable *)NULL;
247 PZ_Unlock(lock);
248 PZ_DestroyLock(lock);
250 return PR_SUCCESS;
254 * nssPointerTracker_add
256 * This method is only present in debug builds.
258 * This routine adds the specified pointer to the nssPointerTracker
259 * object. It should be called in constructor objects to register
260 * new valid objects. The nssPointerTracker is threadsafe, but this
261 * call is not idempotent. This routine returns a PRStatus value;
262 * if successful it will return PR_SUCCESS. On failure it will set
263 * an error on the error stack and return PR_FAILURE.
265 * The error may be one of the following values:
266 * NSS_ERROR_INVALID_POINTER
267 * NSS_ERROR_NO_MEMORY
268 * NSS_ERROR_TRACKER_NOT_INITIALIZED
269 * NSS_ERROR_DUPLICATE_POINTER
271 * Return value:
272 * PR_SUCCESS
273 * PR_FAILURE
276 NSS_IMPLEMENT PRStatus
277 nssPointerTracker_add
279 nssPointerTracker *tracker,
280 const void *pointer
283 void *check;
284 PLHashEntry *entry;
286 if( (nssPointerTracker *)NULL == tracker ) {
287 nss_SetError(NSS_ERROR_INVALID_POINTER);
288 return PR_FAILURE;
291 if( (PZLock *)NULL == tracker->lock ) {
292 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
293 return PR_FAILURE;
296 PZ_Lock(tracker->lock);
298 if( (PLHashTable *)NULL == tracker->table ) {
299 PZ_Unlock(tracker->lock);
300 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
301 return PR_FAILURE;
304 check = PL_HashTableLookup(tracker->table, pointer);
305 if( (void *)NULL != check ) {
306 PZ_Unlock(tracker->lock);
307 nss_SetError(NSS_ERROR_DUPLICATE_POINTER);
308 return PR_FAILURE;
311 entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer);
313 PZ_Unlock(tracker->lock);
315 if( (PLHashEntry *)NULL == entry ) {
316 nss_SetError(NSS_ERROR_NO_MEMORY);
317 return PR_FAILURE;
320 return PR_SUCCESS;
324 * nssPointerTracker_remove
326 * This method is only present in debug builds.
328 * This routine removes the specified pointer from the
329 * nssPointerTracker object. It does not call any destructor for the
330 * object; rather, this should be called from the object's destructor.
331 * The nssPointerTracker is threadsafe, but this call is not
332 * idempotent. This routine returns a PRStatus value; if successful
333 * it will return PR_SUCCESS. On failure it will set an error on the
334 * error stack and return PR_FAILURE.
336 * The error may be one of the following values:
337 * NSS_ERROR_INVALID_POINTER
338 * NSS_ERROR_TRACKER_NOT_INITIALIZED
339 * NSS_ERROR_POINTER_NOT_REGISTERED
341 * Return value:
342 * PR_SUCCESS
343 * PR_FAILURE
346 NSS_IMPLEMENT PRStatus
347 nssPointerTracker_remove
349 nssPointerTracker *tracker,
350 const void *pointer
353 PRBool registered;
355 if( (nssPointerTracker *)NULL == tracker ) {
356 nss_SetError(NSS_ERROR_INVALID_POINTER);
357 return PR_FAILURE;
360 if( (PZLock *)NULL == tracker->lock ) {
361 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
362 return PR_FAILURE;
365 PZ_Lock(tracker->lock);
367 if( (PLHashTable *)NULL == tracker->table ) {
368 PZ_Unlock(tracker->lock);
369 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
370 return PR_FAILURE;
373 registered = PL_HashTableRemove(tracker->table, pointer);
374 PZ_Unlock(tracker->lock);
376 if( !registered ) {
377 nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
378 return PR_FAILURE;
381 return PR_SUCCESS;
385 * nssPointerTracker_verify
387 * This method is only present in debug builds.
389 * This routine verifies that the specified pointer has been registered
390 * with the nssPointerTracker object. The nssPointerTracker object is
391 * threadsafe, and this call may be safely called from multiple threads
392 * simultaneously with the same arguments. This routine returns a
393 * PRStatus value; if the pointer is registered this will return
394 * PR_SUCCESS. Otherwise it will set an error on the error stack and
395 * return PR_FAILURE. Although the error is suitable for leaving on
396 * the stack, callers may wish to augment the information available by
397 * placing a more type-specific error on the stack.
399 * The error may be one of the following values:
400 * NSS_ERROR_INVALID_POINTER
401 * NSS_ERROR_TRACKER_NOT_INITIALIZED
402 * NSS_ERROR_POINTER_NOT_REGISTERED
404 * Return value:
405 * PR_SUCCESS
406 * PR_FAILRUE
409 NSS_IMPLEMENT PRStatus
410 nssPointerTracker_verify
412 nssPointerTracker *tracker,
413 const void *pointer
416 void *check;
418 if( (nssPointerTracker *)NULL == tracker ) {
419 nss_SetError(NSS_ERROR_INVALID_POINTER);
420 return PR_FAILURE;
423 if( (PZLock *)NULL == tracker->lock ) {
424 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
425 return PR_FAILURE;
428 PZ_Lock(tracker->lock);
430 if( (PLHashTable *)NULL == tracker->table ) {
431 PZ_Unlock(tracker->lock);
432 nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED);
433 return PR_FAILURE;
436 check = PL_HashTableLookup(tracker->table, pointer);
437 PZ_Unlock(tracker->lock);
439 if( (void *)NULL == check ) {
440 nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED);
441 return PR_FAILURE;
444 return PR_SUCCESS;
447 #endif /* DEBUG */