home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /*
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- /*
- ** Thread safe versions of malloc, free, realloc, calloc and cfree.
- */
-
- #include "primpl.h"
-
- /*
- ** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply
- ** call their libc equivalents now. This may seem redundant, but it
- ** ensures that we are calling into the same runtime library. On
- ** Win32, it is possible to have multiple runtime libraries (e.g.,
- ** objects compiled with /MD and /MDd) in the same process, and
- ** they maintain separate heaps, which cannot be mixed.
- */
- PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
- {
- #if defined (WIN16)
- return PR_MD_malloc( (size_t) size);
- #else
- return malloc(size);
- #endif
- }
-
- PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
- {
- #if defined (WIN16)
- return PR_MD_calloc( (size_t)nelem, (size_t)elsize );
-
- #else
- return calloc(nelem, elsize);
- #endif
- }
-
- PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
- {
- #if defined (WIN16)
- return PR_MD_realloc( ptr, (size_t) size);
- #else
- return realloc(ptr, size);
- #endif
- }
-
- PR_IMPLEMENT(void) PR_Free(void *ptr)
- {
- #if defined (WIN16)
- PR_MD_free( ptr );
- #else
- free(ptr);
- #endif
- }
-
- /*
- ** Complexity alert!
- **
- ** If malloc/calloc/free (etc.) were implemented to use pr lock's then
- ** the entry points could block when called if some other thread had the
- ** lock.
- **
- ** Most of the time this isn't a problem. However, in the case that we
- ** are using the thread safe malloc code after PR_Init but before
- ** PR_AttachThread has been called (on a native thread that nspr has yet
- ** to be told about) we could get royally screwed if the lock was busy
- ** and we tried to context switch the thread away. In this scenario
- ** PR_CURRENT_THREAD() == NULL
- **
- ** To avoid this unfortunate case, we use the low level locking
- ** facilities for malloc protection instead of the slightly higher level
- ** locking. This makes malloc somewhat faster so maybe it's a good thing
- ** anyway.
- */
- #ifdef _PR_OVERRIDE_MALLOC
-
- /* Imports */
- extern void *_PR_UnlockedMalloc(size_t size);
- extern void *_PR_UnlockedMemalign(size_t alignment, size_t size);
- extern void _PR_UnlockedFree(void *ptr);
- extern void *_PR_UnlockedRealloc(void *ptr, size_t size);
- extern void *_PR_UnlockedCalloc(size_t n, size_t elsize);
-
- static PRBool _PR_malloc_initialised = PR_FALSE;
-
- #ifdef _PR_PTHREADS
- static pthread_mutex_t _PR_MD_malloc_crustylock;
-
- #define _PR_Lock_Malloc() { \
- if(PR_TRUE == _PR_malloc_initialised) { \
- PRStatus rv; \
- rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \
- PR_ASSERT(0 == rv); \
- }
-
- #define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \
- PRStatus rv; \
- rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \
- PR_ASSERT(0 == rv); \
- } \
- }
- #else /* _PR_PTHREADS */
- static _MDLock _PR_MD_malloc_crustylock;
-
- #define _PR_Lock_Malloc() { \
- PRIntn _is; \
- if(PR_TRUE == _PR_malloc_initialised) { \
- if (_PR_MD_CURRENT_THREAD() && \
- !_PR_IS_NATIVE_THREAD( \
- _PR_MD_CURRENT_THREAD())) \
- _PR_INTSOFF(_is); \
- _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
- }
-
- #define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \
- _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
- if (_PR_MD_CURRENT_THREAD() && \
- !_PR_IS_NATIVE_THREAD( \
- _PR_MD_CURRENT_THREAD())) \
- _PR_INTSON(_is); \
- } \
- }
- #endif /* _PR_PTHREADS */
-
- PR_IMPLEMENT(PRStatus) _PR_MallocInit(void)
- {
- PRStatus rv = PR_SUCCESS;
-
- if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS;
-
- #ifdef _PR_PTHREADS
- {
- int status;
- pthread_mutexattr_t mattr;
-
- status = PTHREAD_MUTEXATTR_INIT(&mattr);
- PR_ASSERT(0 == status);
- status = PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr);
- PR_ASSERT(0 == status);
- status = PTHREAD_MUTEXATTR_DESTROY(&mattr);
- PR_ASSERT(0 == status);
- }
- #else /* _PR_PTHREADS */
- _MD_NEW_LOCK(&_PR_MD_malloc_crustylock);
- #endif /* _PR_PTHREADS */
-
- if( PR_SUCCESS == rv )
- {
- _PR_malloc_initialised = PR_TRUE;
- }
-
- return rv;
- }
-
- void *malloc(size_t size)
- {
- void *p;
- _PR_Lock_Malloc();
- p = _PR_UnlockedMalloc(size);
- _PR_Unlock_Malloc();
- return p;
- }
-
- #if defined(IRIX)
- void *memalign(size_t alignment, size_t size)
- {
- void *p;
- _PR_Lock_Malloc();
- p = _PR_UnlockedMemalign(alignment, size);
- _PR_Unlock_Malloc();
- return p;
- }
-
- void *valloc(size_t size)
- {
- return(memalign(sysconf(_SC_PAGESIZE),size));
- }
- #endif /* IRIX */
-
- void free(void *ptr)
- {
- _PR_Lock_Malloc();
- _PR_UnlockedFree(ptr);
- _PR_Unlock_Malloc();
- }
-
- void *realloc(void *ptr, size_t size)
- {
- void *p;
- _PR_Lock_Malloc();
- p = _PR_UnlockedRealloc(ptr, size);
- _PR_Unlock_Malloc();
- return p;
- }
-
- void *calloc(size_t n, size_t elsize)
- {
- void *p;
- _PR_Lock_Malloc();
- p = _PR_UnlockedCalloc(n, elsize);
- _PR_Unlock_Malloc();
- return p;
- }
-
- void cfree(void *p)
- {
- _PR_Lock_Malloc();
- _PR_UnlockedFree(p);
- _PR_Unlock_Malloc();
- }
-
- void _PR_InitMem(void)
- {
- PRStatus rv;
- rv = _PR_MallocInit();
- PR_ASSERT(PR_SUCCESS == rv);
- }
-
- #endif /* _PR_OVERRIDE_MALLOC */
-