NSFC_RecordEntryHit(NSFCCache cache, NSFCEntry entry) { PR_ASSERT(entry->refcnt >= 1); entry->hitcnt++; /* * If existing entries can be recycled for new files, indicate that * this entry is active. */ if (cache->cfg.replaceFiles == PR_TRUE) { /* Update the hit list order if this entry is in the hit list */ PR_Lock(cache->hitLock); if (PR_LIST_HEAD(&entry->hit_list) != PR_LIST_TAIL(&entry->hit_list)) { if (cache->cfg.hitOrder == PR_TRUE) { /* * If this entry is not at the head of the hit list, * move it ahead of all entries with the same hitcnt. */ PRCList *prev; NSFCEntryImpl *pnep; for (prev = PR_PREV_LINK(&entry->hit_list); prev != &cache->hit_list; prev = PR_PREV_LINK(prev)) { pnep = NSFCENTRYIMPL(prev); if (pnep->hitcnt > entry->hitcnt) { break; /* Our spot in the list */ } } /* Move the element up if necessary */ if (prev != PR_PREV_LINK(&entry->hit_list)) { PR_REMOVE_LINK(&entry->hit_list); PR_INSERT_AFTER(&entry->hit_list, prev); } } else { /* Ignore hitcnt, keep list in strict MRU to LRU order */ if (&entry->hit_list != PR_LIST_HEAD(&cache->hit_list)) { PR_REMOVE_LINK(&entry->hit_list); PR_INSERT_LINK(&entry->hit_list, &cache->hit_list); } } } PR_Unlock(cache->hitLock); } }
nsProfileLock& nsProfileLock::operator=(nsProfileLock& rhs) { Unlock(); mHaveLock = rhs.mHaveLock; rhs.mHaveLock = false; #if defined (XP_WIN) mLockFileHandle = rhs.mLockFileHandle; rhs.mLockFileHandle = INVALID_HANDLE_VALUE; #elif defined (XP_OS2) mLockFileHandle = rhs.mLockFileHandle; rhs.mLockFileHandle = -1; #elif defined (XP_UNIX) mLockFileDesc = rhs.mLockFileDesc; rhs.mLockFileDesc = -1; mPidLockFileName = rhs.mPidLockFileName; rhs.mPidLockFileName = nullptr; if (mPidLockFileName) { // rhs had a symlink lock, therefore it was on the list. PR_REMOVE_LINK(&rhs); PR_APPEND_LINK(this, &mPidLockList); } #endif return *this; }
static void RemoveSource( JSDContext* jsdc, JSDSourceText* jsdsrc ) { PR_REMOVE_LINK(&jsdsrc->links); ClearText( jsdc, jsdsrc ); DestroySource( jsdc, jsdsrc ); }
/* cleanup at shutdown */ void RSA_Cleanup(void) { blindingParams * bp = NULL; if (!coBPInit.initialized) return; while (!PR_CLIST_IS_EMPTY(&blindingParamsList.head)) { RSABlindingParams *rsabp = (RSABlindingParams *)PR_LIST_HEAD(&blindingParamsList.head); PR_REMOVE_LINK(&rsabp->link); /* clear parameters cache */ while (rsabp->bp != NULL) { bp = rsabp->bp; rsabp->bp = rsabp->bp->next; mp_clear( &bp->f ); mp_clear( &bp->g ); } SECITEM_FreeItem(&rsabp->modulus,PR_FALSE); PORT_Free(rsabp); } if (blindingParamsList.cVar) { PR_DestroyCondVar(blindingParamsList.cVar); blindingParamsList.cVar = NULL; } if (blindingParamsList.lock) { SKIP_AFTER_FORK(PZ_DestroyLock(blindingParamsList.lock)); blindingParamsList.lock = NULL; } coBPInit.initialized = 0; coBPInit.inProgress = 0; coBPInit.status = 0; }
static void MoveSourceToRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc ) { ClearText(jsdc, jsdsrc); PR_REMOVE_LINK(&jsdsrc->links); PR_INSERT_LINK(&jsdsrc->links, &jsd_removed_source_list); }
/* cleanup at shutdown */ void RSA_Cleanup(void) { if (!coBPInit.initialized) return; while (!PR_CLIST_IS_EMPTY(&blindingParamsList.head)) { struct RSABlindingParamsStr * rsabp = (struct RSABlindingParamsStr *) PR_LIST_HEAD(&blindingParamsList.head); PR_REMOVE_LINK(&rsabp->link); mp_clear(&rsabp->f); mp_clear(&rsabp->g); SECITEM_FreeItem(&rsabp->modulus,PR_FALSE); PORT_Free(rsabp); } if (blindingParamsList.lock) { PZ_DestroyLock(blindingParamsList.lock); blindingParamsList.lock = NULL; } coBPInit.initialized = 0; coBPInit.inProgress = 0; coBPInit.status = 0; }
nsresult nsPACMan::AsyncGetProxyForURI(nsIURI *uri, nsPACManCallback *callback) { NS_ENSURE_STATE(!mShutdown); MaybeReloadPAC(); PendingPACQuery *query = new PendingPACQuery(this, uri, callback); if (!query) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(query); PR_APPEND_LINK(query, &mPendingQ); // If we're waiting for the PAC file to load, then delay starting the query. // See OnStreamComplete. However, if this is the PAC URI then query right // away since we know the result will be DIRECT. We could shortcut some code // in this case by issuing the callback directly from here, but that would // require extra code, so we just go through the usual async code path. int isPACURI = IsPACURI(uri); if (IsLoading() && !isPACURI) return NS_OK; nsresult rv = query->Start(isPACURI ? 0 : nsIDNSService::RESOLVE_SPECULATE); if (rv == NS_ERROR_DNS_LOOKUP_QUEUE_FULL && !isPACURI) { query->OnLookupComplete(NULL, NULL, NS_OK); rv = NS_OK; } else if (NS_FAILED(rv)) { NS_WARNING("failed to start PAC query"); PR_REMOVE_LINK(query); NS_RELEASE(query); } return rv; }
static void _destroyJSDContext(JSDContext* jsdc) { JSD_ASSERT_VALID_CONTEXT(jsdc); JSD_LOCK(); PR_REMOVE_LINK(&jsdc->links); JSD_UNLOCK(); if( jsdc->jscontexts ) { PR_HashTableEnumerateEntries(jsdc->jscontexts, _hash_entry_zapper, NULL); PR_HashTableDestroy(jsdc->jscontexts); } jsdc->inited = JS_FALSE; /* * We should free jsdc here, but we let it leak in case there are any * asynchronous hooks calling into the system using it as a handle * * XXX we also leak the locks */ }
SECStatus SSLExp_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension, SSLExtensionWriter writer, void *writerArg, SSLExtensionHandler handler, void *handlerArg) { sslSocket *ss = ssl_FindSocket(fd); PRCList *cursor; sslCustomExtensionHooks *hook; if (!ss) { return SECFailure; /* Code already set. */ } /* Need to specify both or neither, but not just one. */ if ((writer && !handler) || (!writer && handler)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (ssl_GetExtensionSupport(extension) == ssl_ext_native_only) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (ss->firstHsDone || ((ss->ssl3.hs.ws != idle_handshake) && (ss->ssl3.hs.ws != wait_client_hello))) { PORT_SetError(PR_INVALID_STATE_ERROR); return SECFailure; } /* Remove any old handler. */ for (cursor = PR_NEXT_LINK(&ss->extensionHooks); cursor != &ss->extensionHooks; cursor = PR_NEXT_LINK(cursor)) { hook = (sslCustomExtensionHooks *)cursor; if (hook->type == extension) { PR_REMOVE_LINK(&hook->link); PORT_Free(hook); break; } } if (!writer && !handler) { return SECSuccess; } hook = PORT_ZNew(sslCustomExtensionHooks); if (!hook) { return SECFailure; /* This removed the old one, oh well. */ } hook->type = extension; hook->writer = writer; hook->writerArg = writerArg; hook->handler = handler; hook->handlerArg = handlerArg; PR_APPEND_LINK(&hook->link, &ss->extensionHooks); return SECSuccess; }
void nsPreflightCache::RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal) { CacheEntry* entry; nsCString key; if (GetCacheKey(aURI, aPrincipal, PR_TRUE, key) && mTable.Get(key, &entry)) { PR_REMOVE_LINK(entry); mTable.Remove(key); } if (GetCacheKey(aURI, aPrincipal, PR_FALSE, key) && mTable.Get(key, &entry)) { PR_REMOVE_LINK(entry); mTable.Remove(key); } }
void ssl3_DestroyRemoteExtensions(PRCList *list) { PRCList *cur_p; while (!PR_CLIST_IS_EMPTY(list)) { cur_p = PR_LIST_TAIL(list); PR_REMOVE_LINK(cur_p); PORT_Free(cur_p); } }
void nsScannerBufferList::ReleaseAll() { while (!PR_CLIST_IS_EMPTY(&mBuffers)) { PRCList* node = PR_LIST_HEAD(&mBuffers); PR_REMOVE_LINK(node); //printf(">>> freeing buffer @%p\n", node); free(NS_STATIC_CAST(Buffer*, node)); } }
nsDiskCacheBinding::~nsDiskCacheBinding() { NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "binding deleted while still on list"); if (!PR_CLIST_IS_EMPTY(this)) PR_REMOVE_LINK(this); // XXX why are we still on a list? // sever streamIO/binding link if (mStreamIO) { mStreamIO->ClearBinding(); NS_RELEASE(mStreamIO); } }
PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group) { PRStatus rv = PR_SUCCESS; if (NULL == group) group = mw_state->group; PR_ASSERT(NULL != group); if (NULL != group) { PR_Lock(group->ml); if ((group->waiting_threads == 0) && (group->waiter->count == 0) && PR_CLIST_IS_EMPTY(&group->io_ready)) { group->state = _prmw_stopped; } else { PR_SetError(PR_INVALID_STATE_ERROR, 0); rv = PR_FAILURE; } PR_Unlock(group->ml); if (PR_FAILURE == rv) return rv; PR_Lock(mw_lock); PR_REMOVE_LINK(&group->group_link); PR_Unlock(mw_lock); #ifdef WINNT /* * XXX make sure wait_list is empty and waiter is empty. * These must be checked while holding mdlock. */ _PR_MD_FREE_LOCK(&group->mdlock); #endif PR_DELETE(group->waiter); PR_DELETE(group->polling_list); PR_DestroyCondVar(group->mw_manage); PR_DestroyCondVar(group->new_business); PR_DestroyCondVar(group->io_complete); PR_DestroyCondVar(group->io_taken); PR_DestroyLock(group->ml); if (group == mw_state->group) mw_state->group = NULL; PR_DELETE(group); } else { /* The default wait group is not created yet. */ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); rv = PR_FAILURE; } return rv; } /* PR_DestroyWaitGroup */
void nsScannerBufferList::DiscardUnreferencedPrefix( Buffer* aBuf ) { if (aBuf == Head()) { while (!PR_CLIST_IS_EMPTY(&mBuffers) && !Head()->IsInUse()) { Buffer* buffer = Head(); PR_REMOVE_LINK(buffer); free(buffer); } } }
PR_DestroyTrace( PRTraceHandle handle /* Handle to be destroyed */ ) { RName *rnp = (RName *)handle; QName *qnp = rnp->qName; PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", qnp->name, rnp->name)); /* Lock the Facility */ PR_Lock( traceLock ); /* ** Remove RName from the list of RNames in QName ** and free RName */ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", rnp->name, rnp)); PR_REMOVE_LINK( &rnp->link ); PR_Free( rnp->lock ); PR_DELETE( rnp ); /* ** If this is the last RName within QName ** remove QName from the qNameList and free it */ if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) { PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", qnp->name, qnp)); PR_REMOVE_LINK( &qnp->link ); PR_DELETE( qnp ); } /* Unlock the Facility */ PR_Unlock( traceLock ); return; } /* end PR_DestroyTrace() */
static void TimerManager(void *arg) { PRIntervalTime now; PRIntervalTime timeout; PRCList *head; TimerEvent *timer; PR_Lock(tm_vars.ml); while (1) { if (PR_CLIST_IS_EMPTY(&tm_vars.timer_queue)) { PR_WaitCondVar(tm_vars.new_timer, PR_INTERVAL_NO_TIMEOUT); } else { now = PR_IntervalNow(); head = PR_LIST_HEAD(&tm_vars.timer_queue); timer = TIMER_EVENT_PTR(head); if ((PRInt32) (now - timer->absolute) >= 0) { PR_REMOVE_LINK(head); /* * make its prev and next point to itself so that * it's obvious that it's not on the timer_queue. */ PR_INIT_CLIST(head); PR_ASSERT(2 == timer->ref_count); PR_Unlock(tm_vars.ml); timer->func(timer->arg); PR_Lock(tm_vars.ml); timer->ref_count -= 1; if (0 == timer->ref_count) { PR_NotifyAllCondVar(tm_vars.cancel_timer); } } else { timeout = (PRIntervalTime)(timer->absolute - now); PR_WaitCondVar(tm_vars.new_timer, timeout); } } } PR_Unlock(tm_vars.ml); }
static void ssl_FreeCipherSpec(ssl3CipherSpec *spec) { SSL_TRC(10, ("%d: SSL[-]: Freeing %s spec %d. epoch=%d", SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch)); PR_REMOVE_LINK(&spec->link); /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ if (spec->cipherContext) { PK11_DestroyContext(spec->cipherContext, PR_TRUE); } PK11_FreeSymKey(spec->masterSecret); ssl_DestroyKeyMaterial(&spec->keyMaterial); PORT_ZFree(spec, sizeof(*spec)); }
nsresult nsProfileLock::Unlock(bool aFatalSignal) { nsresult rv = NS_OK; if (mHaveLock) { #if defined (XP_WIN) if (mLockFileHandle != INVALID_HANDLE_VALUE) { CloseHandle(mLockFileHandle); mLockFileHandle = INVALID_HANDLE_VALUE; } #elif defined (XP_OS2) if (mLockFileHandle != -1) { DosClose(mLockFileHandle); mLockFileHandle = -1; } #elif defined (XP_UNIX) if (mPidLockFileName) { PR_REMOVE_LINK(this); (void) unlink(mPidLockFileName); // Only free mPidLockFileName if we're not in the fatal signal // handler. The problem is that a call to free() might be the // cause of this fatal signal. If so, calling free() might cause // us to wait on the malloc implementation's lock. We're already // holding this lock, so we'll deadlock. See bug 522332. if (!aFatalSignal) free(mPidLockFileName); mPidLockFileName = nullptr; } else if (mLockFileDesc != -1) { close(mLockFileDesc); mLockFileDesc = -1; // Don't remove it } #endif mHaveLock = false; } return rv; }
bundleCacheEntry_t * nsStringBundleService::insertIntoCache(nsIStringBundle* aBundle, nsCStringKey* aHashKey) { bundleCacheEntry_t *cacheEntry; if (mBundleMap.Count() < MAX_CACHED_BUNDLES) { // cache not full - create a new entry void *cacheEntryArena; PL_ARENA_ALLOCATE(cacheEntryArena, &mCacheEntryPool, sizeof(bundleCacheEntry_t)); cacheEntry = (bundleCacheEntry_t*)cacheEntryArena; } else { // cache is full // take the last entry in the list, and recycle it. cacheEntry = (bundleCacheEntry_t*)PR_LIST_TAIL(&mBundleCache); // remove it from the hash table and linked list NS_ASSERTION(mBundleMap.Exists(cacheEntry->mHashKey), "Element will not be removed!"); #ifdef DEBUG_alecf NS_WARNING(nsPrintfCString(300, "Booting %s to make room for %s\n", cacheEntry->mHashKey->GetString(), aHashKey->GetString()).get()); #endif mBundleMap.Remove(cacheEntry->mHashKey); PR_REMOVE_LINK((PRCList*)cacheEntry); // free up excess memory recycleEntry(cacheEntry); } // at this point we have a new cacheEntry that doesn't exist // in the hashtable, so set up the cacheEntry cacheEntry->mBundle = aBundle; NS_ADDREF(cacheEntry->mBundle); cacheEntry->mHashKey = (nsCStringKey*)aHashKey->Clone(); // insert the entry into the cache and map, make it the MRU mBundleMap.Put(cacheEntry->mHashKey, cacheEntry); return cacheEntry; }
nsDiskCacheBinding::~nsDiskCacheBinding() { // Grab the cache lock since the binding is stored in nsCacheEntry::mData // and it is released using nsCacheService::ReleaseObject_Locked() which // releases the object outside the cache lock. nsCacheServiceAutoLock lock(LOCK_TELEM(NSDISKCACHEBINDING_DESTRUCTOR)); NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "binding deleted while still on list"); if (!PR_CLIST_IS_EMPTY(this)) PR_REMOVE_LINK(this); // XXX why are we still on a list? // sever streamIO/binding link if (mStreamIO) { if (NS_FAILED(mStreamIO->ClearBinding())) nsCacheService::DoomEntry(mCacheEntry); NS_RELEASE(mStreamIO); } }
/* This finds an existing server cert slot and unlinks it, or it makes a new * server cert slot of the right type. */ static sslServerCert * ssl_FindOrMakeCertType(sslSocket *ss, SSLAuthType authType) { sslServerCert *sc; sslServerCertType certType; certType.authType = authType; /* Setting the named curve to NULL ensures that all EC certificates * are matched when searching for this slot. */ certType.namedCurve = NULL; sc = ssl_FindServerCert(ss, &certType); if (sc) { PR_REMOVE_LINK(&sc->link); return sc; } return ssl_NewServerCert(&certType); }
/* static */ PLDHashOperator nsPreflightCache::RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr<CacheEntry>& aValue, void* aUserData) { PRTime* now = static_cast<PRTime*>(aUserData); aValue->PurgeExpired(*now); if (aValue->mHeaders.IsEmpty() && aValue->mMethods.IsEmpty()) { // Expired, remove from the list as well as the hash table. PR_REMOVE_LINK(aValue); return PL_DHASH_REMOVE; } return PL_DHASH_NEXT; }
void js_DestroyContext(JSContext *cx) { JSRuntime *rt; JSBool rtempty; rt = cx->runtime; PR_ASSERT(JS_IS_RUNTIME_LOCKED(rt)); /* Remove cx from context list first. */ PR_REMOVE_LINK(&cx->links); rtempty = (rt->contextList.next == (PRCList *)&rt->contextList); if (js_InterpreterHooks && js_InterpreterHooks->destroyContext) { /* This is a stub, but in case it removes roots, call it now. */ js_InterpreterHooks->destroyContext(cx); } if (rtempty) { /* No more contexts: clear debugging state to remove GC roots. */ JS_ClearAllTraps(cx); JS_ClearAllWatchPoints(cx); } /* Remove more GC roots in regExpStatics, then collect garbage. */ #if JS_HAS_REGEXPS js_FreeRegExpStatics(cx, &cx->regExpStatics); #endif js_ForceGC(cx); if (rtempty) { /* Free atom state now that we've run the GC. */ js_FreeAtomState(cx, &rt->atomState); } /* Free the stuff hanging off of cx. */ PR_FinishArenaPool(&cx->stackPool); PR_FinishArenaPool(&cx->codePool); PR_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); free(cx); }
void nsStringBundleService::flushBundleCache() { // release all bundles in the cache mBundleMap.Reset(); PRCList *current = PR_LIST_HEAD(&mBundleCache); while (current != &mBundleCache) { bundleCacheEntry_t *cacheEntry = (bundleCacheEntry_t*)current; recycleEntry(cacheEntry); PRCList *oldItem = current; current = PR_NEXT_LINK(current); // will be freed in PL_FreeArenaPool PR_REMOVE_LINK(oldItem); } PL_FreeArenaPool(&mCacheEntryPool); }
void nsPACMan::ProcessPendingQ(nsresult status) { // Now, start any pending queries PRCList *node = PR_LIST_HEAD(&mPendingQ); while (node != &mPendingQ) { PendingPACQuery *query = static_cast<PendingPACQuery *>(node); node = PR_NEXT_LINK(node); if (NS_SUCCEEDED(status)) { // keep the query in the list (so we can complete it from Shutdown if // necessary). status = query->Start(); } if (NS_FAILED(status)) { // remove the query from the list PR_REMOVE_LINK(query); query->Complete(status, EmptyCString()); NS_RELEASE(query); } } }
static PRBool CancelTimer(TimerEvent *timer) { PRBool canceled = PR_FALSE; PR_Lock(tm_vars.ml); timer->ref_count -= 1; if (timer->links.prev == &timer->links) { while (timer->ref_count == 1) { PR_WaitCondVar(tm_vars.cancel_timer, PR_INTERVAL_NO_TIMEOUT); } } else { PR_REMOVE_LINK(&timer->links); canceled = PR_TRUE; } PR_Unlock(tm_vars.ml); PR_DELETE(timer); return canceled; }
nsresult nsStringBundleService::getStringBundle(const char *aURLSpec, nsIStringBundle **aResult) { nsCStringKey completeKey(aURLSpec); bundleCacheEntry_t* cacheEntry = (bundleCacheEntry_t*)mBundleMap.Get(&completeKey); if (cacheEntry) { // cache hit! // remove it from the list, it will later be reinserted // at the head of the list PR_REMOVE_LINK((PRCList*)cacheEntry); } else { // hasn't been cached, so insert it into the hash table nsStringBundle* bundle = new nsStringBundle(aURLSpec, mOverrideStrings); if (!bundle) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(bundle); cacheEntry = insertIntoCache(bundle, &completeKey); NS_RELEASE(bundle); // cache should now be holding a ref // in the cacheEntry } // at this point the cacheEntry should exist in the hashtable, // but is not in the LRU cache. // put the cache entry at the front of the list PR_INSERT_LINK((PRCList *)cacheEntry, &mBundleCache); // finally, return the value *aResult = cacheEntry->mBundle; NS_ADDREF(*aResult); return NS_OK; }
NS_IMETHODIMP PendingPACQuery::OnLookupComplete(nsICancelable *request, nsIDNSRecord *record, nsresult status) { // NOTE: we don't care about the results of this DNS query. We issued // this DNS query just to pre-populate our DNS cache. mDNSRequest = nsnull; // break reference cycle // If we've already completed this query then do nothing. if (!mCallback) return NS_OK; // We're no longer pending, so we can remove ourselves. PR_REMOVE_LINK(this); NS_RELEASE_THIS(); nsCAutoString pacString; status = mPACMan->GetProxyForURI(mURI, pacString); Complete(status, pacString); return NS_OK; }
PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group) { PRStatus rv = PR_SUCCESS; if (NULL == group) group = mw_state->group; PR_ASSERT(NULL != group); if (NULL != group) { if (_prmw_stopped != group->state) /* quick, unsafe test */ { PRMWGroupState mws; /* One shot to correct the situation */ PR_Lock(group->ml); if (group->state < _prmw_stopped) /* safer test */ group->state = _prmw_stopping; mws = MW_TestForShutdownInternal(group); PR_Unlock(group->ml); if (_prmw_stopped != mws) /* quick test again */ { PR_SetError(PR_INVALID_STATE_ERROR, 0); return PR_FAILURE; } } PR_Lock(mw_lock); PR_REMOVE_LINK(&group->group_link); PR_Unlock(mw_lock); PR_DELETE(group->waiter); PR_DestroyCondVar(group->new_business); PR_DestroyCondVar(group->io_complete); PR_DestroyCondVar(group->io_taken); PR_DestroyLock(group->ml); if (group == mw_state->group) mw_state->group = NULL; PR_DELETE(group); } return rv; } /* PR_DestroyWaitGroup */