Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
prcmon.c File Reference
#include "primpl.h"
#include <stdlib.h>
#include <stddef.h>

Go to the source code of this file.

Classes

struct  MonitorCacheEntryStr

Defines

#define _PR_NEW_LOCK_MCACHE()   (_pr_mcacheLock = PR_NewLock())
#define _PR_LOCK_MCACHE()   PR_Lock(_pr_mcacheLock)
#define _PR_UNLOCK_MCACHE()   PR_Unlock(_pr_mcacheLock)
#define HASH(address)
#define FREE_THRESHOLD   5

Typedefs

typedef struct MonitorCacheEntryStr

Functions

static PRStatus ExpandMonitorCache (PRUintn new_size_log2)
static MonitorCacheEntry ** LookupMonitorCacheEntry (void *address)
static PRMonitorCreateMonitor (void *address)
void _PR_InitCMon (void)
 PR_IMPLEMENT (PRMonitor *)
 PR_IMPLEMENT (PRStatus)
 PR_CSetOnMonitorRecycle (void(*callback)(void *address))

Variables

PRLock_pr_mcacheLock
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
int _pr_mcache_ready
static void(* OnMonitorRecycle )(void *address)

Class Documentation

struct MonitorCacheEntryStr

Definition at line 65 of file prcmon.c.

Collaboration diagram for MonitorCacheEntryStr:
Class Members
void * address
long cacheEntryCount
PRMonitor * mon
MonitorCacheEntry * next

Define Documentation

Definition at line 56 of file prcmon.c.

Definition at line 55 of file prcmon.c.

Definition at line 57 of file prcmon.c.

Definition at line 99 of file prcmon.c.

Value:
((PRUint32) ( ((PRUptrdiff)(address) >> 2) ^    \
                  ((PRUptrdiff)(address) >> 10) )   \
     & hash_mask)

Definition at line 83 of file prcmon.c.


Typedef Documentation

typedef struct MonitorCacheEntryStr

Definition at line 63 of file prcmon.c.


Function Documentation

Definition at line 304 of file prcmon.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static PRMonitor* CreateMonitor ( void address) [static]

Definition at line 245 of file prcmon.c.

{
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus ExpandMonitorCache ( PRUintn  new_size_log2) [static]

Definition at line 101 of file prcmon.c.

{
    MonitorCacheEntry **old_hash_buckets, *p;
    PRUintn i, entries, old_num_hash_buckets, added;
    MonitorCacheEntry **new_hash_buckets, *new_entries;

    entries = 1L << new_size_log2;

    /*
    ** Expand the monitor-cache-entry free list
    */
    new_entries = (MonitorCacheEntry*)
        PR_CALLOC(entries * sizeof(MonitorCacheEntry));
    if (NULL == new_entries) 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, added = 0, p = new_entries; i < entries; i++, p++, added++) {
        p->mon = PR_NewMonitor();
        if (!p->mon)
            break;
    }
    if (added != entries) {
        if (added == 0) {
            /* Totally out of system monitors. Lossage abounds */
            PR_DELETE(new_entries);
            return PR_FAILURE;
        }

        /*
        ** We were able to allocate some of the system monitors. Use
        ** realloc to shrink down the new_entries memory
        */
        p = (MonitorCacheEntry*)
            PR_REALLOC(new_entries, added * sizeof(MonitorCacheEntry));
        if (p == 0) {
            /*
            ** Total lossage. We just leaked a bunch of system monitors
            ** all over the floor. This should never ever happen.
            */
            PR_ASSERT(p != 0);
            return PR_FAILURE;
        }
    }

    /*
    ** 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_entries; i < added - 1; i++, p++)
        p->next = p + 1;
    p->next = free_entries;
    free_entries = new_entries;
    num_free_entries += added;

    /* 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 */

Here is the call graph for this function:

Here is the caller graph for this function:

static MonitorCacheEntry** LookupMonitorCacheEntry ( void address) [static]

Definition at line 222 of file prcmon.c.

{
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 407 of file prcmon.c.

Definition at line 315 of file prcmon.c.

Here is the call graph for this function:

Definition at line 331 of file prcmon.c.

{
    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;
}

Here is the call graph for this function:


Variable Documentation

Definition at line 79 of file prcmon.c.

Definition at line 54 of file prcmon.c.

PRBool expanding [static]

Definition at line 78 of file prcmon.c.

MonitorCacheEntry* free_entries [static]

Definition at line 76 of file prcmon.c.

MonitorCacheEntry** hash_buckets [static]

Definition at line 75 of file prcmon.c.

PRUint32 hash_mask [static]

Definition at line 72 of file prcmon.c.

PRUintn num_free_entries [static]

Definition at line 77 of file prcmon.c.

PRUintn num_hash_buckets [static]

Definition at line 73 of file prcmon.c.

PRUintn num_hash_buckets_log2 [static]

Definition at line 74 of file prcmon.c.

Definition at line 81 of file prcmon.c.