📄 disksim_cachemem.c
字号:
// fprintf (outputfile, "doing cache_get_read_lock: target %p, lbn %d, lockgran %d\n", target, target->lbn, cache->lockgran);
if ((target->writelock) && (target->writelock != rwdesc->req)) {
rwdesc->locktype = 0;
cache_add_to_lockstruct(&target->lockwaiters, rwdesc);
return(0);
} else {
cache_add_to_lockstruct((struct cachelockw **)&target->readlocks, rwdesc->req);
if (target->writelock) {
target->writelock = NULL;
cache_lock_free(cache, target);
}
return(cache->lockgran);
}
}
static int cache_free_read_lock (cache_def *cache, cache_atom *target, ioreq_event *owner)
{
cache_lockholders *tmp;
int found = FALSE;
int i;
// fprintf (outputfile, "Entered cache_free_read_lock: target %p, lbn %d, lockgran %d\n", target, target->lbn, cache->lockgran);
if (!cache->sharedreadlocks) {
return(cache_free_write_lock(cache, target, owner));
}
// fprintf (outputfile, "doing cache_free_read_lock: target %p, lbn %d, lockgran %d\n", target, target->lbn, cache->lockgran);
while (target->lbn % cache->lockgran) {
target = target->line_prev;
}
tmp = target->readlocks;
while ((tmp) && (!found)) {
int active = FALSE;
for (i=0; i<CACHE_LOCKSPERSTRUCT; i++) {
if (tmp->entry[i] == owner) {
tmp->entry[i] = 0;
found = TRUE;
} else if (tmp->entry[i]) {
active = TRUE;
}
}
if ((tmp == target->readlocks) && (active == FALSE)) {
target->readlocks = tmp->next;
addtoextraq((event *) tmp);
tmp = target->readlocks;
} else {
tmp = tmp->next;
}
}
if (found) {
if (!target->readlocks) {
cache_lock_free(cache, target);
}
return(cache->lockgran);
} else {
return(0);
}
}
static void cache_get_read_lock_range (cache_def *cache, int start, int end, cache_atom *startatom, cache_event *waiter)
{
cache_atom *line = (startatom->lbn == start) ? startatom : NULL;
int lockgran = 1;
int i;
for (i=start; i<=end; i++) {
if (line == NULL) {
line = cache_find_atom(cache, startatom->devno, i);
ASSERT(line != NULL);
}
if ((line->lbn % lockgran) == 0) {
lockgran = cache_get_read_lock(cache, line, waiter);
/* Must not fail to acquire lock */
ASSERT(lockgran != 0);
}
line = line->line_next;
}
}
static int cache_issue_flushreq (cache_def *cache, int start, int end, cache_atom *startatom, cache_event *waiter)
{
ioreq_event *flushreq;
ioreq_event *flushwait;
int waiting = (cache->IOwaiters == waiter) ? 1 : 0;
// fprintf (outputfile, "Entered issue_flushreq: start %d, end %d\n", start, end);
flushreq = (ioreq_event *) getfromextraq();
flushreq->devno = startatom->devno;
flushreq->blkno = start;
flushreq->bcount = end - start + 1;
flushreq->busno = startatom->busno;
flushreq->slotno = startatom->slotno;
flushreq->type = IO_ACCESS_ARRIVE;
flushreq->flags = 0;
flushwait = (ioreq_event *) getfromextraq();
flushwait->type = IO_REQUEST_ARRIVE;
flushwait->devno = flushreq->devno;
flushwait->blkno = flushreq->blkno;
flushwait->bcount = flushreq->bcount;
flushwait->next = waiter->req;
flushwait->prev = NULL;
if (waiter->req) {
waiter->req->prev = flushwait;
}
waiter->req = flushwait;
waiter->accblkno = -1;
if (!waiting) {
cache_waitfor_IO(cache, 1, waiter, flushwait);
}
waiter->accblkno = -1;
cache->stat.destagewrites++;
cache->stat.destagewriteatoms += end - start + 1;
cache_get_read_lock_range(cache, start, end, startatom, waiter);
// fprintf (outputfile, "Issueing dirty block write-back: blkno %d, bcount %d, devno %d\n", flushreq->blkno, flushreq->bcount, flushreq->devno);
(*cache->issuefunc)(cache->issueparam, flushreq);
return(1);
}
static int cache_flush_cluster (cache_def *cache, int devno, int blkno, int linecnt, int dir)
{
cache_atom *line = NULL;
int lastclean = 0;
int writelocked;
ASSERT1((dir == 1) || (dir == -1), "dir", dir);
while (linecnt <= cache->flush_maxlinecluster) {
if (line == NULL) {
line = cache_find_atom(cache, devno, (blkno+dir));
if ((line == NULL) || (lastclean)) {
break;
}
linecnt++;
continue;
}
writelocked = cache_atom_iswritelocked(cache, line);
if ((line->state & CACHE_DIRTY) && (!writelocked)) {
line->state &= ~CACHE_DIRTY;
lastclean = 0;
blkno = line->lbn;
} else if ((writelocked) || (!(line->state & CACHE_VALID))) {
break;
} else {
lastclean = 1;
}
line = (dir == 1) ? line->line_next : line->line_prev;
}
return(blkno);
}
static int cache_initiate_dirty_block_flush (cache_def *cache, cache_atom *dirtyline, cache_event *allocdesc)
{
cache_atom *dirtyatom = 0;
int dirtyend = 0;
int dirtystart = -1;
cache_atom *tmp = dirtyline;
int flushcnt = 0;
// fprintf (outputfile, "Entered cache_initiate_dirty_block_flush: %d\n", dirtyline->lbn);
while (tmp) {
int writelocked = cache_atom_iswritelocked(cache, tmp);
if ((tmp->state & CACHE_DIRTY) && (!writelocked)) {
tmp->state &= ~CACHE_DIRTY;
if (dirtystart == -1) {
dirtyatom = tmp;
dirtystart = tmp->lbn;
}
dirtyend = tmp->lbn;
} else if ((dirtystart != -1) && ((!(tmp->state & CACHE_VALID)) || (writelocked))) {
if ((cache->flush_maxlinecluster > 1) && (dirtystart == dirtyline->lbn)) {
dirtystart = cache_flush_cluster(cache, dirtyatom->devno, dirtystart, 1, -1);
}
if (cache_issue_flushreq(cache, dirtystart, dirtyend, dirtyatom, allocdesc) == 0) {
return(flushcnt);
}
dirtystart = -1;
flushcnt++;
}
tmp = tmp->line_next;
}
if (dirtystart != -1) {
int linesize = max(cache->linesize, 1);
int linecnt;
if ((cache->flush_maxlinecluster > 1) && (dirtystart == dirtyline->lbn)) {
dirtystart = cache_flush_cluster(cache, dirtyatom->devno, dirtystart, 1, -1);
}
linecnt = 1 + ((dirtyline->lbn - dirtystart) / linesize);
if ((linecnt < cache->flush_maxlinecluster) && (dirtyend == (dirtyline->lbn + linesize -1))) {
dirtyend = cache_flush_cluster(cache, dirtyatom->devno, dirtyend, linecnt, 1);
}
flushcnt += cache_issue_flushreq(cache, dirtystart, dirtyend, dirtyatom, allocdesc);
}
// fprintf (outputfile, "flushcnt %d\n", flushcnt);
return(flushcnt);
}
static cache_event *cache_get_flushdesc()
{
cache_event *flushdesc = (cache_event *) getfromextraq();
flushdesc->type = CACHE_EVENT_SYNC;
flushdesc->donefunc = &disksim->donefunc_cachemem_empty;
flushdesc->req = NULL;
return(flushdesc);
}
static void cache_cleanup_flushdesc (cache_event *flushdesc)
{
if (flushdesc->req) {
if (flushdesc->req->next == NULL) {
flushdesc->accblkno = flushdesc->req->blkno;
}
} else {
addtoextraq((event *) flushdesc);
}
}
/* Not currently dealing with case of two-handed flushing. Easiest way to */
/* do this will be to allocate the cache as one big chunk of memory. Then,*/
/* use the addresses of cache_atoms rather than the pointers to traverse. */
static void cache_periodic_flush (timer_event *timereq)
{
cache_def *cache = (cache_def *) timereq->ptr;
int segcnt = (cache->replacepolicy == CACHE_REPLACE_SLRU) ? cache->numsegs : 1;
int i, j;
cache_atom *line;
cache_atom *stop;
cache_atom *tmp;
cache_event *flushdesc = cache_get_flushdesc();
int flushcnt = 0;
int startit;
for (i=0; i<=cache->mapmask; i++) {
for (j=0; j<segcnt; j++) {
line = cache->map[i].lru[j];
stop = line;
startit = 1;
while ((startit) || (line != stop)) {
startit = 0;
tmp = line;
while (tmp) {
if (tmp->state & CACHE_DIRTY) {
flushcnt += cache_initiate_dirty_block_flush(cache, tmp, flushdesc);
}
tmp = tmp->line_next;
}
line = line->lru_next;
};
}
}
cache_cleanup_flushdesc(flushdesc);
timereq->time += cache->flush_period;
addtointq((event *)timereq);
// fprintf (outputfile, "%f: cache_periodic_flush, %d flushes started\n", simtime, flushcnt);
}
static void cache_idletime_detected (void *idleworkparam, int idledevno)
{
cache_def *cache = idleworkparam;
cache_atom *line = cache_get_replace_startpoint(cache, 0);
cache_atom *stop = line;
cache_atom *tmp;
int segcnt = (cache->replacepolicy == CACHE_REPLACE_SLRU) ? cache->numsegs : 1;
int i;
cache_event *flushdesc;
int startit;
if (ioqueue_get_number_in_queue((*cache->queuefind)(cache->queuefindparam, idledevno))) {
return;
}
flushdesc = cache_get_flushdesc();
flushdesc->type = CACHE_EVENT_IDLESYNC;
for (i=0; i<segcnt; i++) {
if (i) {
line = cache->map[0].lru[i];
stop = line;
}
startit = 1;
while ((startit) || (line != stop)) {
startit = 0;
if (line->devno == idledevno) {
tmp = line;
while (tmp) {
if (tmp->state & CACHE_DIRTY) {
(void)cache_initiate_dirty_block_flush(cache, tmp, flushdesc);
if (flushdesc->req) {
goto cache_idletime_detected_idleused;
}
}
tmp = tmp->line_next;
}
}
line = line->lru_next;
}
}
cache_idletime_detected_idleused:
cache_cleanup_flushdesc(flushdesc);
}
static void cache_unmap_line (cache_def *cache, cache_atom *line, int set)
{
cache_atom *tmp;
if (line->lru_next) {
cache_remove_from_lrulist(&cache->map[set], line, (line->state & CACHE_SEGNUM));
}
if (cache->linesize == 0) {
while ((tmp = line)) {
line = line->line_next;
tmp->line_next = NULL;
tmp->line_prev = NULL;
cache_remove_entry_from_hash(cache, tmp);
cache_add_to_lrulist(&cache->map[set], tmp, CACHE_SEGNUM);
}
} else {
cache_add_to_lrulist(&cache->map[set], line, CACHE_SEGNUM);
while (line) {
cache_remove_entry_from_hash(cache, line);
line = line->line_next;
}
}
}
static int cache_replace (cache_def *cache, int set, cache_event *allocdesc)
{
int numwrites;
cache_atom *line;
cache_atom *tmp;
cache_atom *stop;
int dirty = FALSE;
int locked = FALSE;
cache_event *flushdesc = (cache->allocatepolicy & CACHE_ALLOCATE_NONDIRTY) ? NULL : allocdesc;
if (cache->map[set].freelist) {
return(0);
}
if ((line = cache_get_replace_startpoint(cache, set)) == NULL) {
/* All lines between ownership */
cache_replace_waitforline(cache, allocdesc);
return(-1);
}
stop = line;
cache_replace_loop_continue:
if (locked | dirty) {
line = (cache->replacepolicy == CACHE_REPLACE_LIFO) ? line->lru_prev : line->lru_next;
}
if (line == stop) {
if (locked) {
if ((flushdesc) && (cache->allocatepolicy & CACHE_ALLOCATE_NONDIRTY)) {
cache_cleanup_flushdesc(flushdesc);
}
cache_replace_waitforline(cache, allocdesc);
return(-1);
}
}
locked = FALSE;
tmp = line;
while (tmp) {
if ((locked = (tmp->readlocks || tmp->writelock))) {
goto cache_replace_loop_continue;
}
tmp = tmp->line_next;
}
dirty = FALSE;
tmp = line;
while (tmp) {
if ((dirty = tmp->state & CACHE_DIRTY)) {
if (flushdesc == NULL) {
flushdesc = cache_get_flushdesc();
}
numwrites = cache_initiate_dirty_block_flush(cache, tmp, flushdesc);
if (cache->allocatepolicy & CACHE_ALLOCATE_NONDIRTY) {
goto cache_replace_loop_continue;
} else {
return(numwrites);
}
}
tmp = tmp->line_next;
}
cache_unmap_line(cache, line, set);
return(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -