/**
 *  RemoveBinding :  remove binding from collision detection on deactivation
 */
void
nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
{
    NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
    if (!initialized)   return;
    
    HashTableEntry * hashEntry;
    void           * key = (void *)(uintptr_t)binding->mRecord.HashNumber();

    hashEntry = (HashTableEntry*) PL_DHashTableSearch(&table,
                                                      (void*)(uintptr_t) key);
    if (!hashEntry) {
        NS_WARNING("### disk cache: binding not in hashtable!");
        return;
    }
    
    if (binding == hashEntry->mBinding) {
        if (PR_CLIST_IS_EMPTY(binding)) {
            // remove this hash entry
            PL_DHashTableRemove(&table,
                                (void*)(uintptr_t) binding->mRecord.HashNumber());
            return;
            
        } else {
            // promote next binding to head, and unlink this binding
            hashEntry->mBinding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
        }
    }
    PR_REMOVE_AND_INIT_LINK(binding);
}
/**
 *  RemoveBinding :  remove binding from collision detection on deactivation
 */
void
nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
{
    NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
    if (!initialized)   return;
    
    HashTableEntry * hashEntry;
    void *           key = (void *)binding->mRecord.HashNumber();

    hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table,
                                                       (void*) key,
                                                       PL_DHASH_LOOKUP);
    if (!PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
        NS_WARNING("### disk cache: binding not in hashtable!");
        return;
    }
    
    if (binding == hashEntry->mBinding) {
        if (PR_CLIST_IS_EMPTY(binding)) {
            // remove this hash entry
            (void) PL_DHashTableOperate(&table,
                                        (void*) binding->mRecord.HashNumber(),
                                        PL_DHASH_REMOVE);
            return;
            
        } else {
            // promote next binding to head, and unlink this binding
            hashEntry->mBinding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
        }
    }
    PR_REMOVE_AND_INIT_LINK(binding);
}
Exemple #3
0
nsresult
nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, int32_t deltaSize)
{
    if (entry->IsStreamData()) {
        // we have the right to refuse or pre-evict
        uint32_t  newSize = entry->DataSize() + deltaSize;
        if (EntryIsTooBig(newSize)) {
#ifdef DEBUG
            nsresult rv =
#endif
                nsCacheService::DoomEntry(entry);
            NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed.");
            return NS_ERROR_ABORT;
        }
    }

    // adjust our totals
    mTotalSize    += deltaSize;

    if (!entry->IsDoomed()) {
        // move entry to the tail of the appropriate eviction list
        PR_REMOVE_AND_INIT_LINK(entry);
        PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, deltaSize)]);
    }

    EvictEntriesIfNecessary();
    return NS_OK;
}
Exemple #4
0
nsresult
nsMemoryCacheDevice::BindEntry(nsCacheEntry * entry)
{
    if (!entry->IsDoomed()) {
        NS_ASSERTION(PR_CLIST_IS_EMPTY(entry),"entry is already on a list!");

        // append entry to the eviction list
        PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, 0)]);

        // add entry to hashtable of mem cache entries
        nsresult  rv = mMemCacheEntries.AddEntry(entry);
        if (NS_FAILED(rv)) {
            PR_REMOVE_AND_INIT_LINK(entry);
            return rv;
        }

        // add size of entry to memory totals
        ++mEntryCount;
        if (mMaxEntryCount < mEntryCount) mMaxEntryCount = mEntryCount;

        mTotalSize += entry->DataSize();
        EvictEntriesIfNecessary();
    }

    return NS_OK;
}
PRBool
nsCacheEntry::RemoveRequest(nsCacheRequest * request)
{
    // XXX if debug: verify this request belongs to this entry
    PR_REMOVE_AND_INIT_LINK(request);

    // return true if this entry should stay active
    return !((PR_CLIST_IS_EMPTY(&mRequestQ)) &&
             (PR_CLIST_IS_EMPTY(&mDescriptorQ)));
}
Exemple #6
0
/*
 * timer worker thread function
 */
static void timer_wstart(void *arg)
{
PRThreadPool *tp = (PRThreadPool *) arg;
PRCList *qp;
PRIntervalTime timeout;
PRIntervalTime now;

	/*
	 * call PR_WaitCondVar with minimum value of all timeouts
	 */
	while (!tp->shutdown) {
		PRJob *jobp;

		PR_Lock(tp->timerq.lock);
		if (PR_CLIST_IS_EMPTY(&tp->timerq.list)) {
			timeout = PR_INTERVAL_NO_TIMEOUT;
		} else {
			PRCList *qp;

			qp = tp->timerq.list.next;
			jobp = JOB_LINKS_PTR(qp);

			timeout = jobp->absolute - PR_IntervalNow();
            if (timeout <= 0)
				timeout = PR_INTERVAL_NO_WAIT;  /* already timed out */
		}
		if (PR_INTERVAL_NO_WAIT != timeout)
			PR_WaitCondVar(tp->timerq.cv, timeout);
		if (tp->shutdown) {
			PR_Unlock(tp->timerq.lock);
			break;
		}
		/*
		 * move expired-timer jobs to jobq
		 */
		now = PR_IntervalNow();	
		while (!PR_CLIST_IS_EMPTY(&tp->timerq.list)) {
			qp = tp->timerq.list.next;
			jobp = JOB_LINKS_PTR(qp);

			if ((PRInt32)(jobp->absolute - now) > 0) {
				break;
			}
			/*
			 * job timed out
			 */
			PR_REMOVE_AND_INIT_LINK(&jobp->links);
			tp->timerq.cnt--;
			jobp->on_timerq = PR_FALSE;
			add_to_jobq(tp, jobp);
		}
		PR_Unlock(tp->timerq.lock);
	}
}
Exemple #7
0
/**
 * returns a string containing all the parameters in the ConfigStore hash set in the 
 * format key1=value1&&key2=value2&& ...
 * The list will be lexically ordered by parameter key values.
 * The string needs to be freed by the caller.
 **/
TPS_PUBLIC const char* ConfigStore::GetOrderedList()
{
    char *outstr = NULL;
    char *new_string = NULL;
    PRCList order_list;
    PR_INIT_CLIST(&order_list);

    PR_Lock(m_lock);
    PL_HashTableEnumerateEntries(m_root->getSet(), &OrderLoop, &order_list);
    PR_Unlock(m_lock);

    PRCList *current = PR_LIST_HEAD(&order_list);
    PRCList *next;

    outstr = (char*) PR_Malloc(128);
    int allocated = 128;
    int needed = 0;
    PR_snprintf(outstr, 128, "");

    while (current != &order_list) {
        OrderedEntry_t *entry = (OrderedEntry_t *) current;
        const char *value = GetConfigAsString(entry->key, "");

        if ((entry != NULL) && (entry->key != NULL)) {
            needed = PL_strlen(outstr) + PL_strlen(entry->key) + PL_strlen(value) + 4;
            if (allocated <= needed) {
                while (allocated <= needed) {
                    allocated = allocated * 2;
                }
                new_string = (char *)PR_Malloc(allocated);
                PR_snprintf(new_string, allocated, "%s", outstr);
                PR_Free(outstr);
                outstr = new_string;
            } 
                
            PL_strcat(outstr, entry->key);
            PL_strcat(outstr, "=");
            PL_strcat(outstr, value);

            // free the memory for the Ordered Entry
            PL_strfree(entry->key);
        }

        next = PR_NEXT_LINK(current);
        PR_REMOVE_AND_INIT_LINK(current);
        if (current != NULL) {
            PR_Free(current);
        }
        current = next;

        if (current != &order_list) PL_strcat(outstr, "&&");
    }
    return outstr;
}
Exemple #8
0
PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group)
{
    PRRecvWait **desc;
    PRRecvWait *recv_wait = NULL;
    if (PR_FAILURE == MW_Init())
    {
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        return NULL;
    }
    if (NULL == group) group = mw_state->group;
    PR_ASSERT(NULL != group);
    if (NULL == group)
    {
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        return NULL;
    }

    PR_Lock(group->ml);
    if (_prmw_stopped != group->state)
    {
        if (_prmw_running == group->state)
            group->state = _prmw_stopping;  /* so nothing new comes in */
        if (0 == group->waiting_threads)  /* is there anybody else? */
            group->state = _prmw_stopped;  /* we can stop right now */
        while (_prmw_stopped != group->state)
            (void)PR_WaitCondVar(group->mw_manage, PR_INTERVAL_NO_TIMEOUT);

        /* make all the existing descriptors look done/interrupted */
        for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc)
        {
            if (NULL != *desc)
                _MW_DoneInternal(group, desc, PR_MW_INTERRUPT);
        }

        PR_NotifyAllCondVar(group->new_business);
    }

    /* take first element of finished list and return it or NULL */
    if (PR_CLIST_IS_EMPTY(&group->io_ready))
        PR_SetError(PR_GROUP_EMPTY_ERROR, 0);
    else
    {
        PRCList *head = PR_LIST_HEAD(&group->io_ready);
        PR_REMOVE_AND_INIT_LINK(head);
        recv_wait = (PRRecvWait*)head;
    }
    PR_Unlock(group->ml);

    return recv_wait;
}  /* PR_CancelWaitGroup */
nsCacheEntry *
nsMemoryCacheDevice::FindEntry(nsCString * key, bool *collision)
{
    mozilla::Telemetry::AutoTimer<mozilla::Telemetry::CACHE_MEMORY_SEARCH_2> timer;
    nsCacheEntry * entry = mMemCacheEntries.GetEntry(key);
    if (!entry)  return nullptr;

    // move entry to the tail of an eviction list
    PR_REMOVE_AND_INIT_LINK(entry);
    PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, 0)]);
    
    mInactiveSize -= entry->DataSize();

    return entry;
}
void
nsCacheEntry::DetachDescriptors(void)
{
    nsCacheEntryDescriptor * descriptor =
        (nsCacheEntryDescriptor *)PR_LIST_HEAD(&mDescriptorQ);

    while (descriptor != &mDescriptorQ) {
        nsCacheEntryDescriptor * nextDescriptor =
            (nsCacheEntryDescriptor *)PR_NEXT_LINK(descriptor);
        
        descriptor->ClearCacheEntry();
        PR_REMOVE_AND_INIT_LINK(descriptor);
        descriptor = nextDescriptor;
    }
}
PRBool
nsCacheEntry::RemoveDescriptor(nsCacheEntryDescriptor * descriptor)
{
    NS_ASSERTION(descriptor->CacheEntry() == this, "### Wrong cache entry!!");
    PR_REMOVE_AND_INIT_LINK(descriptor);
    descriptor->ClearCacheEntry();

    if (!PR_CLIST_IS_EMPTY(&mDescriptorQ))
        return PR_TRUE;  // stay active if we still have open descriptors

    if (PR_CLIST_IS_EMPTY(&mRequestQ))
        return PR_FALSE; // no descriptors or requests, we can deactivate

    return PR_TRUE;     // find next best request to give a descriptor to
}
void
nsMemoryCacheDevice::EvictEntry(nsCacheEntry * entry, bool deleteEntry)
{
    CACHE_LOG_DEBUG(("Evicting entry 0x%p from memory cache, deleting: %d\n",
                     entry, deleteEntry));
    // remove entry from our hashtable
    mMemCacheEntries.RemoveEntry(entry);
    
    // remove entry from the eviction list
    PR_REMOVE_AND_INIT_LINK(entry);
    
    // update statistics
    int32_t memoryRecovered = (int32_t)entry->DataSize();
    mTotalSize    -= memoryRecovered;
    if (!entry->IsDoomed())
        mInactiveSize -= memoryRecovered;
    --mEntryCount;
    
    if (deleteEntry)  delete entry;
}
nsresult
nsCacheEntry::CreateDescriptor(nsCacheRequest *           request,
                               nsCacheAccessMode          accessGranted,
                               nsICacheEntryDescriptor ** result)
{
    NS_ENSURE_ARG_POINTER(request && result);

    nsCacheEntryDescriptor * descriptor =
        new nsCacheEntryDescriptor(this, accessGranted);

    // XXX check request is on q
    PR_REMOVE_AND_INIT_LINK(request); // remove request regardless of success

    if (descriptor == nsnull)
        return NS_ERROR_OUT_OF_MEMORY;

    PR_APPEND_LINK(descriptor, &mDescriptorQ);

    NS_ADDREF(*result = descriptor);
    return NS_OK;
}
nsresult
nsMemoryCacheDevice::Shutdown()
{
    NS_ASSERTION(mInitialized, "### attempting shutdown while not initialized");
    NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
    
    mMemCacheEntries.Shutdown();

    // evict all entries
    nsCacheEntry * entry, * next;

    for (int i = kQueueCount - 1; i >= 0; --i) {
        entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
        while (entry != &mEvictionList[i]) {
            NS_ASSERTION(!entry->IsInUse(), "### shutting down with active entries");
            next = (nsCacheEntry *)PR_NEXT_LINK(entry);
            PR_REMOVE_AND_INIT_LINK(entry);
        
            // update statistics
            int32_t memoryRecovered = (int32_t)entry->DataSize();
            mTotalSize    -= memoryRecovered;
            mInactiveSize -= memoryRecovered;
            --mEntryCount;

            delete entry;
            entry = next;
        }
    }

/*
 * we're not factoring in changes to meta data yet...    
 *  NS_ASSERTION(mTotalSize == 0, "### mem cache leaking entries?");
 */
    NS_ASSERTION(mInactiveSize == 0, "### mem cache leaking entries?");
    NS_ASSERTION(mEntryCount == 0, "### mem cache leaking entries?");
    
    mInitialized = false;

    return NS_OK;
}
void
nsCacheEntry::DetachDescriptors(void)
{
    nsCacheEntryDescriptor * descriptor =
        (nsCacheEntryDescriptor *)PR_LIST_HEAD(&mDescriptorQ);

    while (descriptor != &mDescriptorQ) {
        nsCacheEntryDescriptor * nextDescriptor =
            (nsCacheEntryDescriptor *)PR_NEXT_LINK(descriptor);

        // Doom entry if something bad happens while closing. See bug #673543
        // Errors are handled different from RemoveDescriptor because this
        // method is only called from ClearDoomList (in which case the entry is
        // doomed anyway) and ClearActiveEntries (in which case we are shutting
        // down and really want to get rid of the entry immediately)
        if (NS_FAILED(descriptor->CloseOutput()))
            nsCacheService::DoomEntry(this);

        descriptor->ClearCacheEntry();
        PR_REMOVE_AND_INIT_LINK(descriptor);
        descriptor = nextDescriptor;
    }
}
bool
nsCacheEntry::RemoveDescriptor(nsCacheEntryDescriptor * descriptor)
{
    NS_ASSERTION(descriptor->CacheEntry() == this, "### Wrong cache entry!!");
    nsresult rv = descriptor->CloseOutput();
    if (rv == NS_BASE_STREAM_WOULD_BLOCK)
        return true;

    descriptor->ClearCacheEntry();
    PR_REMOVE_AND_INIT_LINK(descriptor);

    // Doom entry if something bad happens while closing. See bug #673543
    if (NS_FAILED(rv))
        nsCacheService::DoomEntry(this);

    if (!PR_CLIST_IS_EMPTY(&mDescriptorQ))
        return true;  // stay active if we still have open descriptors

    if (PR_CLIST_IS_EMPTY(&mRequestQ))
        return false; // no descriptors or requests, we can deactivate

    return true;     // find next best request to give a descriptor to
}
Exemple #17
0
PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group)
{
    PRRecvWait **desc;
    PRRecvWait *recv_wait = NULL;
#ifdef WINNT
    _MDOverlapped *overlapped;
    PRRecvWait **end;
    PRThread *me = _PR_MD_CURRENT_THREAD();
#endif

    if (NULL == group) group = mw_state->group;
    PR_ASSERT(NULL != group);
    if (NULL == group)
    {
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        return NULL;
    }

    PR_Lock(group->ml);
    if (_prmw_stopped != group->state)
    {
        if (_prmw_running == group->state)
            group->state = _prmw_stopping;  /* so nothing new comes in */
        if (0 == group->waiting_threads)  /* is there anybody else? */
            group->state = _prmw_stopped;  /* we can stop right now */
        else
        {
            PR_NotifyAllCondVar(group->new_business);
            PR_NotifyAllCondVar(group->io_complete);
        }
        while (_prmw_stopped != group->state)
            (void)PR_WaitCondVar(group->mw_manage, PR_INTERVAL_NO_TIMEOUT);
    }

#ifdef WINNT
    _PR_MD_LOCK(&group->mdlock);
#endif
    /* make all the existing descriptors look done/interrupted */
#ifdef WINNT
    end = &group->waiter->recv_wait + group->waiter->length;
    for (desc = &group->waiter->recv_wait; desc < end; ++desc)
    {
        if (NULL != *desc)
        {
            if (InterlockedCompareExchange((LONG *)&(*desc)->outcome,
                (LONG)PR_MW_INTERRUPT, (LONG)PR_MW_PENDING)
                == (LONG)PR_MW_PENDING)
            {
                PRFileDesc *bottom = PR_GetIdentitiesLayer(
                    (*desc)->fd, PR_NSPR_IO_LAYER);
                PR_ASSERT(NULL != bottom);
                if (NULL == bottom)
                {
                    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
                    goto invalid_arg;
                }
                bottom->secret->state = _PR_FILEDESC_CLOSED;
#if 0
                fprintf(stderr, "cancel wait group: closing socket\n");
#endif
                if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR)
                {
                    fprintf(stderr, "closesocket failed: %d\n",
                        WSAGetLastError());
                    exit(1);
                }
            }
        }
    }
    while (group->waiter->count > 0)
    {
        _PR_THREAD_LOCK(me);
        me->state = _PR_IO_WAIT;
        PR_APPEND_LINK(&me->waitQLinks, &group->wait_list);
        if (!_PR_IS_NATIVE_THREAD(me))
        {
            _PR_SLEEPQ_LOCK(me->cpu);
            _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT);
            _PR_SLEEPQ_UNLOCK(me->cpu);
        }
        _PR_THREAD_UNLOCK(me);
        _PR_MD_UNLOCK(&group->mdlock);
        PR_Unlock(group->ml);
        _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
        me->state = _PR_RUNNING;
        PR_Lock(group->ml);
        _PR_MD_LOCK(&group->mdlock);
    }
#else
    for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc)
    {
        PR_ASSERT(desc < &group->waiter->recv_wait + group->waiter->length);
        if (NULL != *desc)
            _MW_DoneInternal(group, desc, PR_MW_INTERRUPT);
    }
#endif

    /* take first element of finished list and return it or NULL */
    if (PR_CLIST_IS_EMPTY(&group->io_ready))
        PR_SetError(PR_GROUP_EMPTY_ERROR, 0);
    else
    {
        PRCList *head = PR_LIST_HEAD(&group->io_ready);
        PR_REMOVE_AND_INIT_LINK(head);
#ifdef WINNT
        overlapped = (_MDOverlapped *)
            ((char *)head - offsetof(_MDOverlapped, data));
        head = &overlapped->data.mw.desc->internal;
        if (NULL != overlapped->data.mw.timer)
        {
            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
                != overlapped->data.mw.desc->timeout);
            CancelTimer(overlapped->data.mw.timer);
        }
        else
        {
            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
                == overlapped->data.mw.desc->timeout);
        }
        PR_DELETE(overlapped);
#endif
        recv_wait = (PRRecvWait*)head;
    }
#ifdef WINNT
invalid_arg:
    _PR_MD_UNLOCK(&group->mdlock);
#endif
    PR_Unlock(group->ml);

    return recv_wait;
}  /* PR_CancelWaitGroup */
Exemple #18
0
/**
 * Commits changes to the config file
 */
TPS_PUBLIC int ConfigStore::Commit(const bool backup, char *error_msg, int len)
{
    char name_tmp[256], cdate[256], name_bak[256], bak_dir[256];
    char basename[256], dirname[256];
    PRFileDesc *ftmp  = NULL;
    PRExplodedTime time;
    PRTime now;
    PRStatus status;

    if (m_cfg_file_path == NULL) {
        PR_snprintf(error_msg, len, "ConfigStore::Commit(): m_cfg_file_path is NULL!");
        return 1;
    }

    if (strrchr(m_cfg_file_path, '/') != NULL) {
        PR_snprintf((char *) basename, 256, "%s", strrchr(m_cfg_file_path, '/') +1);
        PR_snprintf((char *) dirname, PL_strlen(m_cfg_file_path) - PL_strlen(basename), "%s", m_cfg_file_path);
        PL_strcat(dirname, '\0');
    } else {
        PR_snprintf((char *) basename, 256, "%s", m_cfg_file_path);
        PR_snprintf((char *) dirname, 256, ".");
    }
    PR_snprintf(bak_dir, 256, "%s/bak", dirname); 

    now = PR_Now();
    PR_ExplodeTime(now, PR_LocalTimeParameters, &time);
    PR_snprintf(cdate, 16, "%04d%02d%02d%02d%02d%02dZ",
        time.tm_year, (time.tm_month + 1), time.tm_mday,
        time.tm_hour, time.tm_min, time.tm_sec);
    PR_snprintf(name_tmp, 256, "%s.%s.tmp", m_cfg_file_path,cdate);
    PR_snprintf(name_bak, 256, "%s/%s.%s", bak_dir, basename, cdate);

    ftmp = PR_Open(name_tmp, PR_WRONLY| PR_CREATE_FILE, 00400|00200);
    if (ftmp == NULL) {
        // unable to create temporary config file 
        PR_snprintf(error_msg, len, "ConfigStore::Commit(): unable to create temporary config file");
        return 1;
    }

    PRCList order_list;
    PR_INIT_CLIST(&order_list);

    PR_Lock(m_lock);
    PL_HashTableEnumerateEntries(m_root->getSet(), &OrderLoop, &order_list);
    PR_Unlock(m_lock);

    PRCList *current = PR_LIST_HEAD(&order_list);
    PRCList *next;

    while (current != &order_list) {
        OrderedEntry_t *entry = (OrderedEntry_t *) current;
        PR_Write(ftmp, entry->key, PL_strlen(entry->key));
        PR_Write(ftmp, "=", 1);
        const char *value = GetConfigAsString(entry->key, "");
        PR_Write(ftmp, value, PL_strlen(value));
        PR_Write(ftmp, "\n", 1);

        // free the memory for the Ordered Entry
        if (entry->key != NULL)  PL_strfree(entry->key);

        next = PR_NEXT_LINK(current);
        PR_REMOVE_AND_INIT_LINK(current);
        if (current != NULL) {
            PR_Free(current);
        }
        current = next;
    }

    PR_Close(ftmp);

    if (backup) { 
        // create the backup directory if it does not exist
        if (PR_Access(bak_dir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
            PR_MkDir(bak_dir, 00770);
        } 
        status = PR_Rename(m_cfg_file_path, name_bak);
        if (status != PR_SUCCESS) {
            // failed to back up CS.cfg
        }
    } 
    if (PR_Access(m_cfg_file_path, PR_ACCESS_EXISTS) == PR_SUCCESS) {
        // backup is false, or backup failed
        status = PR_Delete(m_cfg_file_path);
        if (status != PR_SUCCESS) {
            // failed to delete old CS.cfg file
            PR_snprintf(error_msg, len, "ConfigStore::Commit(): unable to delete old CS.cfg file");
            return 1;
        }
    }

    status = PR_Rename(name_tmp, m_cfg_file_path);
    if (status != PR_SUCCESS) {
        // failed to move tmp to CS.cfg 
        // major badness - we now have only tmp file, no CS.cfg
        PR_snprintf(error_msg, len, "ConfigStore::Commit(): failed to move tmp file to CS.cfg");
        return 1;
    }

    return 0;
}
Exemple #19
0
PR_CancelJob(PRJob *jobp) {

	PRStatus rval = PR_FAILURE;
	PRThreadPool *tp;

	if (jobp->on_timerq) {
		/*
		 * now, check again while holding the timerq lock
		 */
		tp = jobp->tpool;
		PR_Lock(tp->timerq.lock);
		if (jobp->on_timerq) {
			jobp->on_timerq = PR_FALSE;
			PR_REMOVE_AND_INIT_LINK(&jobp->links);
			tp->timerq.cnt--;
			PR_Unlock(tp->timerq.lock);
			if (!JOINABLE_JOB(jobp)) {
				delete_job(jobp);
			} else {
				JOIN_NOTIFY(jobp);
			}
			rval = PR_SUCCESS;
		} else
			PR_Unlock(tp->timerq.lock);
	} else if (jobp->on_ioq) {
		/*
		 * now, check again while holding the ioq lock
		 */
		tp = jobp->tpool;
		PR_Lock(tp->ioq.lock);
		if (jobp->on_ioq) {
			jobp->cancel_cv = PR_NewCondVar(tp->ioq.lock);
			if (NULL == jobp->cancel_cv) {
				PR_Unlock(tp->ioq.lock);
				PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
				return PR_FAILURE;
			}
			/*
			 * mark job 'cancelled' and notify io thread(s)
			 * XXXX:
			 *		this assumes there is only one io thread; when there
			 * 		are multiple threads, the io thread processing this job
			 * 		must be notified.
			 */
			jobp->cancel_io = PR_TRUE;
			PR_Unlock(tp->ioq.lock);	/* release, reacquire ioq lock */
			notify_ioq(tp);
			PR_Lock(tp->ioq.lock);
			while (jobp->cancel_io)
				PR_WaitCondVar(jobp->cancel_cv, PR_INTERVAL_NO_TIMEOUT);
			PR_Unlock(tp->ioq.lock);
			PR_ASSERT(!jobp->on_ioq);
			if (!JOINABLE_JOB(jobp)) {
				delete_job(jobp);
			} else {
				JOIN_NOTIFY(jobp);
			}
			rval = PR_SUCCESS;
		} else
			PR_Unlock(tp->ioq.lock);
	}
	if (PR_FAILURE == rval)
		PR_SetError(PR_INVALID_STATE_ERROR, 0);
	return rval;
}
static NSFCStatus
_NSFC_DeleteEntry(NSFCCache cache, NSFCEntryImpl *nep, 
                  PRBool hasBucketLock, PRBool delCntIt, PRBool outdCntIt)
{
    NSFCStatus rfc = NSFC_OK;

    PR_ASSERT(nep);

    /* Get access to nep's bucket if caller doesn't have it already */
    PRUint32 bucket;
    if (hasBucketLock == PR_FALSE) {
        if (nep->fDelete) {
            return rfc;
        }
        bucket = nep->hash % cache->hsize;
        NSFC_ACQUIREBUCKET(cache, bucket);
    } else {
        NSFC_ASSERTBUCKETHELD(cache, nep->hash % cache->hsize);
    }

    /* If nep hasn't already been marked for deletion... */
    if (!nep->fDelete) {

        /* Remove nep from the hit list */
        PR_Lock(cache->hitLock);
        PR_REMOVE_AND_INIT_LINK(&nep->hit_list);
        PR_Unlock(cache->hitLock);
        PR_ASSERT(PR_LIST_HEAD(&nep->hit_list) == PR_LIST_TAIL(&nep->hit_list));

        /* Mark it for delete */
        nep->fDelete = 1;

        /* Increment total count of entries deleted */
        if (delCntIt == PR_TRUE) { 
            PR_AtomicIncrement((PRInt32 *)&cache->delCnt);
            PR_AtomicIncrement((PRInt32 *)&cache->busydCnt);
            if (outdCntIt == PR_TRUE)
                PR_AtomicIncrement((PRInt32 *)&cache->outdCnt);
        }
    }

    if (nep->refcnt == 0) {
        /*
         * Given that the entry's use count is zero, the caller had better have
         * the bucket lock (because he clearly doesn't have a refcnt)
         */
        PR_ASSERT(hasBucketLock == PR_TRUE);

        _NSFC_DestroyEntry(cache, nep, delCntIt);
    }

    /* Release the bucket lock if we weren't holding it on entry */
    if (hasBucketLock == PR_FALSE) {
        NSFC_RELEASEBUCKET(cache, bucket);
    }

    /* Cache contents have been modified */
    cache->sig++;

    return rfc;
}
Exemple #21
0
/*
 * io worker thread function
 */
static void io_wstart(void *arg)
{
PRThreadPool *tp = (PRThreadPool *) arg;
int pollfd_cnt, pollfds_used;
int rv;
PRCList *qp, *nextqp;
PRPollDesc *pollfds;
PRJob **polljobs;
int poll_timeout;
PRIntervalTime now;

	/*
	 * scan io_jobq
	 * construct poll list
	 * call PR_Poll
	 * for all fds, for which poll returns true, move the job to
	 * jobq and wakeup worker thread.
	 */
	while (!tp->shutdown) {
		PRJob *jobp;

		pollfd_cnt = tp->ioq.cnt + 10;
		if (pollfd_cnt > tp->ioq.npollfds) {

			/*
			 * re-allocate pollfd array if the current one is not large
			 * enough
			 */
			if (NULL != tp->ioq.pollfds)
				PR_Free(tp->ioq.pollfds);
			tp->ioq.pollfds = (PRPollDesc *) PR_Malloc(pollfd_cnt *
						(sizeof(PRPollDesc) + sizeof(PRJob *)));
			PR_ASSERT(NULL != tp->ioq.pollfds);
			/*
			 * array of pollfds
			 */
			pollfds = tp->ioq.pollfds;
			tp->ioq.polljobs = (PRJob **) (&tp->ioq.pollfds[pollfd_cnt]);
			/*
			 * parallel array of jobs
			 */
			polljobs = tp->ioq.polljobs;
			tp->ioq.npollfds = pollfd_cnt;
		}

		pollfds_used = 0;
		/*
		 * add the notify fd; used for unblocking io thread(s)
		 */
		pollfds[pollfds_used].fd = tp->ioq.notify_fd;
		pollfds[pollfds_used].in_flags = PR_POLL_READ;
		pollfds[pollfds_used].out_flags = 0;
		polljobs[pollfds_used] = NULL;
		pollfds_used++;
		/*
		 * fill in the pollfd array
		 */
		PR_Lock(tp->ioq.lock);
		for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) {
			nextqp = qp->next;
			jobp = JOB_LINKS_PTR(qp);
			if (jobp->cancel_io) {
				CANCEL_IO_JOB(jobp);
				continue;
			}
			if (pollfds_used == (pollfd_cnt))
				break;
			pollfds[pollfds_used].fd = jobp->iod->socket;
			pollfds[pollfds_used].in_flags = jobp->io_poll_flags;
			pollfds[pollfds_used].out_flags = 0;
			polljobs[pollfds_used] = jobp;

			pollfds_used++;
		}
		if (!PR_CLIST_IS_EMPTY(&tp->ioq.list)) {
			qp = tp->ioq.list.next;
			jobp = JOB_LINKS_PTR(qp);
			if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout)
				poll_timeout = PR_INTERVAL_NO_TIMEOUT;
			else if (PR_INTERVAL_NO_WAIT == jobp->timeout)
				poll_timeout = PR_INTERVAL_NO_WAIT;
			else {
				poll_timeout = jobp->absolute - PR_IntervalNow();
				if (poll_timeout <= 0) /* already timed out */
					poll_timeout = PR_INTERVAL_NO_WAIT;
			}
		} else {
			poll_timeout = PR_INTERVAL_NO_TIMEOUT;
		}
		PR_Unlock(tp->ioq.lock);

		/*
		 * XXXX
		 * should retry if more jobs have been added to the queue?
		 *
		 */
		PR_ASSERT(pollfds_used <= pollfd_cnt);
		rv = PR_Poll(tp->ioq.pollfds, pollfds_used, poll_timeout);

		if (tp->shutdown) {
			break;
		}

		if (rv > 0) {
			/*
			 * at least one io event is set
			 */
			PRStatus rval_status;
			PRInt32 index;

			PR_ASSERT(pollfds[0].fd == tp->ioq.notify_fd);
			/*
			 * reset the pollable event, if notified
			 */
			if (pollfds[0].out_flags & PR_POLL_READ) {
				rval_status = PR_WaitForPollableEvent(tp->ioq.notify_fd);
				PR_ASSERT(PR_SUCCESS == rval_status);
			}

			for(index = 1; index < (pollfds_used); index++) {
                PRInt16 events = pollfds[index].in_flags;
                PRInt16 revents = pollfds[index].out_flags;	
				jobp = polljobs[index];	

                if ((revents & PR_POLL_NVAL) ||  /* busted in all cases */
                	(revents & PR_POLL_ERR) ||
                			((events & PR_POLL_WRITE) &&
							(revents & PR_POLL_HUP))) { /* write op & hup */
					PR_Lock(tp->ioq.lock);
					if (jobp->cancel_io) {
						CANCEL_IO_JOB(jobp);
						PR_Unlock(tp->ioq.lock);
						continue;
					}
					PR_REMOVE_AND_INIT_LINK(&jobp->links);
					tp->ioq.cnt--;
					jobp->on_ioq = PR_FALSE;
					PR_Unlock(tp->ioq.lock);

					/* set error */
                    if (PR_POLL_NVAL & revents)
						jobp->iod->error = PR_BAD_DESCRIPTOR_ERROR;
                    else if (PR_POLL_HUP & revents)
						jobp->iod->error = PR_CONNECT_RESET_ERROR;
                    else 
						jobp->iod->error = PR_IO_ERROR;

					/*
					 * add to jobq
					 */
					add_to_jobq(tp, jobp);
				} else if (revents) {
					/*
					 * add to jobq
					 */
					PR_Lock(tp->ioq.lock);
					if (jobp->cancel_io) {
						CANCEL_IO_JOB(jobp);
						PR_Unlock(tp->ioq.lock);
						continue;
					}
					PR_REMOVE_AND_INIT_LINK(&jobp->links);
					tp->ioq.cnt--;
					jobp->on_ioq = PR_FALSE;
					PR_Unlock(tp->ioq.lock);

					if (jobp->io_op == JOB_IO_CONNECT) {
						if (PR_GetConnectStatus(&pollfds[index]) == PR_SUCCESS)
							jobp->iod->error = 0;
						else
							jobp->iod->error = PR_GetError();
					} else
						jobp->iod->error = 0;

					add_to_jobq(tp, jobp);
				}
			}
		}
		/*
		 * timeout processing
		 */
		now = PR_IntervalNow();
		PR_Lock(tp->ioq.lock);
		for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) {
			nextqp = qp->next;
			jobp = JOB_LINKS_PTR(qp);
			if (jobp->cancel_io) {
				CANCEL_IO_JOB(jobp);
				continue;
			}
			if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout)
				break;
			if ((PR_INTERVAL_NO_WAIT != jobp->timeout) &&
								((PRInt32)(jobp->absolute - now) > 0))
				break;
			PR_REMOVE_AND_INIT_LINK(&jobp->links);
			tp->ioq.cnt--;
			jobp->on_ioq = PR_FALSE;
			jobp->iod->error = PR_IO_TIMEOUT_ERROR;
			add_to_jobq(tp, jobp);
		}
		PR_Unlock(tp->ioq.lock);
	}
}
Exemple #22
0
/*
 * worker thread function
 */
static void wstart(void *arg)
{
PRThreadPool *tp = (PRThreadPool *) arg;
PRCList *head;

	/*
	 * execute jobs until shutdown
	 */
	while (!tp->shutdown) {
		PRJob *jobp;
#ifdef OPT_WINNT
		BOOL rv;
		DWORD unused, shutdown;
		LPOVERLAPPED olp;

		PR_Lock(tp->jobq.lock);
		tp->idle_threads++;
		PR_Unlock(tp->jobq.lock);
		rv = GetQueuedCompletionStatus(tp->jobq.nt_completion_port,
					&unused, &shutdown, &olp, INFINITE);
		
		PR_ASSERT(rv);
		if (shutdown)
			break;
		jobp = ((NT_notifier *) olp)->jobp;
		PR_Lock(tp->jobq.lock);
		tp->idle_threads--;
		tp->jobq.cnt--;
		PR_Unlock(tp->jobq.lock);
#else

		PR_Lock(tp->jobq.lock);
		while (PR_CLIST_IS_EMPTY(&tp->jobq.list) && (!tp->shutdown)) {
			tp->idle_threads++;
			PR_WaitCondVar(tp->jobq.cv, PR_INTERVAL_NO_TIMEOUT);
			tp->idle_threads--;
		}	
		if (tp->shutdown) {
			PR_Unlock(tp->jobq.lock);
			break;
		}
		head = PR_LIST_HEAD(&tp->jobq.list);
		/*
		 * remove job from queue
		 */
		PR_REMOVE_AND_INIT_LINK(head);
		tp->jobq.cnt--;
		jobp = JOB_LINKS_PTR(head);
		PR_Unlock(tp->jobq.lock);
#endif

		jobp->job_func(jobp->job_arg);
		if (!JOINABLE_JOB(jobp)) {
			delete_job(jobp);
		} else {
			JOIN_NOTIFY(jobp);
		}
	}
	PR_Lock(tp->jobq.lock);
	tp->current_threads--;
	PR_Unlock(tp->jobq.lock);
}
Exemple #23
0
PR_JoinThreadPool(PRThreadPool *tpool)
{
PRStatus rval = PR_SUCCESS;
PRCList *head;
PRStatus rval_status;

	PR_Lock(tpool->jobq.lock);
	while (!tpool->shutdown)
		PR_WaitCondVar(tpool->shutdown_cv, PR_INTERVAL_NO_TIMEOUT);

	/*
	 * wakeup worker threads
	 */
#ifdef OPT_WINNT
	/*
	 * post shutdown notification for all threads
	 */
	{
		int i;
		for(i=0; i < tpool->current_threads; i++) {
			PostQueuedCompletionStatus(tpool->jobq.nt_completion_port, 0,
												TRUE, NULL);
		}
	}
#else
	PR_NotifyAllCondVar(tpool->jobq.cv);
#endif

	/*
	 * wakeup io thread(s)
	 */
	notify_ioq(tpool);

	/*
	 * wakeup timer thread(s)
	 */
	PR_Lock(tpool->timerq.lock);
	notify_timerq(tpool);
	PR_Unlock(tpool->timerq.lock);

	while (!PR_CLIST_IS_EMPTY(&tpool->jobq.wthreads)) {
		wthread *wthrp;

		head = PR_LIST_HEAD(&tpool->jobq.wthreads);
		PR_REMOVE_AND_INIT_LINK(head);
		PR_Unlock(tpool->jobq.lock);
		wthrp = WTHREAD_LINKS_PTR(head);
		rval_status = PR_JoinThread(wthrp->thread);
		PR_ASSERT(PR_SUCCESS == rval_status);
		PR_DELETE(wthrp);
		PR_Lock(tpool->jobq.lock);
	}
	PR_Unlock(tpool->jobq.lock);
	while (!PR_CLIST_IS_EMPTY(&tpool->ioq.wthreads)) {
		wthread *wthrp;

		head = PR_LIST_HEAD(&tpool->ioq.wthreads);
		PR_REMOVE_AND_INIT_LINK(head);
		wthrp = WTHREAD_LINKS_PTR(head);
		rval_status = PR_JoinThread(wthrp->thread);
		PR_ASSERT(PR_SUCCESS == rval_status);
		PR_DELETE(wthrp);
	}

	while (!PR_CLIST_IS_EMPTY(&tpool->timerq.wthreads)) {
		wthread *wthrp;

		head = PR_LIST_HEAD(&tpool->timerq.wthreads);
		PR_REMOVE_AND_INIT_LINK(head);
		wthrp = WTHREAD_LINKS_PTR(head);
		rval_status = PR_JoinThread(wthrp->thread);
		PR_ASSERT(PR_SUCCESS == rval_status);
		PR_DELETE(wthrp);
	}

	/*
	 * Delete queued jobs
	 */
	while (!PR_CLIST_IS_EMPTY(&tpool->jobq.list)) {
		PRJob *jobp;

		head = PR_LIST_HEAD(&tpool->jobq.list);
		PR_REMOVE_AND_INIT_LINK(head);
		jobp = JOB_LINKS_PTR(head);
		tpool->jobq.cnt--;
		delete_job(jobp);
	}

	/* delete io jobs */
	while (!PR_CLIST_IS_EMPTY(&tpool->ioq.list)) {
		PRJob *jobp;

		head = PR_LIST_HEAD(&tpool->ioq.list);
		PR_REMOVE_AND_INIT_LINK(head);
		tpool->ioq.cnt--;
		jobp = JOB_LINKS_PTR(head);
		delete_job(jobp);
	}

	/* delete timer jobs */
	while (!PR_CLIST_IS_EMPTY(&tpool->timerq.list)) {
		PRJob *jobp;

		head = PR_LIST_HEAD(&tpool->timerq.list);
		PR_REMOVE_AND_INIT_LINK(head);
		tpool->timerq.cnt--;
		jobp = JOB_LINKS_PTR(head);
		delete_job(jobp);
	}

	PR_ASSERT(0 == tpool->jobq.cnt);
	PR_ASSERT(0 == tpool->ioq.cnt);
	PR_ASSERT(0 == tpool->timerq.cnt);

	delete_threadpool(tpool);
	return rval;
}
static void PR_CALLBACK Server(void *arg)
{
    PRStatus rv;
    PRNetAddr serverAddress;
    PRThread *me = PR_GetCurrentThread();
    CSServer_t *server = (CSServer_t*)arg;
    PRSocketOptionData sockOpt;

    server->listener = PR_Socket(domain, SOCK_STREAM, protocol);

    sockOpt.option = PR_SockOpt_Reuseaddr;
    sockOpt.value.reuse_addr = PR_TRUE;
    rv = PR_SetSocketOption(server->listener, &sockOpt);
    TEST_ASSERT(PR_SUCCESS == rv);

    memset(&serverAddress, 0, sizeof(serverAddress));
	if (PR_AF_INET6 != domain)
		rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
	else
		rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT,
													&serverAddress);
    rv = PR_Bind(server->listener, &serverAddress);
    TEST_ASSERT(PR_SUCCESS == rv);

    rv = PR_Listen(server->listener, server->backlog);
    TEST_ASSERT(PR_SUCCESS == rv);

    server->started = PR_IntervalNow();
    TimeOfDayMessage("Server started at", me);

    PR_Lock(server->ml);
    server->state = cs_run;
    PR_NotifyCondVar(server->stateChange);
    PR_Unlock(server->ml);

    /*
    ** Create the first worker (actually, a thread that accepts
    ** connections and then processes the work load as needed).
    ** From this point on, additional worker threads are created
    ** as they are needed by existing worker threads.
    */
    rv = CreateWorker(server, &server->pool);
    TEST_ASSERT(PR_SUCCESS == rv);

    /*
    ** From here on this thread is merely hanging around as the contact
    ** point for the main test driver. It's just waiting for the driver
    ** to declare the test complete.
    */
    TEST_LOG(
        cltsrv_log_file, TEST_LOG_VERBOSE,
        ("\tServer(0x%p): waiting for state change\n", me));

    PR_Lock(server->ml);
    while ((cs_run == server->state) && !Aborted(rv))
    {
        rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
    }
    PR_Unlock(server->ml);
    PR_ClearInterrupt();

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_INFO,
        ("\tServer(0x%p): shutting down workers\n", me));

    /*
    ** Get all the worker threads to exit. They know how to
    ** clean up after themselves, so this is just a matter of
    ** waiting for clorine in the pool to take effect. During
    ** this stage we're ignoring interrupts.
    */
    server->workers.minimum = server->workers.maximum = 0;

    PR_Lock(server->ml);
    while (!PR_CLIST_IS_EMPTY(&server->list))
    {
        PRCList *head = PR_LIST_HEAD(&server->list);
        CSWorker_t *worker = (CSWorker_t*)head;
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
        rv = PR_Interrupt(worker->thread);
        TEST_ASSERT(PR_SUCCESS == rv);
        PR_REMOVE_AND_INIT_LINK(head);
    }

    while (server->pool.workers > 0)
    {
        TEST_LOG(
            cltsrv_log_file, TEST_LOG_NOTICE,
            ("\tServer(0x%p): waiting for %u workers to exit\n",
            me, server->pool.workers));
        (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
    }

    server->state = cs_exit;
    PR_NotifyCondVar(server->stateChange);
    PR_Unlock(server->ml);

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_ALWAYS,
        ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
        me, server->operations, server->bytesTransferred));

    if (NULL != server->listener) PR_Close(server->listener);
    server->stopped = PR_IntervalNow();

}  /* Server */
static void PR_CALLBACK Worker(void *arg)
{
    PRStatus rv;
    PRNetAddr from;
    PRFileDesc *fd = NULL;
    PRThread *me = PR_GetCurrentThread();
    CSWorker_t *worker = (CSWorker_t*)arg;
    CSServer_t *server = worker->server;
    CSPool_t *pool = &server->pool;

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_NOTICE,
        ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));

    PR_Lock(server->ml);
    PR_APPEND_LINK(&worker->element, &server->list);
    pool->workers += 1;  /* define our existance */

    while (cs_run == server->state)
    {
        while (pool->accepting >= server->workers.accepting)
        {
            TEST_LOG(
                cltsrv_log_file, TEST_LOG_VERBOSE,
                ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
                me, pool->accepting));
            rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
            if (Aborted(rv) || (cs_run != server->state))
            {
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_NOTICE,
                    ("\tWorker(0x%p): has been %s\n",
                    me, (Aborted(rv) ? "interrupted" : "stopped")));
                goto exit;
            }
        } 
        pool->accepting += 1;  /* how many are really in accept */
        PR_Unlock(server->ml);

        TEST_LOG(
            cltsrv_log_file, TEST_LOG_VERBOSE,
            ("\t\tWorker(0x%p): calling accept\n", me));
        fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);

        PR_Lock(server->ml);        
        pool->accepting -= 1;
        PR_NotifyCondVar(pool->acceptComplete);

        if ((NULL == fd) && Aborted(PR_FAILURE))
        {
            if (NULL != server->listener)
            {
                PR_Close(server->listener);
                server->listener = NULL;
            }
            goto exit;
        }

        if (NULL != fd)
        {
            /*
            ** Create another worker of the total number of workers is
            ** less than the minimum specified or we have none left in
            ** accept() AND we're not over the maximum.
            ** This sort of presumes that the number allowed in accept
            ** is at least as many as the minimum. Otherwise we'll keep
            ** creating new threads and deleting them soon after.
            */
            PRBool another =
                ((pool->workers < server->workers.minimum) ||
                ((0 == pool->accepting)
                    && (pool->workers < server->workers.maximum))) ?
                    PR_TRUE : PR_FALSE;
            pool->active += 1;
            PR_Unlock(server->ml);

            if (another) (void)CreateWorker(server, pool);

            rv = ProcessRequest(fd, server);
            if (PR_SUCCESS != rv)
                TEST_LOG(
                    cltsrv_log_file, TEST_LOG_ERROR,
                    ("\t\tWorker(0x%p): server process ended abnormally\n", me));
            (void)PR_Close(fd); fd = NULL;

            PR_Lock(server->ml);
            pool->active -= 1;
        }
    }

exit:
    PR_ClearInterrupt();    
    PR_Unlock(server->ml);

    if (NULL != fd)
    {
        (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
        (void)PR_Close(fd);
    }

    TEST_LOG(
        cltsrv_log_file, TEST_LOG_NOTICE,
        ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));

    PR_Lock(server->ml);
    pool->workers -= 1;  /* undefine our existance */
    PR_REMOVE_AND_INIT_LINK(&worker->element);
    PR_NotifyCondVar(pool->exiting);
    PR_Unlock(server->ml);

    PR_DELETE(worker);  /* destruction of the "worker" object */

}  /* Worker */
Exemple #26
0
SECStatus
do_accepts(
    PRFileDesc *listen_sock,
    PRFileDesc *model_sock,
    int         requestCert
    )
{
    PRNetAddr   addr;
    PRErrorCode  perr;
#ifdef XP_UNIX
    struct sigaction act;
#endif

    VLOG(("selfserv: do_accepts: starting"));
    PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH);

    acceptorThread = PR_GetCurrentThread();
#ifdef XP_UNIX
    /* set up the signal handler */
    act.sa_handler = sigusr1_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (sigaction(SIGUSR1, &act, NULL)) {
        fprintf(stderr, "Error installing signal handler.\n");
        exit(1);
    }
#endif
    while (!stopping) {
	PRFileDesc *tcp_sock;
	PRCList    *myLink;

	FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n");
	tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
	if (tcp_sock == NULL) {
    	    perr      = PR_GetError();
	    if ((perr != PR_CONNECT_RESET_ERROR &&
	         perr != PR_PENDING_INTERRUPT_ERROR) || verbose) {
		errWarn("PR_Accept");
	    } 
	    if (perr == PR_CONNECT_RESET_ERROR) {
		FPRINTF(stderr, 
		        "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
		continue;
	    }
	    stopping = 1;
	    break;
	}

        VLOG(("selfserv: do_accept: Got connection\n"));

	PZ_Lock(qLock);
	while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) {
            PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
	}
	if (stopping) {
	    PZ_Unlock(qLock);
            if (tcp_sock) {
	        PR_Close(tcp_sock);
            }
	    break;
	}
	myLink = PR_LIST_HEAD(&freeJobs);
	PR_REMOVE_AND_INIT_LINK(myLink);
	/* could release qLock here and reacquire it 7 lines below, but 
	** why bother for 4 assignment statements? 
	*/
	{
	    JOB * myJob = (JOB *)myLink;
	    myJob->tcp_sock    = tcp_sock;
	    myJob->model_sock  = model_sock;
	    myJob->requestCert = requestCert;
	}

	PR_APPEND_LINK(myLink, &jobQ);
	PZ_NotifyCondVar(jobQNotEmptyCv);
	PZ_Unlock(qLock);
    }

    FPRINTF(stderr, "selfserv: Closing listen socket.\n");
    VLOG(("selfserv: do_accepts: exiting"));
    if (listen_sock) {
        PR_Close(listen_sock);
    }
    return SECSuccess;
}
Exemple #27
0
void
nsIOThreadPool::ThreadFunc(void *arg)
{
    nsIOThreadPool *pool = (nsIOThreadPool *) arg;

    LOG(("entering ThreadFunc\n"));

    {
        nsAutoLock lock(pool->mLock);

        for (;;) {
            PRIntervalTime start = PR_IntervalNow(), timeout = IDLE_TIMEOUT;
            //
            // wait for one or more of the following to occur:
            //  (1) the event queue has an event to process
            //  (2) the shutdown flag has been set
            //  (3) the thread has been idle for too long
            //
            // PR_WaitCondVar will return when any of these conditions is true.
            //
            while (PR_CLIST_IS_EMPTY(&pool->mEventQ) && !pool->mShutdown) {
                pool->mNumIdleThreads++;
                PR_WaitCondVar(pool->mIdleThreadCV, timeout);
                pool->mNumIdleThreads--;

                PRIntervalTime delta = PR_IntervalNow() - start;
                if (delta >= timeout)
                    break;
                timeout -= delta;
                start += delta;
            }

            // if the queue is still empty, then kill this thread (either we
            // are shutting down or the thread exceeded the idle timeout)...
            if (PR_CLIST_IS_EMPTY(&pool->mEventQ))
                break;

            // handle one event at a time: we don't want this one thread to hog
            // all the events while other threads may be able to help out ;-)
            do {
                PLEvent *event = PLEVENT_FROM_LINK(PR_LIST_HEAD(&pool->mEventQ));
                PR_REMOVE_AND_INIT_LINK(&event->link);

                LOG(("event:%p\n", event));

                // release lock!
                lock.unlock();
                PL_HandleEvent(event);
                lock.lock();
            }
            while (!PR_CLIST_IS_EMPTY(&pool->mEventQ));
        }

        // thread is going away...
        pool->mNumThreads--;
        PR_NotifyCondVar(pool->mExitThreadCV);
    }

    // release our reference to the pool
    NS_RELEASE(pool);

    LOG(("leaving ThreadFunc\n"));
}