static TimerEvent *CreateTimer( PRIntervalTime timeout, void (*func)(void *), void *arg) { TimerEvent *timer; PRCList *links, *tail; TimerEvent *elem; timer = PR_NEW(TimerEvent); if (NULL == timer) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return timer; } timer->absolute = PR_IntervalNow() + timeout; timer->func = func; timer->arg = arg; timer->ref_count = 2; PR_Lock(tm_vars.ml); tail = links = PR_LIST_TAIL(&tm_vars.timer_queue); while (links->prev != tail) { elem = TIMER_EVENT_PTR(links); if ((PRInt32)(timer->absolute - elem->absolute) >= 0) { break; } links = links->prev; } PR_INSERT_AFTER(&timer->links, links); PR_NotifyCondVar(tm_vars.new_timer); PR_Unlock(tm_vars.ml); return timer; }
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); } }
PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, PRJobFn fn, void * arg, PRBool joinable) { PRIntervalTime now; PRJob *jobp; if (PR_INTERVAL_NO_TIMEOUT == timeout) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } if (PR_INTERVAL_NO_WAIT == timeout) { /* * no waiting; add to jobq right away */ return(PR_QueueJob(tpool, fn, arg, joinable)); } jobp = alloc_job(joinable, tpool); if (NULL == jobp) { return NULL; } /* * Add a new job to timer_jobq * wakeup timer worker thread */ jobp->job_func = fn; jobp->job_arg = arg; jobp->tpool = tpool; jobp->timeout = timeout; now = PR_IntervalNow(); jobp->absolute = now + timeout; PR_Lock(tpool->timerq.lock); jobp->on_timerq = PR_TRUE; if (PR_CLIST_IS_EMPTY(&tpool->timerq.list)) PR_APPEND_LINK(&jobp->links,&tpool->timerq.list); else { PRCList *qp; PRJob *tmp_jobp; /* * insert into the sorted timer jobq */ for (qp = tpool->timerq.list.prev; qp != &tpool->timerq.list; qp = qp->prev) { tmp_jobp = JOB_LINKS_PTR(qp); if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { break; } } PR_INSERT_AFTER(&jobp->links,qp); } tpool->timerq.cnt++; /* * notify timer worker thread(s) */ notify_timerq(tpool); PR_Unlock(tpool->timerq.lock); return jobp; }
/* queue a job, when a socket is readable or writeable */ static PRJob * queue_io_job(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, PRBool joinable, io_op_type op) { PRJob *jobp; PRIntervalTime now; jobp = alloc_job(joinable, tpool); if (NULL == jobp) { return NULL; } /* * Add a new job to io_jobq * wakeup io worker thread */ jobp->job_func = fn; jobp->job_arg = arg; jobp->tpool = tpool; jobp->iod = iod; if (JOB_IO_READ == op) { jobp->io_op = JOB_IO_READ; jobp->io_poll_flags = PR_POLL_READ; } else if (JOB_IO_WRITE == op) { jobp->io_op = JOB_IO_WRITE; jobp->io_poll_flags = PR_POLL_WRITE; } else if (JOB_IO_ACCEPT == op) { jobp->io_op = JOB_IO_ACCEPT; jobp->io_poll_flags = PR_POLL_READ; } else if (JOB_IO_CONNECT == op) { jobp->io_op = JOB_IO_CONNECT; jobp->io_poll_flags = PR_POLL_WRITE|PR_POLL_EXCEPT; } else { delete_job(jobp); PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } jobp->timeout = iod->timeout; if ((PR_INTERVAL_NO_TIMEOUT == iod->timeout) || (PR_INTERVAL_NO_WAIT == iod->timeout)) { jobp->absolute = iod->timeout; } else { now = PR_IntervalNow(); jobp->absolute = now + iod->timeout; } PR_Lock(tpool->ioq.lock); if (PR_CLIST_IS_EMPTY(&tpool->ioq.list) || (PR_INTERVAL_NO_TIMEOUT == iod->timeout)) { PR_APPEND_LINK(&jobp->links,&tpool->ioq.list); } else if (PR_INTERVAL_NO_WAIT == iod->timeout) { PR_INSERT_LINK(&jobp->links,&tpool->ioq.list); } else { PRCList *qp; PRJob *tmp_jobp; /* * insert into the timeout-sorted ioq */ for (qp = tpool->ioq.list.prev; qp != &tpool->ioq.list; qp = qp->prev) { tmp_jobp = JOB_LINKS_PTR(qp); if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { break; } } PR_INSERT_AFTER(&jobp->links,qp); } jobp->on_ioq = PR_TRUE; tpool->ioq.cnt++; /* * notify io worker thread(s) */ PR_Unlock(tpool->ioq.lock); notify_ioq(tpool); return jobp; }
NSFC_NewFilenameEntry(NSFCCache cip, const char *filename, PRUint32 hvalue, NSFCStatus &rfc) { PRUint32 bucket = hvalue % cip->hsize; PR_ASSERT(cip); if (cip->state != NSFCCache_Active) { rfc = NSFC_DEADCACHE; return NULL; } rfc = NSFC_OK; /* Replace file cache entries once the cache fills up */ if (_NSFC_IsTimeToReplace(cip)) { PR_Lock(cip->hitLock); if (!PR_CLIST_IS_EMPTY(&cip->hit_list)) { NSFCEntryImpl* nepDelete; PRUint32 bucketDelete; /* Get the LRU entry from the hit list and remember its bucket */ PRCList *lru = PR_LIST_TAIL(&cip->hit_list); PR_ASSERT(lru); nepDelete = (NSFCEntryImpl*)((char*)lru - offsetof(NSFCEntryImpl, hit_list)); bucketDelete = nepDelete->hash % cip->hsize; PR_Unlock(cip->hitLock); /* Get access to the LRU entry's bucket */ if (bucket != bucketDelete) { NSFC_RELEASEBUCKET(cip, bucket); NSFC_ACQUIREBUCKET(cip, bucketDelete); } /* Look for the LRU entry in the bucket */ NSFCEntryImpl *nep; for (nep = cip->hname[bucketDelete]; nep; nep = nep->next) { if (nep == nepDelete) break; } if (nep == nepDelete) { /* The LRU entry is still around, mark it for deletion */ NSFC_DeleteEntry(cip, nep, PR_TRUE); /* Increment count of replaced entries */ PR_AtomicIncrement((PRInt32*)&cip->rplcCnt); } /* Get access to the new entry's bucket */ if (bucket != bucketDelete) { NSFC_RELEASEBUCKET(cip, bucketDelete); NSFC_ACQUIREBUCKET(cip, bucket); } } else { PR_Unlock(cip->hitLock); } } /* Respect limit on number of cache entries */ if (cip->curFiles >= cip->cfg.maxFiles) { cip->cacheFull = PR_TRUE; rfc = NSFC_NOSPACE; return NULL; } /* Get a file name entry */ PR_Lock(cip->namefLock); NSFCEntryImpl *nep = cip->namefl; if (nep != NULL) { /* Found a file name entry on the free list */ PR_ASSERT(nep->refcnt == 0); PR_ASSERT(!nep->fHashed); cip->namefl = nep->next; } PR_Unlock(cip->namefLock); if (nep == NULL) { /* Allocate a new file name entry */ nep = (NSFCEntryImpl *)NSFC_Calloc(1, sizeof(*nep), cip); if (nep) { nep->seqno = 1; } } if (nep) { nep->filename = NSFC_Strdup(filename, cip); if (nep->filename) { /* Initialize entry */ nep->next = NULL; nep->pdLock = PR_NewLock(); nep->pdlist = NULL; nep->finfo.pr.type = PR_FILE_OTHER; nep->finfo.pr.size = 0; nep->finfo.pr.creationTime = 0; nep->finfo.pr.modifyTime = 0; PRIntervalTime now = ft_timeIntervalNow(); nep->finfo.lastUpdate = now; nep->finfo.fileid[0] = hvalue; nep->finfo.fileid[1] = nep->seqno; nep->finfo.prerr = 0; nep->finfo.oserr = 0; nep->hash = hvalue; nep->hitcnt = 0; nep->refcnt = 1; nep->flags = 0; nep->fHashed = 1; nep->fDelete = 0; nep->fWriting = 0; /* Add entry to cache instance hash table */ NSFC_ASSERTBUCKETHELD(cip, bucket); nep->next = cip->hname[bucket]; cip->hname[bucket] = nep; PR_AtomicIncrement((PRInt32*)&cip->curFiles); /* Add entry to the hit list */ PR_Lock(cip->hitLock); PR_INIT_CLIST(&nep->hit_list); if (cip->cfg.hitOrder == PR_TRUE) { /* * Add this entry towards the end of the hit list, * but ahead of other entries with a zero hit count. */ PRCList *prev; NSFCEntryImpl *pnep; for (prev = PR_LIST_TAIL(&cip->hit_list); prev != &cip->hit_list; prev = PR_PREV_LINK(prev)) { pnep = NSFCENTRYIMPL(prev); if (pnep->hitcnt > nep->hitcnt) { break; /* Our spot in the list */ } } PR_INSERT_AFTER(&nep->hit_list, prev); } else { /* Put new entry at head of hit list */ PR_INSERT_LINK(&nep->hit_list, &cip->hit_list); } PR_Unlock(cip->hitLock); PR_ASSERT(!nep->fDelete); } else { /* Failed, so return the entry to the free list */ PR_Lock(cip->namefLock); nep->next = cip->namefl; cip->namefl = nep; nep = NULL; PR_Unlock(cip->namefLock); cip->cacheFull = PR_TRUE; /* file cache is full */ rfc = NSFC_NOSPACE; } } else { cip->cacheFull = PR_TRUE; /* file cache is full */ rfc = NSFC_NOSPACE; } /* Cache contents have been modified */ cip->sig++; return nep; }