/* file: xread.c * author: Robert S. Laramee * class: cs720/820 * date started: 11 Mar 98 * date "finished": 09 Apr 98 * project: assignment 3 * description: This project develops a buffer cache mechanism to * store copies of recently read blocks of disk files. * All read operations are block oriented. The block size is 512 bytes. * When a read of file data is to be performed, the buffer cache is searched * first for the data. A hash table is used to locate these blocks. If the * desired block is not located in the cache, then the data is read from the * disk. A copy of this data is stored in the cache. The cache uses the * Least Recently Used (LRU) page replacement policy. * * argv[0] = xread -name of program */ #include/* for printf(), scanf(), fopen(), fclose etc. */ #include /* for strlen(), strncopy() */ #include /* for realpath() */ #include /* for strerror(), errno */ #include /* for open(), lseek() */ #include /* for open() */ #include /* for open() */ #include /* for read(), write(), lseek() */ #include /* for sigemptyset(), sigfillset() etc. */ #include /* for setitimer(), ITIMER_REAL, etc */ #include /* for sigsetjmp() and siglongjmp() */ #include "cache.h" /* contains definitions of cache data structures */ #define SUCCESS 1 /* for get_block_for_read() */ static volatile sig_atomic_t jump_ok = 0; static sigjmp_buf jump_buffer; /* notify the user that they pressed ^c (a dummy funtion) */ void control_c() { //printf("\n ^c pressed, continue \n"); } /* notify the user that the system has been idle for 30 seconds */ char printbuffer[]= "\n System idle for 30 seconds***** \n"; void send_notification() { write(STDOUT_FILENO, printbuffer, sizeof(printbuffer)); if (jump_ok == 0) return; fflush(stdin); fflush(stdout); siglongjmp(jump_buffer, 1); } int main(int argc, char *argv[]) { int i, begin_byte, end_byte;/* print only from begin_byte to end_byte */ int seek_address=0; /* seek address (byte offset 0) */ int num_bytes=0; /* number of bytes (not blocks) to be read */ int num_blocks=0; /* number of blocks to be read */ int start_bollock_num=0; /* first block to check for in cache */ int end_bollock_num=0; /* last block to check for in cache */ int current_bollock_num=0; /* last block to check for in cache */ char data_file[FILE_NAME_SIZE]; int from_fd; /* input file descriptor */ CACHE_PKT *free_pkt; /* a pointer to a free packet from free list */ CACHE_PKT *temp; sigset_t blocked_set, original_set; struct sigaction sigalarm_action, controlc_action; struct itimerval timer_value; /* check for valid command line arguments */ if (argc != 1) { fprintf(stderr, "\n Incorrect usage: e.g. % xread \n"); exit(EXIT_FAILURE); } /* install SIGINT (control c) signal handler */ controlc_action.sa_handler = control_c; controlc_action.sa_flags = 0; sigemptyset(&controlc_action.sa_mask); if (sigaction(SIGINT, &controlc_action, NULL) == -1) perror("\n Could not set up SIGINT handler for control_c() action \n"); /* install the SIGALARM signal handler */ sigalarm_action.sa_handler = send_notification; sigalarm_action.sa_flags = SA_RESTART; sigemptyset(&sigalarm_action.sa_mask); if (sigaction(SIGALRM, &sigalarm_action, NULL) == -1) perror("\n Could not set up SIGALARM handler for SIGALARM action \n"); /* set the UNIX real time interval timer for 30-second intervals * the ITIMER_REAL decerements in real time and generate a SIGALARM signal * when it expires */ timer_value.it_interval.tv_sec = 30; /* value to reload into timer */ timer_value.it_interval.tv_usec = 0; timer_value.it_value.tv_sec = 30; /* time until next expiration */ timer_value.it_value.tv_usec = 0; /* allocate memory space for cache and link cache packets on free list */ init_it(); while (1) { if (sigsetjmp(jump_buffer, 1)) fprintf(stderr, "Returned to main loop due to ^c or SIGALRM \n"); jump_ok = 1; if ((setitimer(ITIMER_REAL, &timer_value, NULL)) == -1) perror("\n Could not install interval timer \n"); /* suspend the process until the SIGINT signal given by ^c occurs */ sigemptyset(&blocked_set); sigprocmask(SIG_SETMASK, NULL, &original_set); sigaddset(&blocked_set, SIGINT); sigprocmask(SIG_BLOCK, &blocked_set, NULL); sigdelset(&blocked_set, SIGINT); sigsuspend(&blocked_set); printf("please enter file name (e.g. file.dat) > "); if(scanf("%s", data_file) != 1) { fprintf(stderr, "error reading file name \n"); exit(EXIT_FAILURE); } printf("please enter seek address (e.g. 1000) > "); if(scanf("%d", &seek_address) != 1) { fprintf(stderr, "error reading seek address \n"); exit(EXIT_FAILURE); } printf("please enter number of bytes (e.g. 3000) > "); if(scanf("%d", &num_bytes) != 1) { fprintf(stderr, "error reading number of bytes \n"); exit(EXIT_FAILURE); } if ((seek_address < 0) || (num_bytes < 0)) { printf("\n Invalid input (e.g. file.dat 100 1050). Try again \n"); break; } /* compute starting block and ending block */ num_blocks = num_bytes/BLOCK_SIZE + 1; start_bollock_num = seek_address/BLOCK_SIZE; end_bollock_num = start_bollock_num + num_blocks - 1; begin_byte = seek_address % BLOCK_SIZE; end_byte = num_bytes % BLOCK_SIZE; for(current_bollock_num = start_bollock_num; current_bollock_num <= end_bollock_num; current_bollock_num++) { if((get_block_for_read(data_file, (current_bollock_num % HASH_SIZE), &free_pkt)) != SUCCESS) { /* copy the file name */ strncpy(free_pkt->file_name, data_file, FILE_NAME_SIZE); /* read bytes from disk */ if((from_fd = open(data_file, O_RDONLY)) == -1) { fprintf(stderr, "Error cannot open %s: %s \n" , data_file, strerror(errno)); exit(EXIT_FAILURE); } if (lseek(from_fd, current_bollock_num * BLOCK_SIZE, SEEK_SET) != (current_bollock_num * BLOCK_SIZE)) { fprintf(stderr, "Error with offset in file %s: %s \n" , data_file, strerror(errno)); exit(EXIT_FAILURE); } if (read(from_fd, free_pkt->file_data, BLOCK_SIZE) != BLOCK_SIZE) { fprintf(stderr, "Error reading file %s: %s \n" , data_file, strerror(errno)); exit(EXIT_FAILURE); } close(from_fd); put_block_in_cache(data_file, (current_bollock_num % HASH_SIZE), &free_pkt); } /* end if get_block_for_read() */ /* print LRU list to stdout */ printf("--> LRU blocks: \n"); /* temp = cp_lru_head; while ( temp->c_lru_prev != NULL) { printf("%c%d ", temp->file_name[0], temp->bollock_num); temp = temp->c_lru_prev; } printf("%c%d (tail) \n", cp_lru_tail->file_name[0] , cp_lru_tail->bollock_num); */ /* prints out whole last block */ temp = cp_lru_head; while ( temp->c_lru_prev != NULL) { for (i=0; i < BLOCK_SIZE; i++) { printf("%c", temp->file_data[i]); } printf("\n"); temp = temp->c_lru_prev; } for (i=begin_byte; i < BLOCK_SIZE; i++) { printf("%c", cp_lru_tail->file_data[i]); } printf("\n"); } /* end for current_bollock_num */ } /* end while() */ free(cp_free_list); /* no memory leaks here */ } /* end main() */