I have a server and a client. The client can send request like ADD to list by entering ADD:Joe:2 it should add to list. Key = Joe Value =2.
I'm trying to ADD a key:value into a linked list that uses a buffer ring of max 5 elements. When the linked list reaches the max size of elements(5) and a new key:value is entered, the oldest element is overwritten with the new element.
Every time I adding it seems to add fine, but when the max size is reached and tries to delete the first KEY:VALUE it crashes.
Add to LIST:
void push_item(struct item** Front,struct item** Rear,char *new_key,char *new_value,int newsockfd)
{
char buffer [50] = {0};
struct item* new_node = malloc(sizeof(struct item));
strcpy(new_node->value,new_value);
strcpy(new_node->key,new_key);
//new_node->next = NULL;
if(p_size==5)
{
char *itemVal;
char *itemKey;
/* if queue is empty */
if ( *Front == NULL )
{
printf ( "List is empty");
}
else
{
if (*Front == *Rear)
{
strcpy(itemVal,(*Front)->value);
strcpy(itemKey,(*Front)->key);
free(*Front);
*Front = NULL ;
*Rear = NULL ;
}
else
{
//delete node
new_node = *Front;
strcpy(itemVal,new_node->value);
strcpy(itemKey,new_node->key);
*Front=(*Front)->next;
(*Rear)->next=*Front;
free(new_node);
}
printf("Node deleted Key: %s Value: %s",itemKey,itemVal);
}
}
else
{
*Rear=new_node;
(*Rear)->next=new_node;
if(*Front==NULL)
{
(*Front)=new_node;
p_size++;
}
else
{
(*Rear)->next=new_node;
p_size++;
printf("Elements in List: %d\n",p_size);
}
}
sprintf(buffer,"Added");
int num_bytes = write(newsockfd, buffer, strlen(buffer));
if (num_bytes < 0)
{
fprintf(stderr, "Thread ERROR: write() failed\n");
}
}
Server:
struct item *Front = NULL;
struct item *Rear = NULL;
char buffer[BUFFER_SIZE] = {0};
void* handle_client(void *socket)
{
int newsockfd = (int)socket;
pthread_t thread_id = pthread_self();
printf("----------\nThread %lu using socket %x\n", (unsigned long)thread_id, newsockfd);
/* Start communicating */
int num_bytes = read(newsockfd, buffer, BUFFER_SIZE-1);
if (num_bytes < 0) {
fprintf(stderr, "Thread %lu ERROR: read() failed\n", (unsigned long)thread_id);
return NULL;
}
printf("Thread %lu recieved request\n", (unsigned long)thread_id);
if(strncmp(buffer,"ADD",3)==0)
{
char* key = buffer+4;
int charIndex;
char *new_value = strchr(buffer+4 , ':')+1;
charIndex = (int)(new_value-buffer)-1;
buffer[charIndex] = '\0';
push_item(&Front,&Rear,key,new_value,newsockfd);
printf("Value:%s Key:%s\n",new_value,key);
}
EDIT:
Images of CMD :
Left cmd is the client and the right one is the server
The p_size represents the current number of elements in the linked list.
It Crashes after it enters the if condition P_size == 5.
When looking on the push_item() function for the problem located in case of if(p_size==5), the error is when writing data of the node to be removed.
Error 1 - temporary itemVal and itemKey are declared as char * but never allocated to an array.
// To do
strcpy(itemVal,(*Front)->value);
strcpy(itemKey,(*Front)->key);
// or
strcpy(itemVal,new_node->value);
strcpy(itemKey,new_node->key);
Both char *itemVal; and char *itemKey; shall be allocated.
// Local variables (STR_SIZE has to be adjusted)
char itemVal[STR_SIZE+1];
char itemKey[STR_SIZE+1];
Warning 1 - but solving that issue will reveal a malfunction in the Ring Buffer algorithm when using linked-list.
In the push_item() function, the writing/push pointer *Front and
the reading/pop pointer *Rear are managed independently. When the
Ring Buffer is full (if(p_size==5)) the new item is deleted instead
of the oldest one.
Related
I have to use a buffer of size max_cache_req_len to read in the value received from mq_receive. Here is my code that is receiving a value from shared memory and then placing it on a queue:
size_t received_bytes = 0;
char buffer[MAX_CACHE_REQUEST_LEN];
received_bytes = 0;
memset(&buffer, 0, MAX_CACHE_REQUEST_LEN);
received_bytes = mq_receive(mq, buffer, MAX_CACHE_REQUEST_LEN, NULL);
if (received_bytes != -1)
{
item_type *item = malloc(sizeof(item_type));
item->path = buffer;
pthread_mutex_lock(&queue_lock);
steque_enqueue(&queue, item);
pthread_cond_signal(&queue_cond);
pthread_mutex_unlock(&queue_lock);
}
Here is my code that is taking the item off the queue, and placing it into a char* value. When I print the path, I get "".
void *worker(void *arg)
{
item_type *new_item;
char *path;
int fd;
while (1)
{
pthread_mutex_lock(&queue_lock);
while (steque_isempty(&queue) == 1)
pthread_cond_wait(&queue_cond, &queue_lock);
new_item = steque_pop(&queue);
path = new_item->path;
free(new_item);
new_item = NULL;
pthread_mutex_unlock(&queue_lock);
fd = simplecache_get(path);
sleep(cache_delay);
printf("%d\n", fd);
printf("%s\n", path);
// MAKE WORKER THREAD TAKE
if (fd == CACHE_FAILURE)
{
}
else
{
}
}
}
If I hardcode something like:
item->path = "buffer";
Then it prints buffer from within my worker function. This is a multithreaded application, I am just unsure what to do with my char[size] array to transform it into a char* and allow it to transfer.
Nutshell:
(char*)&char[size] queued -> queue turns it into a void* -> popped off queue, turned into a char* and value is lost
My first problem is that I have problem to make that for loop and implement it into the code and somehow finish my program.
My second problem is compiler showing problem in this: memset(database,0,SIZE*sizeof(struct student)); type specifier missing, defaults to 'int'
And at the end of program i have problem with memcpy(database.name,name,size_of_name); member reference base type 'struct student [100]' is not a structure or union
There are my structure and functions:
#define SIZE 100
struct student {
char name[SIZE];
int votes;
};
struct student database[SIZE];
memset(database,0,SIZE*sizeof(struct student));
int size = 0;
int find_student(struct student* students,int size, const char* name){
// for loop,which take all entries in database
// if it find same name, then reutrn his index
//otherwise reuturn -1;
int i;
for(i=0; i<SIZE;i++){
// how to make that loop
}
return -1;
}
int compare(const void* p1, const void* p2){
struct student* s1 = (struct student*)p1;
struct student* s2 = (struct student*)p2;
// s1->votes
// s1->name
return 0;
}
And there is my code what I already did( sorry for my grammar):
char line[SIZE];
memset(line,0,SIZE);
char* r = fgets(line,SIZE,stdin);
if (r == NULL){
printf("End of input");
return (-1);
}
char* end = NULL;
int value = strtol(line,&end,10);
if (value == 0){
printf("Convertion was not sucessful");
return (-1);
}
// helping array
char name[SIZE];
// set on zero
memset(name,0,SIZE);
// get begining of a name = one position after space
char* beginning_name = end + 1;
// Size of name is number of signs to end of string
// minus end of line
int size_of_name = strlen(beginning_name) - 1;
if (size_of_name > 0){
// copy
memcpy(name,beginning_name,size_of_name);
// At the end is saved string with name
// without end of line and with zero at the end
}
else {
// failed to read a name
printf("Failed to read a name");
return (-1);
}
int id = find_student(database,size,name);
if (id< 0){
// copy it to last place in array
memcpy(database.name,name,size_of_name);
// increase number of entries
size+=1;
}
else {
// there I need add to votes,something like votes++;
}
}
Sorry for formating but I am new at stackoverflow.
I'm trying to implement the producer consumer with conditional variables so I can learn about synchronization. I'm using the github to guide me and solved some seg faults but now it seems that my consumer never gets executed or is stuck in deadlock. I'm not sure what could be the error. I have included printf statements in the producer to execute everytime it runs and it completes producing any string in messages.txt less than 5. The consumer though does not and is stuck in a deadlock.
#define max 5
int par = 0;
// Data structure for queue
struct queue
{
char *items; // array to store queue elements
int maxsize; // maximum capacity of the queue
int front; // front points to front element in the queue (if any)
int rear; // rear points to last element in the queue
int size; // current capacity of the queue
pthread_mutex_t mutex; // needed to add/remove data from the buffer
pthread_cond_t can_produce; // signaled when items are removed
pthread_cond_t can_consume; // signaled when items are added
};
// Utility function to initialize queue
struct queue* newQueue(int size)
{
struct queue *pt = NULL;
pt = (struct queue*)malloc(sizeof(struct queue));
pt->items = (char*)malloc(size * sizeof(char));
pt->maxsize = size;
pt->front = 0;
pt->rear = -1;
pt->size = 0;
pthread_mutex_init(&pt->mutex, NULL);
pthread_cond_init(&pt->can_produce, NULL);
pthread_cond_init(&pt->can_consume, NULL);
return pt;
}
// Utility function to return the size of the queue
int size(struct queue *pt)
{
return pt->size;
}
// Utility function to check if the queue is empty or not
int isEmpty(struct queue *pt)
{
return !size(pt);
}
// Utility function to return front element in queue
char front(struct queue *pt)
{
if (isEmpty(pt))
{
//printf("UnderFlow\nProgram Terminated\n");
}
return pt->items[pt->front];
}
// Utility function to add an element x in the queue
void enqueue(struct queue *pt, char x)
{
if (size(pt) == pt->maxsize)
{
//printf("OverFlow\nProgram Terminated\n");
}
//printf("Inserting %c\t", x);
pt->rear = (pt->rear + 1) % pt->maxsize; // circular queue
pt->items[pt->rear] = x;
pt->size++;
//printf("front = %c, rear = %c\n", pt->front, pt->rear);
}
// Utility function to remove element from the queue
void dequeue(struct queue *pt)
{
if (isEmpty(pt)) // front == rear
{
//printf("UnderFlow\nProgram Terminated\n");
}
//printf("Removing %c\t", front(pt));
pt->front = (pt->front + 1) % pt->maxsize; // circular queue
pt->size--;
//printf("front = %d, rear = %c\n", pt->front, pt->rear);
}
void consumer_f(void *arg)
{
struct queue *pt = (struct queue*)arg;
while (par==0 && !isEmpty(pt))
{
pthread_mutex_lock(&pt->mutex);
if (pt->size == 0)
{ // empty
// wait for new items to be appended to the buffer
pthread_cond_wait(&pt->can_consume, &pt->mutex);
}
printf("%c", pt->front);
dequeue(pt);
pthread_cond_signal(&pt->can_produce);
pthread_mutex_unlock(&pt->mutex);
}
}
void producer_f(void *arg)
{
struct queue *pt = (struct queue*)arg;
char tmp;
FILE *fp;
fp = fopen("messages.txt", "r");
if (fp == NULL)
{
//fprintf(stderr, "error opening messages.txt");
return -1;
}
while ((tmp = fgetc(fp)) != EOF)
{
pthread_mutex_lock(&pt->mutex);
if (pt->size == max)
pthread_cond_wait(&pt->can_produce, &pt->mutex);
enqueue(pt, tmp);
printf("sent");
pthread_cond_signal(&pt->can_consume);
pthread_mutex_unlock(&pt->mutex);
}
par = 1; //denotes EOF for consumer */
}
int main()
{
printf("nop");
struct queue *pt = newQueue(5);
pthread_t producer;
pthread_t consumer;
printf("got here");
if (pthread_create(&producer, NULL, &producer_f, pt))
{
//fprintf(stderr, "Error creating producer thread\n");
return -1;
}
if (pthread_create(&consumer, NULL, &consumer_f, pt))
{
//fprintf(stderr, "Error creating consumer thread\n");
return -1;
}
if (pthread_join(producer_f, NULL))
{
//fprintf(stderr, "Error joining proucer thread\n");
return -1;
}
if (pthread_join(consumer_f, NULL))
{
//fprintf(stderr, "Error joinging consumer thread\n");
return -1;
}
return 0;
}
The consumer thread is not going to deadlock state but it is exiting without consuming as EOS is reached before consumer started consuming.
As you know, threads can get scheduled in a random way by OS (I mean, at least you can assume that they get scheduled in a random way). With this assumption, the producer might have started and read all bytes and enabled eos flag i.e. par=1. If consumer thread starts after par=1, it is not consuming at all.
To handle this case, you need to update the consumer_f() function.
while (1) //Run the loop always
{
pthread_mutex_lock(&pt->mutex);
if ((pt->size == 0) && (par == 0)) //Make sure that EOS is not already reached.
{ // empty
// wait for new items to be appended to the buffer
pthread_cond_wait(&pt->can_consume, &pt->mutex);
}
if(par && isEmpty(pt))
{
//If Array is empty and eos is reached, unlock and exit loop
pthread_mutex_lock(&pt->mutex);
break;
}
//Other code
}
Similarly, you need to enable eos flag inside mutex in producer_f().
while ((tmp = fgetc(fp)) != EOF)
{
//Your code
}
pthread_mutex_lock(&pt->mutex);
par = 1;
pthread_cond_signal(&pt->can_consume); //To make sure that consumer thread wakesup
pthread_mutex_unlock(&pt->mutex);
PS: pt->size == 0 can be replaced with isEmpty(pt) for more readability.
I'm trying to build a string that will go into a logfile with this format: "Executable: Time:... Error: ...". However, I am having trouble allocating for my time variable in my data structure. I have been able to code it so that the time can go before the string later but I cannot figure out how to have the time be between the executable and the error message. If anyone could tell me what I'm doing wrong I'd appreciate it.
Code:
log.h
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <time.h>
typedef struct data_struct
{
time_t time;
char *string;
} data_t;
int addmsg(data_t data, char *arg0);
void clearlog(void);
char *getlog(void);
int savelog(char *filename);
loglib.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include "log.h"
//Basic template from Excercise 2.13
typedef struct list_struct
{
data_t item;
struct list_struct *next;
} log_t;
static log_t *headPtr = NULL;
static log_t *tailPtr = NULL;
//Like book example with add on for executable name
int addmsg(data_t data, char *arg0)
{
log_t *newnode;
int nodesize;
char timeString[] = ": Time: ";
char errorString[] = " Error: ";
//Allocate size for "Executable: time: Error: "
nodesize = sizeof(log_t) + strlen(data.string) + strlen(arg0) + sizeof(time_t) + strlen(timeString) + strlen(errorString) + 1;
if((newnode = (log_t *)(malloc(nodesize))) == NULL)
{
perror("Malloc failed: ");
return -1;
}
//Makes string "Executable: time: Error: "
newnode->item.time = data.time;
char *timeCode = ctime(&newnode->item.time);
newnode->item.string = (char *)newnode + sizeof(log_t);
strcpy(newnode->item.string, arg0);
newnode->item.string = strcat(newnode->item.string, timeString);
newnode->item.string = strcat(newnode->item.string, timeCode);
newnode->item.string = strcat(newnode->item.string, errorString);
newnode->item.string = strcat(newnode->item.string, data.string);
newnode->next = NULL;
//Puts string as EOF
if(headPtr == NULL)
{
headPtr = newnode;
}
else
{
tailPtr->next = newnode;
}
tailPtr = newnode;
return 0;
}
//Clears log
void clearlog(void)
{
log_t *nextPtr = headPtr;
//Loop through and clear the log
while(nextPtr != NULL)
{
nextPtr = headPtr->next;
free(headPtr);
headPtr = nextPtr;
}
}
char *getlog(void)
{
int size = 1;//Set to 1 because of null terminator
int entryNum = 0; //Number of error logs
log_t *node = headPtr; //Start at beggining
char *wholeLog = NULL; //Used to return the entire log
char *entryString = NULL;
//Get size
while(node != NULL)
{
entryNum++;
size += strlen(node->item.string);
node = node->next;
}
//Memory allocation
wholeLog = malloc(sizeof(char)*(size + 1 + (entryNum * 2)));
if(wholeLog == NULL)
{
perror("Malloc failed: ");
return NULL;
}
//Reset node to beggining
node = headPtr;
//Builds the entire log to return
while(node != NULL)
{
entryString = strcat(entryString, node->item.string);
wholeLog = strcat(wholeLog, entryString);
wholeLog = strcat(wholeLog, "\n"); //New line
node = node->next;
}
//Make space
wholeLog += (strlen(wholeLog) - size - (entryNum-1));
return wholeLog;
}
int savelog(char *filename)
{
FILE *f;
char *logPrinter;
f = fopen(filename, "a");
if(!f)
{
perror("Error opening file: ");
return -1;
}
//Get the log to print
logPrinter = getlog();
if(logPrinter == NULL)
{
printf("Empty Log\n");
return 0;
}
fprintf(f, "%s\n", logPrinter);
fclose(f);
return 0;
}
Your code seems bent on calculating the size of a memory buffer that would hold both the log_t node structure and the concatenated message parts, having the string pointer within the data_t member of the linked list node point within the single memory block, just passed the linked list node content, where the message is stored. In short, a single allocation holding both the node and the message.
That said, exploit the fact that there are standard library API's, notably snprintf that can calculate formatted message buffer length requirements for you, and you can then skip most of the string management malaise in favor of the real purpose of this, managing the linked list structure and the dynamic message content with a single invoke to malloc (and by circumstance, a single invoke to free() when this fiasco needs to be undone):
Determine the length of the formatted string data
Allocate a buffer large enough to hold that data, and the structure that will precede it.
Position the string pointer in the structure to the first char just passed the structure layout.
Perform the formatted message dump into the memory pointed to by that string pointer.
The result is a single allocation of dynamic length, depending on the content of the message being formatted.
Using snprintf Instead
int addmsg(data_t data, const char *arg0)
{
static const char fmt[] = "%s: Time: %s Error: %s";
char stime[32] = ""; // per ctime docs, must be at least 26 chars
int res = -1;
// get time string, trim newline
ctime_r(&data.time, stime);
if (*stime)
stime[strlen(stime)-1] = 0;
// find needed message size
int req = snprintf(NULL, 0, fmt, data.string, stime, arg0);
if (req > 0)
{
// include size of log record, formatted message, and terminator
log_t *node = malloc(sizeof (log_t) + req + 1);
if (node != NULL)
{
node->item.string = (char*)(node+1); // NOTE: see below
node->item.time = data.time;
node->next = NULL;
snprintf(node->item.string, req+1, fmt, data.string, stime, arg0);
// link into list
if (!headPtr)
headPtr = node;
else
tailPtr->next = node;
tailPtr = node;
// good return value
res = 0;
}
else
{
perror("Failed to allocate memory for log mesage: ");
}
}
else
{
perror("Failed to perform message formatting: ");
}
return res;
}
Everything above is fairly straight forward, save for possible NOTE, which I'll explain now. It uses pointer arithmetic. Given a pointer node of some type log_t* the expression:
(node + 1)
calculates the next position in memory where a subsequent log_t object could reside, or the "one-past" memory position in the case of the end of a sequence. When we allocated our memory, we did so to a layout that looks like this:
node ---> |=== log_t ===|===== message text =====|
the expression (node+1), using typed pointer arithmetic, give us:
node ---> |=== log_t ===|===== message text =====|
(node+1)-----------------^
which is then cast to char*, saved in node->data.string and used as the target for the final message formatting using snprintf. Short version: node->item.string points to the extra memory we allocated following the log_t structure pointed to by node.
That's it. The result is a single allocation to a linked list node that contains both the node management data, and also contains a pointer to the dynamic message string stored in the suffix memory of the single allocation past the log_t core data.
If you replaced the log_t construction piece of addmsg with something perhaps like this you would get better results. Your calculation of required memory size is a little off. Might want to also avoid assuming things about memory with your malloc (i.e. Allocating extra memory to store both a structure and the contents of a pointer member of that structure could easily get you into trouble)
...
log_t *newnode = NULL;
void *vp = NULL;
if (NULL == (vp = malloc(sizeof(log_t)))) {
perror("malloc failed (sizeof(log_t))");
return -1;
}
newnode = (log_t *)vp;
newnode->item.time = data.time;
char *timeCode = ctime(&newnode->item.time);
int msgsize = strlen(": Time: Error: ")
+ strlen(arg0)
+ strlen(timeCode)
+ strlen(data.string)
+ 1;
if (NULL == (vp = malloc(msgsize))) {
perror("malloc failed (msgsize)");
free(newnode);
return -1;
}
newnode->item.string = (char *)vp;
sprintf(newnode->item.string, "%s: Time: %s Error: %s", arg0, timeCode, data.string);
...
Edited to include short description of what is expected from the code.
#include <sys/file.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MAX_PAGE 0xFF+1
/* page table entry you may need to add your own fields to it*/
typedef struct
{
unsigned short frame;/*location*/
unsigned int valid:1;
unsigned int in_mem:1;
unsigned int dirty:1;
unsigned int last_frame;
} pt_entry;
/* list entry for physical frames*/
struct list_item
{
unsigned short frame;
struct list_item *next;
struct list_item *prev;
int page_num;
};
typedef struct list_item *list;
void start_simulation(FILE *);
void resolve(int);
unsigned short find_frame(void);
unsigned short find_victim(void);
void display_stats(void);
void to_resident_set(list);
void free_mem(list);
void invalidate(unsigned short);
/*============================ header ends here ============================== *
/*#include "lru.h"*/
pt_entry pte[MAX_PAGE]; /* page table */
int mem_size; /* physical memory size in page frames */
list free_list_head; /* free list */
list res_set_head; /* resident set */
int total_fault = 0; /* total number of page faults */
int total_ref = 0; /* total number of memory references */
/* main program:
** read in paramters, and open the input file start the simulation */
int main(int argc, char *argv[])
{
FILE *stream;
if (argc != 3)
{
printf("The format is: pager file_name memory_size.\n");
exit(1);
}
printf("File used %s, resident set size %d\n", argv[1], atoi(argv[2]));
if ((stream = fopen(argv[1], "r")) == NULL)
{
perror("File open failed");
exit(1);
}
mem_size = atoi(argv[2]);
start_simulation(stream);
fclose(stream);
}
/*initialise the page table
** initialise the resident set, and the free list
** in the simulation loop
**16-bit memory addresses representing the program trace are read from the input
**file one by one the virtual address is resolved ie. physical frame for the
**virtual page identified
**the loop exits when it encounters the end of file
** free memory allocated for lists
** display statistics
*/
void start_simulation(FILE * stream)
{
char *addr_buf;
int address;
int i, n;
list new_entry, current;
/* initialise the page table */
for(i=0; i<MAX_PAGE;i++)
{
pte[i].frame = -1;
pte[i].valid = 0;
pte[i].dirty = 0;
pte[i].in_mem = 0;
}
/* initialise the resident set - empty*/
res_set_head = (list)malloc(sizeof(struct list_item));
res_set_head->next = res_set_head;
res_set_head->prev = res_set_head;
/* initialise free list - all physical pages*/
free_list_head = (list)malloc(sizeof(struct list_item));
free_list_head->next = free_list_head;
free_list_head->prev = free_list_head;
current = free_list_head;
for(i=0; i<mem_size;i++)
{
new_entry = (list)malloc(sizeof(struct list_item));
current->next = new_entry;
new_entry->prev = current;
new_entry->next = free_list_head;
new_entry->frame = i;
current = new_entry;
free_list_head->prev = current;
}
/* main simulation loop */
while( (n = fscanf(stream, "%x", &address)) != -1)
{
resolve(address);
total_ref++;
}
free_mem(free_list_head);
free_mem(res_set_head);
display_stats();
return;
}
/* resolve address reference
** if page table entry valid - do nothing
** if page table entry invalid - find a physical frame for this page
**and update pte for the page
*/
void resolve(int address)
{
unsigned short frame_alloc;
int virt_page;
static int disp_counter = 0;
virt_page = address >> 8;
if (pte[virt_page].valid == 1)
{
/*Was trying to implement */
//pte[virt_page].frame = pte[0];
}
else
{
frame_alloc = find_frame();
pte[virt_page].valid = 1;
pte[virt_page].frame = frame_alloc;
total_fault++;
}
}
/* find_frame:
** if free list is empty find a victim frame
** else detach the last frame of the free list and attach it
** to the resident set
** return frame number
*/
unsigned short find_frame()
{
unsigned short frame;
list current, new_tail;
if (free_list_head == free_list_head->prev) /* free list empty */
frame = find_victim();
else
{
new_tail = free_list_head->prev->prev;
new_tail->next = free_list_head;
current = free_list_head->prev;
free_list_head->prev = new_tail;
to_resident_set(current);
frame = current->frame;
}
return frame;
}
/* to_resident_set:
** attach a list entry at the end of resident set
*/
void to_resident_set(list current)
{
list tail;
tail = res_set_head->prev;
tail->next = current;
current->next = res_set_head;
current->prev = tail;
res_set_head->prev = current;
}
/* find_victim:
** As you can see I simply take the first page frame from the resident set list.
** This implements the FIFO replacement strategy. Your task is to replace it with
** a more efficient strategy.
*/
unsigned short find_victim()
{
int i;
unsigned short frame=0;
list current;
for(i=0;i<MAX_PAGE;i++)
{
if (pte[i].frame == frame && pte[i].valid == 1)
{
frame = res_set_head->next->frame;
invalidate(frame);
current = res_set_head->next;
res_set_head->next = current->next;
res_set_head->next->prev = res_set_head;
to_resident_set(current);
break;
}
}
return frame;
}
/* invalidate:
** invalidate the page table entry for the victim page */
void invalidate(unsigned short frame)
{
int i;
for(i=0;i<MAX_PAGE;i++)
{
if (pte[i].frame == frame && pte[i].valid == 1)
{
pte[i].valid = 0;
pte[i].frame = -1;
break;
}
}
}
/* display_stats:
** This is very basic, you may want to make it more sophisticated,
** for example save the data from multiple runs into a file for
** comparison etc
*/
void display_stats()
{
printf("\nProcess issued %d memory references\n", total_ref);
printf("Process triggered %d page faults\n", total_fault);
printf("Pafe fault rate is %d percent\n",((total_fault*100)/total_ref));
}
/* free memory allocated to the list */
void free_mem(list head)
{
list current,tail;
tail = head->prev;
current = head;
while (current->prev != tail)
{
current = current->next;
free(current->prev);
}
}
The most obvious problem lies in the input to your algorithm.
The restpage array is a global array and will thus be initialised to contain only the value 0. You then use these array elements as the page-numbers you are requesting, which means that your algorithm processes only requests for page 0 if mem_size < 100.
And if mem_size >= 100, you are overrunning the array bounds and land squarely in the land of undefined behaviour.
There are two fixes you need to make:
Just as you are checking for a valid file in the command-line arguments, you must also check that mem_size is not too large
Write an additional loop to give each element in restpage a random value, to ensure not all page requests are for the same page.
You have dimensioned restpage to [100] but mem_size seems freely configurable, is this the intent?
mem_size = atoi(argv[2]);
fclose(stream);
..
for(i=0;i<mem_size;i++)
{
totalabsence+=find_victim(&pt,restpage[i]);
}
EDIT:
I see one bug in your new code, in your find_victim you don't initialize the local variable 'frame'
EDITx2:
When you read from the file you may just want to put one hex address on each line
and use instead fgets() to read the file line by line (or load the whole file and
go through it line by line).