-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.c
More file actions
712 lines (515 loc) · 18.9 KB
/
main.c
File metadata and controls
712 lines (515 loc) · 18.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
/*
Authors - Rajdeep Pinge, Aditya Joglekar
March-April, 2017
*/
/* Code Reference:
Basic code given by University of Notre Dame for project on virtual memory in their cse30341 operating systems course.
link to the project description: http://www3.nd.edu/~dthain/courses/cse30341/spring2017/project5/
link to the source code: http://www3.nd.edu/~dthain/courses/cse30341/spring2017/project5/source/
*/
/*
Main program for the virtual memory project.
Make all of your modifications to this file.
You may add or rearrange any code or data as you need.
The header files page_table.h and disk.h explain
how to use the page table and disk interfaces.
*/
#include "page_table.h"
#include "disk.h"
#include "time.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// Global Variables
int nframes; // stores total number of frames
int *is_frame_occup_struc = NULL; // pointer to free frame data struc
int *frame_holds_what = NULL; // array to maintain which frame holds which physical page
char *PRAlgoToUse; // store which page replacement algorithm to use
char *virtmem = NULL;
char *physmem = NULL;
struct disk *disk = NULL; // global pointer to disk
// data struct for fifo
int oldest_page = 0;
int newest_page = 0;
int *fifo_page_queue = NULL;
// data struct for LRU
struct page_node
{
int page;
struct page_node *nextPage;
}*head, *tail, *currPage, *newPage, *prevPage;
// Variables used to track statistics to print at the end
int pageFaults = 0;
int diskReads = 0;
int diskWrites = 0;
// function definitions
int findnset_free_frame(int *is_frame_occup_struc,int nframes);
void random_pra( struct page_table *pt, int page );
void fifo_pra( struct page_table *pt, int page);
void custom_pra( struct page_table *pt, int page);
void replace_page( struct page_table *pt, int page, int frame_no_toremove );
// function definitions for standard programs to run for testing
void scan_program( char *data, int length );
void sort_program( char *data, int length );
void focus_program( char *data, int length );
void rearrange_page_list(int i);
static int compare_bytes( const void *pa, const void *pb );
/* Some miscellaneous definitions
pt: pointer to page table
page: virtual page requested
*/
/**************** Version 1 of Page Fault Handler ***********************/
/* This function handles the page faults generated while accessing the memory
In this version We do nothing and simply terminate program when page fault happens
*/
/*
void page_fault_handler( struct page_table *pt, int page )
{
printf("page fault on page #%d\n",page);
exit(1);
}
*/
/**************** Version 2 of Page Fault Handler ***********************/
/* This function handles the page faults generated while accessing the memory
In this version Basic Page fault handling is done assuming number of pages = number of page-frames
*/
/*
void page_fault_handler( struct page_table *pt, int page )
{
printf("page fault on page #%d\n",page);
// map virtual page to physical page same as its own number
page_table_set_entry(pt, page, page, PROT_READ|PROT_WRITE);
}
*/
/**************** Version 3 of Page Fault Handler ***********************/
/* This function handles the page faults generated while accessing the memory
In this version the entry is first given only the read access and then is required write access is given
*/
/*
void page_fault_handler( struct page_table *pt, int page )
{
printf("page fault on page #%d\n",page);
int bits, mapframe;
// get entry in the page table
page_table_get_entry( pt, page, &mapframe, &bits );
// FAULT TYPE 1 - page not in virtual memory i.e. no protection bits set i.e. entry in page table is free
if( ((bits & PROT_READ) == 0) && ((bits & PROT_WRITE) == 0) && ((bits & PROT_EXEC) == 0) )
{
bits = bits|PROT_READ;
page_table_set_entry(pt, page, page, bits);
}
else if( ((bits & PROT_READ) == 1) && ((bits & PROT_WRITE) == 0) ) // FAULT TYPE 2 - page in virtual memory but does not have write permission
{
bits = bits|PROT_WRITE;
page_table_set_entry( pt, page, mapframe, bits );
}
// code for testing
// page_table_print(pt);
// printf("------------------------------------------------\n");
// exit(1);
}
*/
/**************** Version 4 of Page Fault Handler ***********************/
/* This function handles the page faults generated while accessing the memory
In this version the entry is first given only the read access and then is required write access is given
*/
void page_fault_handler( struct page_table *pt, int page )
{
// printf("page fault on page #%d\n",page); // print this virtual page is needed
pageFaults++; //increment page faults
// variables to store information about the page on which page fault has occured
int curr_bits;
int curr_frame;
// get the details of the page table entry corresponding to the page i.e. which frame does it hold and what are the permission bits
page_table_get_entry( pt, page, &curr_frame, &curr_bits );
// FAULT TYPE 1 - page not in virtual memory i.e. no protection bits set i.e. entry in page table is free
if ( ( (curr_bits & PROT_READ)==0 ) && ( (curr_bits & PROT_WRITE)==0 ) && ( (curr_bits & PROT_EXEC)==0 ) )
{
// find a free frame
int free_loc = findnset_free_frame(is_frame_occup_struc, nframes);
if (free_loc != -1) // have found a free frame. Bring page in that free frame
{
// set an entry of page in page table to free_loc frame location and give read access to it
page_table_set_entry(pt, page, free_loc, 0|PROT_READ);
// if fifo then need to store this frame in queue
if ( !strcmp(PRAlgoToUse, "fifo") )
{
fifo_page_queue[newest_page] = free_loc;
newest_page = (newest_page + 1) % nframes; // make it a circular queue
}
// if LRU then create a new node for this page in page list
if ( !strcmp(PRAlgoToUse, "custom") )
{
newPage = (struct page_node *) malloc(sizeof(struct page_node));
newPage->page = page;
newPage->nextPage = NULL;
if (head == NULL)
{
head = newPage;
tail = head;
}
else
{
tail->nextPage = newPage;
tail = newPage;
}
}
// Read data from disk at virtual address given by 'page' to physical memory frame
disk_read(disk, page, &physmem[free_loc*PAGE_SIZE]);
diskReads++;
// Store info that this page is held in which page frame.
// this frame holds this page, inverse of page table.
frame_holds_what[free_loc] = page;
}
else // all frames all full. Need to kick out some page from some frame. Will need page replacement algorithm. Call the page replacement algorithm given by the user.
{
if (!strcmp(PRAlgoToUse, "rand"))
{
random_pra(pt, page);
}
else if (!strcmp(PRAlgoToUse, "fifo"))
{
fifo_pra(pt, page);
}
else if (!strcmp(PRAlgoToUse, "custom"))
{
custom_pra(pt, page);
}
else //check for incorrect policy name
{
printf("use: virtmem <npages> <nframes> <rand|fifo|custom> <sort|scan|focus>\n");
exit(1);
}
}
}
else // FAULT TYPE 2 - page is in virtual memory but does not have necessary permissions
{
// dont have write permission but has read
if ( ( (curr_bits & PROT_WRITE)==0 ) && ( ( curr_bits & PROT_READ ) ==1 ) )
{
//OR curr_bits with PROC masks to get 1's at req positions.
page_table_set_entry( pt, page, curr_frame, curr_bits | PROT_WRITE);
}
else // has write but not read, may happen though unlikely
{
// OR with write permission
page_table_set_entry( pt, page, curr_frame, curr_bits | PROT_READ);
}
}
// For testing purpose
// page_table_print(pt);
}
int main( int argc, char *argv[] )
{
// check if all command line arguments are given
if(argc!=5) {
printf("use: virtmem <npages> <nframes> <rand|fifo|custom> <sort|scan|focus>\n");
return 1;
}
// derive details of the program to run from command line arguments
int npages = atoi(argv[1]);
nframes = atoi(argv[2]); //made global
PRAlgoToUse = argv[3]; // store which page replacement algorithm to use
const char *program = argv[4]; // store which testing program to run
is_frame_occup_struc = malloc(nframes * sizeof(int)); // allocate memory for structure storing frame occupation info
if(is_frame_occup_struc == NULL) {
printf("Error allocating space for structure storing frame occupation information!\n");
exit(1);
}
frame_holds_what = malloc(nframes * sizeof(int)); // allocate memory for array storing which frame holds which physical page
if(frame_holds_what == NULL) {
printf("Error allocating space for array storing info about which frame holds what page!\n");
exit(1);
}
// initialize the arrays to store frame status
for(int i=0; i < nframes; i++)
{
is_frame_occup_struc[i] = 0; // initially no frame is occupied
frame_holds_what[i] = 0; // initially no frame holds any physical page
}
// for fifo
if ( !strcmp(PRAlgoToUse, "fifo") )
{
fifo_page_queue = malloc(nframes * sizeof(int)); // allocate memory for fifo queue
if(fifo_page_queue == NULL) {
printf("Error allocating space for fifo page queue!\n");
exit(1);
}
}
// for LRU, initialize pointers to page list
if ( !strcmp(PRAlgoToUse, "custom") )
{
head = NULL;
tail = NULL;
currPage = head;
}
// try to create a disk
disk = disk_open("myvirtualdisk", npages);
// if 0 is returned then disk is not created. Therefore show error
if(!disk) {
fprintf(stderr,"couldn't create virtual disk: %s\n",strerror(errno));
return 1;
}
// try to cretae page table
struct page_table *pt = page_table_create( npages, nframes, page_fault_handler );
// if 0 is returned then page table is not created. Therefore show error
if(!pt) {
fprintf(stderr,"couldn't create page table: %s\n",strerror(errno));
return 1;
}
// get pointer to virtual memory from the page table
virtmem = page_table_get_virtmem(pt);
// get pointer to physical memory from the page table
physmem = page_table_get_physmem(pt);
// run appropriate program base on the command given by the user.
if(!strcmp(program,"sort")) {
sort_program(virtmem,npages*PAGE_SIZE);
} else if(!strcmp(program,"scan")) {
scan_program(virtmem,npages*PAGE_SIZE);
} else if(!strcmp(program,"focus")) {
focus_program(virtmem,npages*PAGE_SIZE);
} else {
fprintf(stderr,"unknown program: %s\n",argv[3]);
}
//printing final state of the page table
printf("--------------------------------------------------------------\n");
printf("Final Page Table\n");
page_table_print(pt);
printf("--------------------------------------------------------------\n");
//print results to user
printf("Disk Reads: %d\n", diskReads);
printf("Disk Writes: %d\n", diskWrites);
printf("Page Faults: %d\n", pageFaults);
// free the allocated resources
free(is_frame_occup_struc);
free(frame_holds_what);
// clean used resources
page_table_delete(pt);
disk_close(disk);
return 0;
}
/*
This function implements random page replacement algorithm when a page fault occurs
Algorithm: A random frame is chosen from available frames for replacement and the page that it holds is replaced
*/
void random_pra( struct page_table *pt, int page )
{
int frame_no_toremove= (int)lrand48()%nframes; // select a random frame to remove
replace_page(pt, page, frame_no_toremove);
}
/*
This function implements first in first out (fifo) page replacement algorithm when a page fault occurs
Algorithm: A page which came first is chosen for replacement.
*/
void fifo_pra( struct page_table *pt, int page )
{
int frame_no_toremove= fifo_page_queue[oldest_page]; // select first frame in the queue to replace
// NOTE here that page will be replaced only if all frames are full
// i.e. pointer to newest page location point actually at oldest page which is to be deleted
// shift oldest_page to next oldest_page so that this page is removed from the queue
oldest_page = (oldest_page + 1) % nframes;
replace_page(pt, page, frame_no_toremove);
// add the new page at the back of the queue and shift newest_page pointer so that it again points at the location of oldest page which is to be replaced next time.
fifo_page_queue[newest_page] = frame_no_toremove;
newest_page = (newest_page + 1) % nframes; // make it a circular queue
}
/*
This function implements Least Recently Used (LRU) page replacement algorithm when a page fault occurs
Algorithm: Here Linked List approach is used for implementing LRU.
1. If a new page arrives and if there is space in page table, then a new entry is made for that page at the end of the linked list.
2. If a page which is in linked list is referenced again, thenit is put at the end of the list.
3. If a new page is arrived and an old page is to be replaced, then the page at the front of the list is replaced and the new page is put at the back of the list.
*/
void custom_pra( struct page_table *pt, int page )
{
int frame_no_toremove = head->page; // select first page in the page list (which is least recenly used) for replacement.
// NOTE here that page will be replaced only if all entries in page table are full
// shift oldest_page to next oldest_page so that this page is removed from the queue
currPage = head;
head = head->nextPage;
tail->nextPage = currPage;
tail = currPage;
currPage->nextPage = NULL;
replace_page(pt, page, frame_no_toremove);
}
/* This function replaces the given page (according to page replacement policy) with the new page */
void replace_page( struct page_table *pt, int page, int frame_no_toremove )
{
int pageno_to_remove= frame_holds_what[frame_no_toremove]; // what page does the frame hold?
// get page table entry of that page
int frame_toremove;
int frame_toremove_bits;
page_table_get_entry(pt, pageno_to_remove, &frame_toremove, &frame_toremove_bits ); // info from page table
// if dirty i.e if it has write access, then have to write this page back in disk and then replace the page
if ( (frame_toremove_bits&PROT_WRITE)!=0 )
{
disk_write( disk,pageno_to_remove, &physmem[(frame_toremove)*PAGE_SIZE] ); // write back page to disk
diskWrites++;
}
page_table_set_entry( pt, pageno_to_remove, 0, 0); // 0's invalidate frame entry of previous page
page_table_set_entry( pt, page, (frame_toremove), 0|PROT_READ ); // set new page table entry with read permission
disk_read( disk, page, &physmem[(frame_toremove)*PAGE_SIZE] ); // Read data from disk at virtual address given by 'page' to physical memory frame
diskReads++;
// Store info that this page is held in which age frame.
// this frame holds this page, inverse of page table.
frame_holds_what[(frame_toremove)] = page; // the frame now contains this page.
}
/*
This function tries to find a free frame from the available frames
INPUT: Structure storing the occupation information of all frames, total frames
OUTPUT: Position of free frame if a free frame is found. Otherwise -1.
*/
int findnset_free_frame(int *is_frame_occup_struc, int nframes)
{
int i;
for (i=0;i<nframes;i++)
{
if (is_frame_occup_struc[i] == 0) // if a free frame is found
{
is_frame_occup_struc[i] = 1; // mark that frame as occupied for the new incoming page
return i; // return the position of frame
}
}
// if no free frame is found, the whole page table is full, return -1
return -1;
}
/*****************************************************************************************************************************/
/*****************************************************************************************************************************/
/************************* Code implementing testing programs for above functional code **************************************/
/* This function compares bytes and returns which one is greater
*/
static int compare_bytes( const void *pa, const void *pb )
{
int a = *(char*)pa;
int b = *(char*)pb;
if(a<b) {
return -1;
} else if(a==b) {
return 0;
} else {
return 1;
}
}
/* Standard program having random data access */
void focus_program( char *data, int length )
{
int total=0;
int i,j;
srand(3829);
for(i=0;i<length;i++) {
data[i] = 0; // write access to memory
// if LRU we need to re-arrange page list if the page is in the list
if ( !strcmp(PRAlgoToUse, "custom") )
{
// printf("page accessed: %d\n", i/PAGE_SIZE);
rearrange_page_list(i);
}
}
for(j=0;j<1000;j++) {
int start = rand()%length;
int size = 25;
for(i=0;i<1000;i++) {
int index = length-1-(start+rand()%(i+j+2))%length;
data[ index ] = rand(); // write access to memory
// if LRU we need to re-arrange page list if the page is in the list
if ( !strcmp(PRAlgoToUse, "custom") )
{
// printf("page accessed: %d\n", index/PAGE_SIZE);
rearrange_page_list(index);
}
}
}
for(i=0;i<length;i++) {
total += data[i]; // read access to memory
// if LRU we need to re-arrange page list if the page is in the list
if ( !strcmp(PRAlgoToUse, "custom") )
{
// printf("page accessed: %d\n", i/PAGE_SIZE);
rearrange_page_list(i);
}
}
// printf("focus result is %d\n",total);
}
/* Standard program having data access according to a sorted order */
void sort_program( char *data, int length )
{
int total = 0;
int i;
srand(4856);
for(i=0;i<length;i++) {
data[i] = rand();
printf("page accessed: %d\n", i/PAGE_SIZE);
}
qsort(data,length,1,compare_bytes);
for(i=0;i<length;i++) {
total += data[i];
printf("page accessed: %d\n", i/PAGE_SIZE);
}
// printf("sort result is %d\n",total);
}
/* Standard program with sequential data access */
void scan_program( char *cdata, int length )
{
unsigned i, j;
unsigned char *data = cdata;
unsigned total = 0;
for(i=0;i<length;i+=PAGE_SIZE) {
// for(i=0;i<length;i++) {
data[i] = i%256;
if ( !strcmp(PRAlgoToUse, "custom") )
{
printf("page accessed: %d\n", i/PAGE_SIZE);
rearrange_page_list(i);
}
}
for(j=0;j<5;j++) {
for(i=0;i<length;i+=PAGE_SIZE) {
// for(i=0;i<length;i++) {
total += data[i];
if ( !strcmp(PRAlgoToUse, "custom") )
{
printf("page accessed: %d\n", i/PAGE_SIZE);
rearrange_page_list(i);
}
}
}
// printf("scan result is %d\n",total);
}
/* This function re-arranges the page list by removing existing page from the list and putting it at the tail of the list.
This is a requirement for LRU page Replacement algorithm
*/
void rearrange_page_list(int i)
{
int page_accessed = i/PAGE_SIZE;
//check if page in list. If page not found then there is already a fault which will be handled
// if page found the put it at tail i.e. most recently used
prevPage = NULL;
currPage = head;
while ( currPage != NULL )
{
if (currPage->page == page_accessed)
{
// remove page and put and tail
if (currPage != tail)
{
if(currPage != head)
{
prevPage->nextPage = currPage->nextPage;
currPage->nextPage = tail->nextPage;
tail->nextPage = currPage;
tail = currPage;
}
else
{
head = head->nextPage;
tail->nextPage = currPage;
currPage->nextPage = NULL;
}
}
break;
}
prevPage = currPage;
currPage = currPage->nextPage;
}
}