Ejemplo n.º 1
0
void
terminateWorkerThreads(void)
{
    int i;

    VLOG(("httpserv: server_thread: waiting on stopping"));
    PZ_Lock(qLock);
    PZ_NotifyAllCondVar(jobQNotEmptyCv);
    PZ_Unlock(qLock);

    /* Wait for worker threads to terminate. */
    for (i = 0; i < maxThreads; ++i) {
        perThread *slot = threads + i;
        if (slot->prThread) {
            PR_JoinThread(slot->prThread);
        }
    }

    /* The worker threads empty the jobQ before they terminate. */
    PZ_Lock(qLock);
    PORT_Assert(threadCount == 0);
    PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ));
    PZ_Unlock(qLock);

    DESTROY_CONDVAR(jobQNotEmptyCv);
    DESTROY_CONDVAR(freeListNotEmptyCv);
    DESTROY_CONDVAR(threadCountChangeCv);

    PR_DestroyLock(lastLoadedCrlLock);
    DESTROY_LOCK(qLock);
    PR_Free(jobTable);
    PR_Free(threads);
}
Ejemplo n.º 2
0
static void
port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
{
    PORTArenaPool *pool = (PORTArenaPool *)arena;
    if (ARENAPOOL_MAGIC == pool->magic ) {
	PZ_Lock(pool->lock);
#ifdef THREADMARK
	{
	    threadmark_mark **pw, *tm;

	    if (PR_GetCurrentThread() != pool->marking_thread ) {
		PZ_Unlock(pool->lock);
		PORT_SetError(SEC_ERROR_NO_MEMORY);
		PORT_Assert(0);
		return /* no error indication available */ ;
	    }

	    pw = &pool->first_mark;
	    while( *pw && (mark != (*pw)->mark) ) {
		pw = &(*pw)->next;
	    }

	    if (! *pw ) {
		/* bad mark */
		PZ_Unlock(pool->lock);
		PORT_SetError(SEC_ERROR_NO_MEMORY);
		PORT_Assert(0);
		return /* no error indication available */ ;
	    }

	    tm = *pw;
	    *pw = (threadmark_mark *)NULL;

	    if (zero) {
		port_ArenaZeroAfterMark(arena, mark);
	    }
	    PL_ARENA_RELEASE(arena, mark);

	    if (! pool->first_mark ) {
		pool->marking_thread = (PRThread *)NULL;
	    }
	}
#else /* THREADMARK */
	if (zero) {
	    port_ArenaZeroAfterMark(arena, mark);
	}
	PL_ARENA_RELEASE(arena, mark);
#endif /* THREADMARK */
	PZ_Unlock(pool->lock);
    } else {
	if (zero) {
	    port_ArenaZeroAfterMark(arena, mark);
	}
	PL_ARENA_RELEASE(arena, mark);
    }
}
Ejemplo n.º 3
0
void *
PORT_ArenaMark(PLArenaPool *arena)
{
    void * result;

    PORTArenaPool *pool = (PORTArenaPool *)arena;
    if (ARENAPOOL_MAGIC == pool->magic ) {
	PZ_Lock(pool->lock);
#ifdef THREADMARK
	{
	  threadmark_mark *tm, **pw;
	  PRThread * currentThread = PR_GetCurrentThread();

	    if (! pool->marking_thread ) {
		/* First mark */
		pool->marking_thread = currentThread;
	    } else if (currentThread != pool->marking_thread ) {
		PZ_Unlock(pool->lock);
		PORT_SetError(SEC_ERROR_NO_MEMORY);
		PORT_Assert(0);
		return NULL;
	    }

	    result = PL_ARENA_MARK(arena);
	    PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
	    if (!tm) {
		PZ_Unlock(pool->lock);
		PORT_SetError(SEC_ERROR_NO_MEMORY);
		return NULL;
	    }

	    tm->mark = result;
	    tm->next = (threadmark_mark *)NULL;

	    pw = &pool->first_mark;
	    while( *pw ) {
		 pw = &(*pw)->next;
	    }

	    *pw = tm;
	}
#else /* THREADMARK */
	result = PL_ARENA_MARK(arena);
#endif /* THREADMARK */
	PZ_Unlock(pool->lock);
    } else {
	/* a "pure" NSPR arena */
	result = PL_ARENA_MARK(arena);
    }
    return result;
}
NSS_IMPLEMENT void
nssTrustDomain_UnlockCertCache (
  NSSTrustDomain *td
)
{
    PZ_Unlock(td->cache->lock);
}
Ejemplo n.º 5
0
SECStatus
launch_threads(
    startFn    *startFunc,
    PRFileDesc *a,
    PRFileDesc *b,
    int         c,
    PRBool      local)
{
    int i;
    SECStatus rv = SECSuccess;

    /* create the thread management serialization structs */
    qLock               = PZ_NewLock(nssILockSelfServ);
    jobQNotEmptyCv      = PZ_NewCondVar(qLock);
    freeListNotEmptyCv  = PZ_NewCondVar(qLock);
    threadCountChangeCv = PZ_NewCondVar(qLock);

    /* create monitor for crl reload procedure */
    lastLoadedCrlLock   = PR_NewLock();

    /* allocate the array of thread slots */
    threads = PR_Calloc(maxThreads, sizeof(perThread));
    if ( NULL == threads )  {
        fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n");
        return SECFailure;
    }
    /* 5 is a little extra, intended to keep the jobQ from underflowing. 
    ** That is, from going empty while not stopping and clients are still
    ** trying to contact us.
    */
    rv = setupJobs(maxThreads + 5);
    if (rv != SECSuccess)
    	return rv;

    PZ_Lock(qLock);
    for (i = 0; i < maxThreads; ++i) {
    	perThread * slot = threads + i;

	slot->state = rs_running;
	slot->a = a;
	slot->b = b;
	slot->c = c;
	slot->startFunc = startFunc;
	slot->prThread = PR_CreateThread(PR_USER_THREAD, 
			thread_wrapper, slot, PR_PRIORITY_NORMAL, 
                        (PR_TRUE==local)?PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
                        PR_UNJOINABLE_THREAD, 0);
	if (slot->prThread == NULL) {
	    printf("selfserv: Failed to launch thread!\n");
	    slot->state = rs_idle;
	    rv = SECFailure;
	    break;
	} 

	++threadCount;
    }
    PZ_Unlock(qLock); 

    return rv;
}
Ejemplo n.º 6
0
void
nssSlot_ExitMonitor(NSSSlot *slot)
{
    if (slot->lock) {
	PZ_Unlock(slot->lock);
    }
}
Ejemplo n.º 7
0
NSS_IMPLEMENT PRStatus
nssSession_ExitMonitor (
  nssSession *s
)
{
    return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS;
}
Ejemplo n.º 8
0
/*
 * If zero is true, zeroize the arena memory before freeing it.
 */
void
PORT_FreeArena(PLArenaPool *arena, PRBool zero)
{
    PORTArenaPool *pool = (PORTArenaPool *)arena;
    PRLock *lock = (PRLock *)0;
    size_t len = sizeof *arena;

    if (!pool)
        return;
    if (ARENAPOOL_MAGIC == pool->magic) {
        len = sizeof *pool;
        lock = pool->lock;
        PZ_Lock(lock);
    }
    if (zero) {
        PL_ClearArenaPool(arena, 0);
    }
    (void)PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList);
    if (useFreeList) {
        PL_FreeArenaPool(arena);
    } else {
        PL_FinishArenaPool(arena);
    }
    PORT_ZFree(arena, len);
    if (lock) {
        PZ_Unlock(lock);
        PZ_DestroyLock(lock);
    }
}
Ejemplo n.º 9
0
/*
 * nssHash_Add
 *
 */
NSS_IMPLEMENT PRStatus
nssHash_Add
(
  nssHash *hash,
  const void *key,
  const void *value
)
{
  PRStatus error = PR_FAILURE;
  PLHashEntry *he;

  PZ_Lock(hash->mutex);
  
  he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
  if( (PLHashEntry *)NULL == he ) {
    nss_SetError(NSS_ERROR_NO_MEMORY);
  } else if (he->value != value) {
    nss_SetError(NSS_ERROR_HASH_COLLISION);
  } else {
    hash->count++;
    error = PR_SUCCESS;
  }

  (void)PZ_Unlock(hash->mutex);

  return error;
}
Ejemplo n.º 10
0
int
jobLoop(PRFileDesc *a, PRFileDesc *b, int c)
{
    PRCList *myLink = 0;
    JOB *myJob;

    PZ_Lock(qLock);
    do {
        myLink = 0;
        while (PR_CLIST_IS_EMPTY(&jobQ) && !stopping) {
            PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
        }
        if (!PR_CLIST_IS_EMPTY(&jobQ)) {
            myLink = PR_LIST_HEAD(&jobQ);
            PR_REMOVE_AND_INIT_LINK(myLink);
        }
        PZ_Unlock(qLock);
        myJob = (JOB *)myLink;
        /* myJob will be null when stopping is true and jobQ is empty */
        if (!myJob)
            break;
        handle_connection(myJob->tcp_sock, myJob->model_sock,
                          myJob->requestCert);
        PZ_Lock(qLock);
        PR_APPEND_LINK(myLink, &freeJobs);
        PZ_NotifyCondVar(freeListNotEmptyCv);
    } while (PR_TRUE);
    return 0;
}
Ejemplo n.º 11
0
/*
 * If zero is true, zeroize the arena memory before freeing it.
 */
void
PORT_FreeArena(PLArenaPool *arena, PRBool zero)
{
    PORTArenaPool *pool = (PORTArenaPool *)arena;
    PRLock *       lock = (PRLock *)0;
    size_t         len  = sizeof *arena;
    static PRBool  checkedEnv = PR_FALSE;
    static PRBool  doFreeArenaPool = PR_FALSE;

    if (!pool)
    	return;
    if (ARENAPOOL_MAGIC == pool->magic ) {
	len  = sizeof *pool;
	lock = pool->lock;
	PZ_Lock(lock);
    }
    if (!checkedEnv) {
	/* no need for thread protection here */
	doFreeArenaPool = (PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
	checkedEnv = PR_TRUE;
    }
    if (zero) {
	PL_ClearArenaPool(arena, 0);
    }
    if (doFreeArenaPool) {
	PL_FreeArenaPool(arena);
    } else {
	PL_FinishArenaPool(arena);
    }
    PORT_ZFree(arena, len);
    if (lock) {
	PZ_Unlock(lock);
	PZ_DestroyLock(lock);
    }
}
Ejemplo n.º 12
0
/* we can only get here if we've destroyed the module, or some one has
 * erroneously freed a slot that wasn't referenced. */
void
SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) 
{
    PRBool willfree = PR_FALSE;
    if (fromSlot) {
        PORT_Assert(module->refCount == 0);
	PZ_Lock(module->refLock);
	if (module->slotCount-- == 1) {
	    willfree = PR_TRUE;
	}
	PORT_Assert(willfree || (module->slotCount > 0));
	PZ_Unlock(module->refLock);
        if (!willfree) return;
    }

    if (module == pendingModule) {
	pendingModule = NULL;
    }

    if (module->loaded) {
	SECMOD_UnloadModule(module);
    }
    PZ_DestroyLock(module->refLock);
    PORT_FreeArena(module->arena,PR_FALSE);
    secmod_PrivateModuleCount--;
}
Ejemplo n.º 13
0
/*
 * make a new reference to a module so It doesn't go away on us
 */
SECMODModule *
SECMOD_ReferenceModule(SECMODModule *module) 
{
    PZ_Lock(module->refLock);
    PORT_Assert(module->refCount > 0);

    module->refCount++;
    PZ_Unlock(module->refLock);
    return module;
}
Ejemplo n.º 14
0
void
PK11_ExitContextMonitor(PK11Context *cx) {
    /* if we own the session and our slot is ThreadSafe, only monitor
     * the Context */
    if ((cx->ownSession) && (cx->slot->isThreadSafe)) {
        /* Should this use monitors instead? */
        PZ_Unlock(cx->sessionLock);
    } else {
        PK11_ExitSlotMonitor(cx->slot);
    }
}
Ejemplo n.º 15
0
NSS_IMPLEMENT void
nssCertificateStore_DumpStoreInfo (
  nssCertificateStore *store,
  void (* cert_dump_iter)(const void *, void *, void *),
  void *arg
)
{
    PZ_Lock(store->lock);
    nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg);
    PZ_Unlock(store->lock);
}
Ejemplo n.º 16
0
void
PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
{
#ifdef THREADMARK
    PORTArenaPool *pool = (PORTArenaPool *)arena;
    if (ARENAPOOL_MAGIC == pool->magic ) {
	threadmark_mark **pw, *tm;

	PZ_Lock(pool->lock);

	if (PR_GetCurrentThread() != pool->marking_thread ) {
	    PZ_Unlock(pool->lock);
	    PORT_SetError(SEC_ERROR_NO_MEMORY);
	    PORT_Assert(0);
	    return /* no error indication available */ ;
	}

	pw = &pool->first_mark;
	while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) {
	    pw = &(*pw)->next;
	}

	if ((threadmark_mark *)NULL == *pw ) {
	    /* bad mark */
	    PZ_Unlock(pool->lock);
	    PORT_SetError(SEC_ERROR_NO_MEMORY);
	    PORT_Assert(0);
	    return /* no error indication available */ ;
	}

	tm = *pw;
	*pw = (threadmark_mark *)NULL;

	if (! pool->first_mark ) {
	    pool->marking_thread = (PRThread *)NULL;
	}

	PZ_Unlock(pool->lock);
    }
#endif /* THREADMARK */
}
Ejemplo n.º 17
0
void *
PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
{
    void *p = NULL;

    PORTArenaPool *pool = (PORTArenaPool *)arena;

    if (size <= 0) {
	size = 1;
    }

    if (size > MAX_SIZE) {
	/* you lose. */
    } else 
    /* Is it one of ours?  Assume so and check the magic */
    if (ARENAPOOL_MAGIC == pool->magic ) {
	PZ_Lock(pool->lock);
#ifdef THREADMARK
        /* Most likely one of ours.  Is there a thread id? */
	if (pool->marking_thread  &&
	    pool->marking_thread != PR_GetCurrentThread() ) {
	    /* Another thread holds a mark in this arena */
	    PZ_Unlock(pool->lock);
	    PORT_SetError(SEC_ERROR_NO_MEMORY);
	    PORT_Assert(0);
	    return NULL;
	} /* tid != null */
#endif /* THREADMARK */
	PL_ARENA_ALLOCATE(p, arena, size);
	PZ_Unlock(pool->lock);
    } else {
	PL_ARENA_ALLOCATE(p, arena, size);
    }

    if (!p) {
	++port_allocFailures;
	PORT_SetError(SEC_ERROR_NO_MEMORY);
    }

    return(p);
}
Ejemplo n.º 18
0
/*
 * stub files for legacy db's to be able to encrypt and decrypt
 * various keys and attributes.
 */
static SECStatus
sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) 
{
    SFTKDBHandle *handle = sdb->app_private;
    SECStatus rv;
    SECItem *oldKey = NULL;

    if (handle == NULL) {
	return SECFailure;
    }

    /* if we aren't th handle, try the other handle */
    oldKey = handle->oldKey;
    if (handle->type != SFTK_KEYDB_TYPE) {
	handle = handle->peerDB;
    }

    /* not a key handle */
    if (handle == NULL || handle->passwordLock == NULL) {
	return SECFailure;
    }

    PZ_Lock(handle->passwordLock);
    if (handle->passwordKey.data == NULL) {
	PZ_Unlock(handle->passwordLock);
	/* PORT_SetError */
	return SECFailure;
    }

#if defined(PKCS11_DB_DATA_KEY_USE_KEYSTORE) || defined(PKCS11_DB_DATA_KEY_USE_KEYCHAIN)
	rv = sftkdb_DecryptAttributeByDbDataKey(
			cipherText, plainText);
	
#else
    rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey,
		cipherText, plainText);
#endif
    PZ_Unlock(handle->passwordLock);

    return rv;
}
Ejemplo n.º 19
0
NSS_IMPLEMENT void
nssCertificateStore_Unlock (
  nssCertificateStore *store, nssCertificateStoreTrace* in,
  nssCertificateStoreTrace* out
)
{
#ifdef DEBUG
    PORT_Assert(in);
    PORT_Assert(out);
    out->store = store;
    out->lock = store->lock;
    out->unlocked = PR_TRUE;

    PORT_Assert(in->store == out->store);
    PORT_Assert(in->lock == out->lock);
    PORT_Assert(in->locked);

    PZ_Unlock(out->lock);
#else
    PZ_Unlock(store->lock);
#endif
}
Ejemplo n.º 20
0
void
thread_wrapper(void *arg)
{
    perThread *slot = (perThread *)arg;

    slot->rv = (*slot->startFunc)(slot->a, slot->b, slot->c);

    /* notify the thread exit handler. */
    PZ_Lock(qLock);
    slot->state = rs_zombie;
    --threadCount;
    PZ_NotifyAllCondVar(threadCountChangeCv);
    PZ_Unlock(qLock);
}
Ejemplo n.º 21
0
/*
 * If zero is true, zeroize the arena memory before freeing it.
 */
void
PORT_FreeArena(PLArenaPool *arena, PRBool zero)
{
    PORTArenaPool *pool = (PORTArenaPool *)arena;
    PRLock *       lock = (PRLock *)0;
    size_t         len  = sizeof *arena;
    extern const PRVersionDescription * libVersionPoint(void);
    static const PRVersionDescription * pvd;
    static PRBool  doFreeArenaPool = PR_FALSE;

    if (ARENAPOOL_MAGIC == pool->magic ) {
	len  = sizeof *pool;
	lock = pool->lock;
	PZ_Lock(lock);
    }
    if (!pvd) {
	/* Each of NSPR's DLLs has a function libVersionPoint().
	** We could do a lot of extra work to be sure we're calling the
	** one in the DLL that holds PR_FreeArenaPool, but instead we
	** rely on the fact that ALL NSPR DLLs in the same directory
	** must be from the same release, and we call which ever one we get. 
	*/
	/* no need for thread protection here */
	pvd = libVersionPoint();
	if ((pvd->vMajor > 4) || 
	    (pvd->vMajor == 4 && pvd->vMinor > 1) ||
	    (pvd->vMajor == 4 && pvd->vMinor == 1 && pvd->vPatch >= 1)) {
	    const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
	    if (!ev) doFreeArenaPool = PR_TRUE;
	}
    }
    if (zero) {
	PLArena *a;
	for (a = arena->first.next; a; a = a->next) {
	    PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
	    memset((void *)a->base, 0, a->avail - a->base);
	}
    }
    if (doFreeArenaPool) {
	PL_FreeArenaPool(arena);
    } else {
	PL_FinishArenaPool(arena);
    }
    PORT_ZFree(arena, len);
    if (lock) {
	PZ_Unlock(lock);
	PZ_DestroyLock(lock);
    }
}
Ejemplo n.º 22
0
NSS_IMPLEMENT NSSCertificate *
nssCertificateStore_FindCertificateByIssuerAndSerialNumber (
  nssCertificateStore *store,
  NSSDER *issuer,
  NSSDER *serial
)
{
    NSSCertificate *rvCert = NULL;

    PZ_Lock(store->lock);
    rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked (
                           store, issuer, serial);
    PZ_Unlock(store->lock);
    return rvCert;
}
Ejemplo n.º 23
0
/*
 * nssHash_Count
 *
 */
NSS_IMPLEMENT PRUint32
nssHash_Count
(
  nssHash *hash
)
{
  PRUint32 count;

  PZ_Lock(hash->mutex);

  count = hash->count;

  (void)PZ_Unlock(hash->mutex);

  return count;
}
Ejemplo n.º 24
0
/*
 * nssHash_Lookup
 *
 */
NSS_IMPLEMENT void *
nssHash_Lookup
(
  nssHash *hash,
  const void *it
)
{
  void *rv;

  PZ_Lock(hash->mutex);

  rv = PL_HashTableLookup(hash->plHashTable, it);

  (void)PZ_Unlock(hash->mutex);

  return rv;
}
Ejemplo n.º 25
0
void *
PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
{
    PORTArenaPool *pool = (PORTArenaPool *)arena;
    PORT_Assert(newsize >= oldsize);
    
    if (ARENAPOOL_MAGIC == pool->magic ) {
	PZ_Lock(pool->lock);
	/* Do we do a THREADMARK check here? */
	PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
	PZ_Unlock(pool->lock);
    } else {
	PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
    }
    
    return(ptr);
}
Ejemplo n.º 26
0
NSS_IMPLEMENT nssSMIMEProfile *
nssCertificateStore_FindSMIMEProfileForCertificate (
  nssCertificateStore *store,
  NSSCertificate *cert
)
{
    certificate_hash_entry *entry;
    nssSMIMEProfile *rvProfile = NULL;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
                              nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry && entry->profile) {
	rvProfile = nssSMIMEProfile_AddRef(entry->profile);
    }
    PZ_Unlock(store->lock);
    return rvProfile;
}
Ejemplo n.º 27
0
NSS_IMPLEMENT NSSTrust *
nssCertificateStore_FindTrustForCertificate (
  nssCertificateStore *store,
  NSSCertificate *cert
)
{
    certificate_hash_entry *entry;
    NSSTrust *rvTrust = NULL;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
                              nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry && entry->trust) {
	rvTrust = nssTrust_AddRef(entry->trust);
    }
    PZ_Unlock(store->lock);
    return rvTrust;
}
Ejemplo n.º 28
0
NSS_EXTERN PRStatus
nssCertificateStore_AddSMIMEProfile (
  nssCertificateStore *store,
  nssSMIMEProfile *profile
)
{
    NSSCertificate *cert;
    certificate_hash_entry *entry;
    cert = profile->certificate;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
                              nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry) {
	entry->profile = nssSMIMEProfile_AddRef(profile);
    }
    PZ_Unlock(store->lock);
    return (entry) ? PR_SUCCESS : PR_FAILURE;
}
Ejemplo n.º 29
0
NSS_EXTERN PRStatus
nssCertificateStore_AddTrust (
  nssCertificateStore *store,
  NSSTrust *trust
)
{
    NSSCertificate *cert;
    certificate_hash_entry *entry;
    cert = trust->certificate;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
                              nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry) {
	entry->trust = nssTrust_AddRef(trust);
    }
    PZ_Unlock(store->lock);
    return (entry) ? PR_SUCCESS : PR_FAILURE;
}
Ejemplo n.º 30
0
/* destroy an existing module */
void
SECMOD_DestroyModule(SECMODModule *module) 
{
    PRBool willfree = PR_FALSE;
    int slotCount;
    int i;

    PZ_Lock(module->refLock);
    if (module->refCount-- == 1) {
	willfree = PR_TRUE;
    }
    PORT_Assert(willfree || (module->refCount > 0));
    PZ_Unlock(module->refLock);

    if (!willfree) {
	return;
    }
   
    if (module->parent != NULL) {
	SECMODModule *parent = module->parent;
	/* paranoia, don't loop forever if the modules are looped */
	module->parent = NULL;
	SECMOD_DestroyModule(parent);
    }

    /* slots can't really disappear until our module starts freeing them,
     * so this check is safe */
    slotCount = module->slotCount;
    if (slotCount == 0) {
	SECMOD_SlotDestroyModule(module,PR_FALSE);
	return;
    }

    /* now free all out slots, when they are done, they will cause the
     * module to disappear altogether */
    for (i=0 ; i < slotCount; i++) {
	if (!module->slots[i]->disabled) {
		PK11_ClearSlotList(module->slots[i]);
	}
	PK11_FreeSlot(module->slots[i]);
    }
    /* WARNING: once the last slot has been freed is it possible (even likely)
     * that module is no more... touching it now is a good way to go south */
}