| Index: nspr/pr/src/threads/prcmon.c
|
| diff --git a/nspr/pr/src/threads/prcmon.c b/nspr/pr/src/threads/prcmon.c
|
| deleted file mode 100644
|
| index 2a196e9d4cc97cdfc86f81d5fd50aa7701932135..0000000000000000000000000000000000000000
|
| --- a/nspr/pr/src/threads/prcmon.c
|
| +++ /dev/null
|
| @@ -1,431 +0,0 @@
|
| -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -#include "primpl.h"
|
| -
|
| -#include <stdlib.h>
|
| -#include <stddef.h>
|
| -
|
| -/* Lock used to lock the monitor cache */
|
| -#ifdef _PR_NO_PREEMPT
|
| -#define _PR_NEW_LOCK_MCACHE()
|
| -#define _PR_DESTROY_LOCK_MCACHE()
|
| -#define _PR_LOCK_MCACHE()
|
| -#define _PR_UNLOCK_MCACHE()
|
| -#else
|
| -#ifdef _PR_LOCAL_THREADS_ONLY
|
| -#define _PR_NEW_LOCK_MCACHE()
|
| -#define _PR_DESTROY_LOCK_MCACHE()
|
| -#define _PR_LOCK_MCACHE() { PRIntn _is; _PR_INTSOFF(_is)
|
| -#define _PR_UNLOCK_MCACHE() _PR_INTSON(_is); }
|
| -#else
|
| -PRLock *_pr_mcacheLock;
|
| -#define _PR_NEW_LOCK_MCACHE() (_pr_mcacheLock = PR_NewLock())
|
| -#define _PR_DESTROY_LOCK_MCACHE() \
|
| - PR_BEGIN_MACRO \
|
| - if (_pr_mcacheLock) { \
|
| - PR_DestroyLock(_pr_mcacheLock); \
|
| - _pr_mcacheLock = NULL; \
|
| - } \
|
| - PR_END_MACRO
|
| -#define _PR_LOCK_MCACHE() PR_Lock(_pr_mcacheLock)
|
| -#define _PR_UNLOCK_MCACHE() PR_Unlock(_pr_mcacheLock)
|
| -#endif
|
| -#endif
|
| -
|
| -/************************************************************************/
|
| -
|
| -typedef struct MonitorCacheEntryStr MonitorCacheEntry;
|
| -
|
| -struct MonitorCacheEntryStr {
|
| - MonitorCacheEntry* next;
|
| - void* address;
|
| - PRMonitor* mon;
|
| - long cacheEntryCount;
|
| -};
|
| -
|
| -/*
|
| -** An array of MonitorCacheEntry's, plus a pointer to link these
|
| -** arrays together.
|
| -*/
|
| -
|
| -typedef struct MonitorCacheEntryBlockStr MonitorCacheEntryBlock;
|
| -
|
| -struct MonitorCacheEntryBlockStr {
|
| - MonitorCacheEntryBlock* next;
|
| - MonitorCacheEntry entries[1];
|
| -};
|
| -
|
| -static PRUint32 hash_mask;
|
| -static PRUintn num_hash_buckets;
|
| -static PRUintn num_hash_buckets_log2;
|
| -static MonitorCacheEntry **hash_buckets;
|
| -static MonitorCacheEntry *free_entries;
|
| -static PRUintn num_free_entries;
|
| -static PRBool expanding;
|
| -static MonitorCacheEntryBlock *mcache_blocks;
|
| -
|
| -static void (*OnMonitorRecycle)(void *address);
|
| -
|
| -#define HASH(address) \
|
| - ((PRUint32) ( ((PRUptrdiff)(address) >> 2) ^ \
|
| - ((PRUptrdiff)(address) >> 10) ) \
|
| - & hash_mask)
|
| -
|
| -/*
|
| -** Expand the monitor cache. This grows the hash buckets and allocates a
|
| -** new chunk of cache entries and throws them on the free list. We keep
|
| -** as many hash buckets as there are entries.
|
| -**
|
| -** Because we call malloc and malloc may need the monitor cache, we must
|
| -** ensure that there are several free monitor cache entries available for
|
| -** malloc to get. FREE_THRESHOLD is used to prevent monitor cache
|
| -** starvation during monitor cache expansion.
|
| -*/
|
| -
|
| -#define FREE_THRESHOLD 5
|
| -
|
| -static PRStatus ExpandMonitorCache(PRUintn new_size_log2)
|
| -{
|
| - MonitorCacheEntry **old_hash_buckets, *p;
|
| - PRUintn i, entries, old_num_hash_buckets, added;
|
| - MonitorCacheEntry **new_hash_buckets;
|
| - MonitorCacheEntryBlock *new_block;
|
| -
|
| - entries = 1L << new_size_log2;
|
| -
|
| - /*
|
| - ** Expand the monitor-cache-entry free list
|
| - */
|
| - new_block = (MonitorCacheEntryBlock*)
|
| - PR_CALLOC(sizeof(MonitorCacheEntryBlock)
|
| - + (entries - 1) * sizeof(MonitorCacheEntry));
|
| - if (NULL == new_block) return PR_FAILURE;
|
| -
|
| - /*
|
| - ** Allocate system monitors for the new monitor cache entries. If we
|
| - ** run out of system monitors, break out of the loop.
|
| - */
|
| - for (i = 0, p = new_block->entries; i < entries; i++, p++) {
|
| - p->mon = PR_NewMonitor();
|
| - if (!p->mon)
|
| - break;
|
| - }
|
| - added = i;
|
| - if (added != entries) {
|
| - MonitorCacheEntryBlock *realloc_block;
|
| -
|
| - if (added == 0) {
|
| - /* Totally out of system monitors. Lossage abounds */
|
| - PR_DELETE(new_block);
|
| - return PR_FAILURE;
|
| - }
|
| -
|
| - /*
|
| - ** We were able to allocate some of the system monitors. Use
|
| - ** realloc to shrink down the new_block memory. If that fails,
|
| - ** carry on with the too-large new_block.
|
| - */
|
| - realloc_block = (MonitorCacheEntryBlock*)
|
| - PR_REALLOC(new_block, sizeof(MonitorCacheEntryBlock)
|
| - + (added - 1) * sizeof(MonitorCacheEntry));
|
| - if (realloc_block)
|
| - new_block = realloc_block;
|
| - }
|
| -
|
| - /*
|
| - ** Now that we have allocated all of the system monitors, build up
|
| - ** the new free list. We can just update the free_list because we own
|
| - ** the mcache-lock and we aren't calling anyone who might want to use
|
| - ** it.
|
| - */
|
| - for (i = 0, p = new_block->entries; i < added - 1; i++, p++)
|
| - p->next = p + 1;
|
| - p->next = free_entries;
|
| - free_entries = new_block->entries;
|
| - num_free_entries += added;
|
| - new_block->next = mcache_blocks;
|
| - mcache_blocks = new_block;
|
| -
|
| - /* Try to expand the hash table */
|
| - new_hash_buckets = (MonitorCacheEntry**)
|
| - PR_CALLOC(entries * sizeof(MonitorCacheEntry*));
|
| - if (NULL == new_hash_buckets) {
|
| - /*
|
| - ** Partial lossage. In this situation we don't get any more hash
|
| - ** buckets, which just means that the table lookups will take
|
| - ** longer. This is bad, but not fatal
|
| - */
|
| - PR_LOG(_pr_cmon_lm, PR_LOG_WARNING,
|
| - ("unable to grow monitor cache hash buckets"));
|
| - return PR_SUCCESS;
|
| - }
|
| -
|
| - /*
|
| - ** Compute new hash mask value. This value is used to mask an address
|
| - ** until it's bits are in the right spot for indexing into the hash
|
| - ** table.
|
| - */
|
| - hash_mask = entries - 1;
|
| -
|
| - /*
|
| - ** Expand the hash table. We have to rehash everything in the old
|
| - ** table into the new table.
|
| - */
|
| - old_hash_buckets = hash_buckets;
|
| - old_num_hash_buckets = num_hash_buckets;
|
| - for (i = 0; i < old_num_hash_buckets; i++) {
|
| - p = old_hash_buckets[i];
|
| - while (p) {
|
| - MonitorCacheEntry *next = p->next;
|
| -
|
| - /* Hash based on new table size, and then put p in the new table */
|
| - PRUintn hash = HASH(p->address);
|
| - p->next = new_hash_buckets[hash];
|
| - new_hash_buckets[hash] = p;
|
| -
|
| - p = next;
|
| - }
|
| - }
|
| -
|
| - /*
|
| - ** Switch over to new hash table and THEN call free of the old
|
| - ** table. Since free might re-enter _pr_mcache_lock, things would
|
| - ** break terribly if it used the old hash table.
|
| - */
|
| - hash_buckets = new_hash_buckets;
|
| - num_hash_buckets = entries;
|
| - num_hash_buckets_log2 = new_size_log2;
|
| - PR_DELETE(old_hash_buckets);
|
| -
|
| - PR_LOG(_pr_cmon_lm, PR_LOG_NOTICE,
|
| - ("expanded monitor cache to %d (buckets %d)",
|
| - num_free_entries, entries));
|
| -
|
| - return PR_SUCCESS;
|
| -} /* ExpandMonitorCache */
|
| -
|
| -/*
|
| -** Lookup a monitor cache entry by address. Return a pointer to the
|
| -** pointer to the monitor cache entry on success, null on failure.
|
| -*/
|
| -static MonitorCacheEntry **LookupMonitorCacheEntry(void *address)
|
| -{
|
| - PRUintn hash;
|
| - MonitorCacheEntry **pp, *p;
|
| -
|
| - hash = HASH(address);
|
| - pp = hash_buckets + hash;
|
| - while ((p = *pp) != 0) {
|
| - if (p->address == address) {
|
| - if (p->cacheEntryCount > 0)
|
| - return pp;
|
| - return NULL;
|
| - }
|
| - pp = &p->next;
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -/*
|
| -** Try to create a new cached monitor. If it's already in the cache,
|
| -** great - return it. Otherwise get a new free cache entry and set it
|
| -** up. If the cache free space is getting low, expand the cache.
|
| -*/
|
| -static PRMonitor *CreateMonitor(void *address)
|
| -{
|
| - PRUintn hash;
|
| - MonitorCacheEntry **pp, *p;
|
| -
|
| - hash = HASH(address);
|
| - pp = hash_buckets + hash;
|
| - while ((p = *pp) != 0) {
|
| - if (p->address == address) goto gotit;
|
| -
|
| - pp = &p->next;
|
| - }
|
| -
|
| - /* Expand the monitor cache if we have run out of free slots in the table */
|
| - if (num_free_entries < FREE_THRESHOLD) {
|
| - /* Expand monitor cache */
|
| -
|
| - /*
|
| - ** This function is called with the lock held. So what's the 'expanding'
|
| - ** boolean all about? Seems a bit redundant.
|
| - */
|
| - if (!expanding) {
|
| - PRStatus rv;
|
| -
|
| - expanding = PR_TRUE;
|
| - rv = ExpandMonitorCache(num_hash_buckets_log2 + 1);
|
| - expanding = PR_FALSE;
|
| - if (PR_FAILURE == rv) return NULL;
|
| -
|
| - /* redo the hash because it'll be different now */
|
| - hash = HASH(address);
|
| - } else {
|
| - /*
|
| - ** We are in process of expanding and we need a cache
|
| - ** monitor. Make sure we have enough!
|
| - */
|
| - PR_ASSERT(num_free_entries > 0);
|
| - }
|
| - }
|
| -
|
| - /* Make a new monitor */
|
| - p = free_entries;
|
| - free_entries = p->next;
|
| - num_free_entries--;
|
| - if (OnMonitorRecycle && p->address)
|
| - OnMonitorRecycle(p->address);
|
| - p->address = address;
|
| - p->next = hash_buckets[hash];
|
| - hash_buckets[hash] = p;
|
| - PR_ASSERT(p->cacheEntryCount == 0);
|
| -
|
| - gotit:
|
| - p->cacheEntryCount++;
|
| - return p->mon;
|
| -}
|
| -
|
| -/*
|
| -** Initialize the monitor cache
|
| -*/
|
| -void _PR_InitCMon(void)
|
| -{
|
| - _PR_NEW_LOCK_MCACHE();
|
| - ExpandMonitorCache(3);
|
| -}
|
| -
|
| -/*
|
| -** Destroy the monitor cache
|
| -*/
|
| -void _PR_CleanupCMon(void)
|
| -{
|
| - _PR_DESTROY_LOCK_MCACHE();
|
| -
|
| - while (free_entries) {
|
| - PR_DestroyMonitor(free_entries->mon);
|
| - free_entries = free_entries->next;
|
| - }
|
| - num_free_entries = 0;
|
| -
|
| - while (mcache_blocks) {
|
| - MonitorCacheEntryBlock *block;
|
| -
|
| - block = mcache_blocks;
|
| - mcache_blocks = block->next;
|
| - PR_DELETE(block);
|
| - }
|
| -
|
| - PR_DELETE(hash_buckets);
|
| - hash_mask = 0;
|
| - num_hash_buckets = 0;
|
| - num_hash_buckets_log2 = 0;
|
| -
|
| - expanding = PR_FALSE;
|
| - OnMonitorRecycle = NULL;
|
| -}
|
| -
|
| -/*
|
| -** Create monitor for address. Don't enter the monitor while we have the
|
| -** mcache locked because we might block!
|
| -*/
|
| -PR_IMPLEMENT(PRMonitor*) PR_CEnterMonitor(void *address)
|
| -{
|
| - PRMonitor *mon;
|
| -
|
| - if (!_pr_initialized) _PR_ImplicitInitialization();
|
| -
|
| - _PR_LOCK_MCACHE();
|
| - mon = CreateMonitor(address);
|
| - _PR_UNLOCK_MCACHE();
|
| -
|
| - if (!mon) return NULL;
|
| -
|
| - PR_EnterMonitor(mon);
|
| - return mon;
|
| -}
|
| -
|
| -PR_IMPLEMENT(PRStatus) PR_CExitMonitor(void *address)
|
| -{
|
| - MonitorCacheEntry **pp, *p;
|
| - PRStatus status = PR_SUCCESS;
|
| -
|
| - _PR_LOCK_MCACHE();
|
| - pp = LookupMonitorCacheEntry(address);
|
| - if (pp != NULL) {
|
| - p = *pp;
|
| - if (--p->cacheEntryCount == 0) {
|
| - /*
|
| - ** Nobody is using the system monitor. Put it on the cached free
|
| - ** list. We are safe from somebody trying to use it because we
|
| - ** have the mcache locked.
|
| - */
|
| - p->address = 0; /* defensive move */
|
| - *pp = p->next; /* unlink from hash_buckets */
|
| - p->next = free_entries; /* link into free list */
|
| - free_entries = p;
|
| - num_free_entries++; /* count it as free */
|
| - }
|
| - status = PR_ExitMonitor(p->mon);
|
| - } else {
|
| - status = PR_FAILURE;
|
| - }
|
| - _PR_UNLOCK_MCACHE();
|
| -
|
| - return status;
|
| -}
|
| -
|
| -PR_IMPLEMENT(PRStatus) PR_CWait(void *address, PRIntervalTime ticks)
|
| -{
|
| - MonitorCacheEntry **pp;
|
| - PRMonitor *mon;
|
| -
|
| - _PR_LOCK_MCACHE();
|
| - pp = LookupMonitorCacheEntry(address);
|
| - mon = pp ? ((*pp)->mon) : NULL;
|
| - _PR_UNLOCK_MCACHE();
|
| -
|
| - if (mon == NULL)
|
| - return PR_FAILURE;
|
| - return PR_Wait(mon, ticks);
|
| -}
|
| -
|
| -PR_IMPLEMENT(PRStatus) PR_CNotify(void *address)
|
| -{
|
| - MonitorCacheEntry **pp;
|
| - PRMonitor *mon;
|
| -
|
| - _PR_LOCK_MCACHE();
|
| - pp = LookupMonitorCacheEntry(address);
|
| - mon = pp ? ((*pp)->mon) : NULL;
|
| - _PR_UNLOCK_MCACHE();
|
| -
|
| - if (mon == NULL)
|
| - return PR_FAILURE;
|
| - return PR_Notify(mon);
|
| -}
|
| -
|
| -PR_IMPLEMENT(PRStatus) PR_CNotifyAll(void *address)
|
| -{
|
| - MonitorCacheEntry **pp;
|
| - PRMonitor *mon;
|
| -
|
| - _PR_LOCK_MCACHE();
|
| - pp = LookupMonitorCacheEntry(address);
|
| - mon = pp ? ((*pp)->mon) : NULL;
|
| - _PR_UNLOCK_MCACHE();
|
| -
|
| - if (mon == NULL)
|
| - return PR_FAILURE;
|
| - return PR_NotifyAll(mon);
|
| -}
|
| -
|
| -PR_IMPLEMENT(void)
|
| -PR_CSetOnMonitorRecycle(void (*callback)(void *address))
|
| -{
|
| - OnMonitorRecycle = callback;
|
| -}
|
|
|