/* VIRT2.ABC ** ** REV 1281.041 */ #include #include #include "virt.h" INTERN COUNT LAST_BLK = 0; INTERN LONG time = 0L; INTERN BITS tmps[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* FIND_BLK(index, blk) returns a pointer to the page descriptor holding blk, ** or a NULL if the blk isn't in memory. index selects which virtual array ** root segment is involved. */ PAGE_PTR find_blk(index, blk) FAST COUNT index; FAST COUNT blk; { FAST PAGE_PTR p; IMPORT struct rt ROOT[]; p = ROOT[index].frst_page; while ( p != NULL ) { if ( p->blk_num == blk ) break; else p = p->nxt_page; } return(p); } /* GET_LRU(index) finds the least recently used page and returns ** a pointer to that page. index selects the correct virtual array ** root segment. */ PAGE_PTR get_lru(index) FAST COUNT index; { IMPORT LONG ticks(); FAST PAGE_PTR lru; FAST PAGE_PTR p; INTERN LONG time; IMPORT struct rt ROOT[]; LONG diff,d; p = lru = ROOT[index].frst_page; time = ticks(); diff = time - p->acc_time; while ( (p = p->nxt_page) != NULL ) { d = time - p->acc_time; if ( d > diff ) { diff = d; lru = p; } } return(lru); } /* SWAP(index, page, blk) writes the current data contents of ** the page and readsin the new block blk. A completion routine is ** called to set the global variable IOFLAG for both the swapin. ** The tricky part here is the return from swap() without waiting for ** the completion routine to be called in. The function calling ** swap() is responsible for checking on the status of IOFLAG. While ** IOFLAG is set to YES the data transfere has not been completed. */ VOID swap(index,page,blk) FAST COUNT index; FAST PAGE_PTR page; COUNT blk; { IMPORT COUNT bug; IMPORT LONG ticks(); IMPORT VOID iodone(); IMPORT PAGE_PTR get_lru(), find_blk(); IMPORT COUNT IOFLAG, err_index; COUNT code; IMPORT struct rt ROOT[]; IOFLAG = NO; if ( page->update == YES ) { IOFLAG = YES; if ( (code =cwrite(ROOT[index].chan, page->blk_num, page->data,\ BLK_W_SIZE, iodone)) < 0 ) { code &= BYTMASK; err_index = index; trouble(WRITERR); } } page->update = NO; page->blk_num = blk; while (IOFLAG == YES) ; IOFLAG = YES; if ( (code = cread(ROOT[index].chan, blk, page->data,\ BLK_W_SIZE, iodone)) < 0 ) { code &= BYTMASK; err_index = index; trouble(READERR); exit(NO); } } /* TICKS() returns a long value which is the number of 1/60th second ticks ** since midnight. */ LONG ticks() { LOCAL LONG time; emt375((021<<8),&time); return(time); } /* VREAD(array_index, index) is one of two main entries into the package. ** all data read from a virtual array comes thru VREAD(). array_index ** selects which virtual array is being processed. index is a long integer ** value expressing the location of the item in the virtual array. ** VREAD() first calculated the block number from the index and the known ** size of the data item stored in the array. It then uses FIND_BLK() ** to see if it is in memory. If that block is not in memory then ** GET_LRU() is used to find the least recently used block allocated ** to this virtual array which is then swapped out to disk by SWAP(). ** After SWAP() returns VREAD() updates the attributes of the page, then ** waits for the completion routine to reset the IOFLAG. ** ** VREAD returns a pointer into the data array offset bytes from the ** start of the array. This pointer may then be coerced into being ** the proper type by the calling program. Note that currently there ** aren't any alignment problems, however using this routine to ** access arbitrary files could result in floats or doubles that ** start at odd addresses. */ TEXT *vread(array_index, index) FAST COUNT array_index; LONG index; /* location of data element in array */ { IMPORT BOOL IOFLAG; IMPORT LONG ticks(); IMPORT PAGE_PTR find_blk(), get_lru(); IMPORT struct rt ROOT[]; FAST COUNT blk; FAST PAGE_PTR p; BYTES offset; TEXT *q; LONG temp; IMPORT BOOL bug; temp = index * (long)ROOT[array_index].size; blk = (int)(temp /(long)BLK_SIZE); if ( (p = find_blk(array_index, blk)) == NULL ) swap(array_index, (p = get_lru(array_index)), blk); offset = (unsigned)(temp % (long)BLK_SIZE); p->acc_time = ticks(); p->blk_num = blk; q = &(p->data[0]) + offset; while (IOFLAG) ; return ( q ); } /* VWRITE(array_index, index, data) is the second major access method ** for the virtual array package. It is responsible for writing new ** data into the file. ** array_index selects which virtual array is involved and selects the ** appropriate attributes. index is a long value which points to the ** item element in the virtual array. Data is a pointer to the data ** element to be written. ** VWRITE() starts as VREAD() and calculates the block number of ** the data element to be stored. It then searches for that element ** in the linked list of pages using FIND_BLK(). If the element is ** not in memory then GET_LRU() finds the least recently used page ** and passes that to SWAP(). The offset into the block is then ** calculated and a pointer assigned to that location. The actual ** transfere is done one byte at a time using the pointers into the ** storage cell array and the pointer passed to VWRITE(). */ VOID vwrite(array_index, index, data) FAST COUNT array_index; LONG index; /* array position for data */ TEXT *data; { IMPORT BOOL IOFLAG; IMPORT COUNT error; IMPORT LONG ticks(); IMPORT PAGE_PTR find_blk(), get_lru(); IMPORT struct rt ROOT[]; FAST COUNT blk; FAST PAGE_PTR p; COUNT i; BYTES offset; TEXT *q; LONG temp; temp = index * (long)ROOT[array_index].size; blk = temp / (long)BLK_SIZE; if ( (p = find_blk(array_index, blk)) == NULL ) swap(array_index, (p = get_lru(array_index)), blk); offset = (unsigned)( temp % (long)BLK_SIZE); p->acc_time = ticks(); p->update = YES; p->blk_num = blk; q = offset + &(p->data[0]); while (IOFLAG) ; /* wait for I/O to complete */ { FAST COUNT i; for ( i = 0; i < ROOT[array_index].size; i++) { *q++ = *data++; } } }