Linked list in C with OMP : memory issues - c

I've adapted a very nice omp-parallelized code to perform numerical integration I found here.
However, some massif profiling revealed that there is some serious memory-leaking going on...
I guess this is related to how popping elements from the stack is handeled, where the top element on the stack is returned but not removed from the stack.
So I figured, I could easily add this missing feature as I've done this before in serial code.
But I'm obiously doing something wrong because I'm getting an "invalid pointer error" after a couple of "frees" ...
Since I'm completely new to OMP I figured, I could ask you guys for help.
I'm really sorry, that I wasn't able to cut done my "example" more.
But I think, that it's important to see how the author implemented the linked list and which datastructures.
I guess most of the code below may be skipped, it looks fine to me.
The problem arises when I try to "free" the data associated with the top element of the stack in the function "pop_stack" at the very end.
Popping elements in serial seems to work fine - inside the parallel section it doesn't.
Can you spot the mistake(s) ?
Note: This is incomplete code. It won't compile.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
#include <math.h>
int num_threads;
#define INITIAL_STACK_SIZE 128
/* the stack structure */
struct stack_s{
int el_count; /* count of elements on stack */
int el_size; /* size of an element */
int mem_reserve; /* allocated memory for stack */
void* elements; /* pointer to begin of stack */
};
struct myparams { double c1; double c1;};
typedef struct _work_t{
double a;
double b;
double rec; /* max recursion depth */
struct myparams * p;
} work_t;
typedef struct stack_s* stack_t;
void create_stack(stack_t* stack, int element_size);
int empty_stack(stack_t stack);
void push_stack(stack_t stack, void* element);
void pop_stack(stack_t stack, void* element);
double do_something(
double (*f)(double,struct myparams*), /* function to be called */
double a,
double b,
int rec, /*max. recursion depth*/
struct myparams* p);
static double myfun(double x,struct myparams* p){ return exp(-x*x)/p->a+log(x*pow(p->b,2.0));}
int main(int argc,char** argv)
{
num_threads=omp_get_num_threads();
double a=somevalue;
double b=somevalue;
struct myparams pinit;
pinit.c1=someval;
pinit.c2=someval;
double answer=0;
#pragma omp parallel
{
answer = do_something(myfun, xmin, xmax, 100, &pinit);
} /* omp parallel */
return 0;
}
double do_something(
double (*f)(double,struct myparams*), /* function to be called */
double a,
double b,
int rec,
struct myparams* p)
{
stack_t stack;
work_t work;
int ready, idle, busy;
/* prepare stack */
work.a = a;
work.b = b;
work.rec=rec;
work.p=p;
create_stack(&stack, sizeof(work_t));
push_stack(stack, &work);
double result = 0.0;
busy = 0;
#pragma omp parallel default(none) \
shared(stack, result,f,busy) \
private(work, idle, ready)
{
ready = 0;
idle = 1;
while(!ready )
{
#pragma omp critical (stack)
{
if (!empty_stack(stack)){
/* we have new work */
pop_stack(stack, &work);
if (idle){
/* say others i'm busy */
busy += 1;
idle = 0;
}
}else{
/* no new work on stack */
if (!idle){
busy -= 1;
idle = 1;
}
/* nobody has anything to do; let us leave the loop */
if (busy == 0)
ready = 1;
}
} /* end critical(stack) */
if (idle)
continue;
/* do some calculations using values saved in work and as well as the function f
along with the function parameters saved in myparams
-> estimate an error & save it to 'delta' */
if(rec <= 0 || fabs(delta) <= global_tolerance)
{
//error acceptable
#pragma omp critical (result)
result += somevalue_computed_above;
}
else // error not acceptable
{
//push 2 new work-elements to stack
//prepare 1st new elem.
work.a = some_new_a;
work.b = some_new_b;
work.rec=rec-1;
#pragma omp critical (stack)
{
push_stack(stack, &work);
//prepare 2nd new element
work.a = some_new_a2;
work.b = some_new_b2;
work.rec=rec-1;
push_stack(stack, &work);
}
}
} /* while */
} /* end omp parallel */
return result;
}
/******************************************
* create new stack
******************************************/
void
create_stack(
stack_t* stack, /* stack to create */
int element_size) /* size of a stack element */
{
int initial_size = INITIAL_STACK_SIZE;
/* allocate memory for new stack struct */
(*stack) = (stack_t) malloc(sizeof(struct stack_s));
if (!(*stack)){
fprintf(stderr, "error: could not allocate memory for stack.. Abort.\n");
exit(1);
}
/* allocate memory for stack elements */
(*stack)->elements = (void*) malloc(element_size * initial_size);
(*stack)->mem_reserve = initial_size;
if (!(*stack)->elements){
fprintf(stderr, "error: could not allocate memory for stack.. Abort.\n");
exit(1);
}
(*stack)->el_size = element_size;
(*stack)->el_count = 0;
}
/*****************************************
* check if the stack is empty
*****************************************/
int
empty_stack
(stack_t stack)
{
return stack->el_count <= 0;
}
/*****************************************
* push a element on stack
*****************************************/
void
push_stack(
stack_t stack, /* target stack */
void* element) /* element to push */
{
int i, new_reserve;
int log2_count;
/* check if we need more memory for stack */
if (stack->el_count >= stack->mem_reserve){
/* calculate new size for the stack
it should be a power of two */
for (i = stack->el_count, log2_count = 0;
i > 0;
i>>1, log2_count++);
new_reserve = 1 << log2_count;
/* reallocate memory for phase thread tables
and nullify new values */
stack->elements = (void *) realloc(stack->elements,
stack->el_size * new_reserve);
if (!stack->elements){
fprintf(stderr, "error: can't reallocate stack.. Aborting\n");
exit(1);
}
stack->mem_reserve = new_reserve;
}
/* now push the element on top of the stack */
memcpy((char*)stack->elements + stack->el_count*stack->el_size,
element, stack->el_size);
stack->el_count++;
}
/*****************************************
* pop an element from stack
* THIS IS WHERE I SUSPECT A MISTAKE !
*****************************************/
void pop_stack(
stack_t stack, /* target stack */
void* element) /* where poped el. should be stored */
{
if (stack->el_count <= 0){
fprintf(stderr, "error: trying to pop from empty stack.\n");
exit(2);
}
stack->el_count--;
memcpy(element,
(char*)stack->elements + stack->el_count*stack->el_size,
stack->el_size);
// try to remove last element from stack
// in original code there was no cleanup
struct _work_t *tmp = (struct _work_t*) stack->elements+stack->el_count;
printf("ncount:%d, foo:%f\n",stack->el_count+1,tmp->a);
free(tmp); //Works as long as el_count == 1 but fails if it becomes 2
}

So it looks like pop_stack() is only called inside some stack related critical region, so we can stop worrying about data races.
You identify this part of the code:
/*****************************************
* pop an element from stack
* THIS IS WHERE I SUSPECT A MISTAKE !
*****************************************/
void pop_stack(
stack_t stack, /* target stack */
void* element) /* where poped el. should be stored */
{
if (stack->el_count <= 0){
fprintf(stderr, "error: trying to pop from empty stack.\n");
exit(2);
}
stack->el_count--;
memcpy(element,
(char*)stack->elements + stack->el_count*stack->el_size,
stack->el_size);
// try to remove last element from stack
// in original code there was no cleanup
struct _work_t *tmp = (struct _work_t*) stack->elements+stack->el_count;
printf("ncount:%d, foo:%f\n",stack->el_count+1,tmp->a);
free(tmp); //Works as long as el_count == 1 but fails if it becomes 2
}
as the possible seat of the problem. So the push_stack() clearly copies stack->el_size bytes of the element to the stack, and pop_stack() copies them back again. That all looks wonderful. The last part of pop_stack() is, however, a bit of a puzzle...
struct _work_t *tmp = (struct _work_t*) stack->elements+stack->el_count;
printf("ncount:%d, foo:%f\n",stack->el_count+1,tmp->a);
free(tmp); //Works as long as el_count == 1 but fails if it becomes 2
stack->elements is a void* pointer to the first byte of the first element, so adding stack->el_count to that does not give you the address of the element that has just been popped, except when stack->el_count == 0 !! So tmp is set to a nonsense value, and tmp->a is also, therefore, nonsense. As for the free(tmp)... only when el_count == 0 (now) will the free() not fail, but it will destroy the stack.
Looking at the way the stack works does not suggest to me that the pop_stack() needs to do any "cleanup". If you think it does, then you need to reconsider what that really needs to be. It's possible that you are using the stack as a stack of pointers to "stuff"... but in any case, there's a little more work to be done.

Related

C. double free or corruption (!prev) Aborted (core dumped)

I'm trying to use a "fixed memory scheme" and pre-allocate memory & reuse it via alloc, init, free fashion as many times as possible.
free() will called at shutdown only, but I want to test many iterations.
Although I call my alloc function bn_tree_alloc_node_space_heap() & init function bn_tree_init_node_heap(), I can only call free function bn_tree_free_node_space once.
Below is a complete reproducible snippet of my memory management, maint_test.c:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#define BN_TREE_HEAP_SIZE 100
/*variables internal*/
typedef struct bntree_internals;
/*bn_tree_node is single bntree_t leaf*/
typedef struct bn_tree_node {
struct bn_tree_node* left;
struct bn_tree_node* right;
float* dataset;
float distance_to_neighbor;
int visited;
int heap_index;
} bn_tree_node;
/*tree*/
typedef struct {
/*in order to keep track of the bn-tree root*/
bn_tree_node* _root;
/*pointer to internal variables struct*/
struct bntree_internals* _internals;
} bntree_t;
/*bn tree leaf nodes heap*/
bn_tree_node* node_processing_space = NULL;
/*leaf nodes*/
void bn_tree_alloc_node_space_heap(int max_dimensions);
bn_tree_node*
get_pre_allocated_bn_tree_node_heap();
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions);
void bn_tree_free_node_space(bn_tree_node* nodes);
int main(int argc, char** argv) {
/*PROBLEM:called the alloc,init,free cycle several times, problem,
getting seg fault on 2nd call of free()*/
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
return (EXIT_SUCCESS);
}
void bn_tree_alloc_node_space_heap(int max_dimensions) {
if (NULL == node_processing_space) {
node_processing_space = (bn_tree_node*) calloc(BN_TREE_HEAP_SIZE, sizeof (bn_tree_node));
//TODO: bn_tree_set_k_dimensions (max_dimensions);
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
node_processing_space[i].dataset = (float*) calloc(max_dimensions, sizeof (float));
}
//bn_heap_tail_index = bn_heap_head_index = 0;
}
}
bn_tree_node* get_pre_allocated_bn_tree_node_heap() {
return node_processing_space;
}
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions) {
int i = 0;
int c = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
/*reset values */
if (NULL != nodes[i].dataset) {
c = 0;
for (; c < max_dimensions; c++) {
nodes[i].dataset[c] = FLT_MIN;
}
}
nodes[i].visited = 0;
nodes[i].distance_to_neighbor = FLT_MAX;
nodes[i].left = NULL;
nodes[i].right = NULL;
nodes[i].heap_index = -1;
}
}
/*PROBLEM is subsequent call to free(), but if I alloc again why cant I free again?*/
void bn_tree_free_node_space(bn_tree_node* nodes) {
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if (nodes[i].dataset) {
free(nodes[i].dataset);
}
}
free(nodes);
nodes = NULL;
}
Here is the output that I expect/want:
alloc
init
free
alloc
init
free
alloc
init
free
alloc
init
free
But Im getting this output/error:
alloc
init
free
alloc
init
double free or corruption (!prev)
Aborted (core dumped)
How can fix this?
Can't I do alloc,init,free as many times as I want (as long as I called alloc before free) OR I can do only alloc() once, then many init(), free() once?
Thanks a million & please be kind enough to provide concise answers with minimal changes.
The problem is that your bn_tree_free_node_space function takes, as its argument, a copy of the pointer variable - that is, you are passing the pointer by value - thus, the line nodes = NULL; at the end of that function only sets the local variable to NULL and does not change the value of the node_processing_space variable.
To fix this (with minimal changes to your code logic1), you need to pass that function a pointer to the pointer, and dereference that in the function. So, your function should look like this:
void bn_tree_free_node_space(bn_tree_node** nodes) // Argument is pointer-to-pointer
{
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if ((*nodes)[i].dataset) { // Now we need to use (*nodes) to get the underlying pointer
free((*nodes)[i].dataset); // ... same here
}
}
free(*nodes); /// ... and here
*nodes = NULL;
}
You will, of course, also need to change the function prototype (just before your main) to match the new definition:
void bn_tree_free_node_space(bn_tree_node** nodes); // Must match definition!
Fruther, you will (clearly) need to change the calls to that function to pass the address of the node_processing_space pointer:
bn_tree_free_node_space(&node_processing_space); // Likewise for the other 3 calls!
Feel free to ask for further clarification and/or explanation.
1 EDIT: There are other ways (some may argue better ways) to implement your system, and also other 'minor' issues in your code. However, you did explicitly ask for "concise answers with minimal changes," so I have endeavoured to comply with that request!

Simple coding error (potentially) in kernel code

Here are the related structs:
typedef struct OS_BM {
void *free; /* Pointer to first free memory block */
void *end; /* Pointer to memory block end */
U32 blk_size; /* Memory block size */
U32 owner_one;
} *P_BM;
typedef struct NEW { //struct ADDED BY ME
void *free;
U8 pid;
} *P_GH;
Here is the code in question (only the part "ADDED BY ME"):
void *rt_alloc_box (void *box_mem) {
/* Allocate a memory block and return start address. */
void **free;
#if !(defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
int irq_dis;
irq_dis = __disable_irq ();
free = ((P_BM) box_mem)->free;
if (free) {
array[counter]->free=((P_BM) box_mem)->free; //ADDED BY ME- MAY NOT BE WORKING
array[counter]->pid = rt_tsk_self(); //ADDED BY ME
counter++; //ADDED BY ME
((P_BM) box_mem)->free = *free;
}
if (!irq_dis) __enable_irq ();
#else
do {
if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0) {
__clrex();
break;
}
} while (__strex((U32)*free, &((P_BM) box_mem)->free));
#endif
return (free);
}
int free_owner (void *box_mem, void *box){ //FUNCTION ADDED BY ME
int i;
for(i = 0; i<8;i++){
if (box == array[i]->free;){ //MAY NOT BE WORKING
if(rt_tsk_self() == (array[i]->pid))
return (0);
}
}
return (1);
}
Code Description: The first function is to do with memory allocation, but I need to added protection/ownership to the memory block that is allocated from the pool. That is why I am putting the memory block address as well as the process ID (returned from rt_tsk_self()) into an extra global array that I created. The second function just checks if the process with using the allocated block has the same ownership as the one created (again it uses rt_tsk_self()).
Actual Problem: The lines commented with "MAY NOT BE WORKING" don't seem to work as I am sure that I can put the process ID into the array as well as checking that it is in there, but I cannot do the same with memory block address. This is very likely to just be a simple coding error rather than conceptual.
if (box == array[i]->free;){ //MAY NOT BE WORKING
Shouldn't this be:
if (box == *(array[i]->free)){ //MAY NOT BE WORKING
Also, somehow comparing void pointers make me, uneasy.

2d Array gains unwanted additional elements

This is my first post, but I have been using this site for a while now, been very useful.
I am in the process of writing a memory-pool implementation but I have run into a strange problem. Right now I have 2 memory pools, there is an odd problem that whenever I initialize both of them the first array will have 1 more element than it is supposed to have. For each pool I add beyond the first it gains an additional element. It is not supposed to and I have no idea why.
In my code the first pool has 32 elements (0 - 31) which works fine, but when I initialize the second pool it shows as having 33 elements (0 - 32).
Here is my code :
#include <stdio.h>
typedef struct memoryBlock {
/* Pointer to array */
int *Address;
struct memoryBlock *Next;
}memoryBlock;
/* Small Pool */
#define BLOCKNUM_POOL_S 32 //number of blocks
#define BLOCKSIZE_POOL_S 8 //ints per block
static memoryBlock *Pool_Head_S;
static memoryBlock *Pool_Tail_S;
/* The memory that will be dynamically allocated will be stored in this array */
static int Pool_Block_S[BLOCKNUM_POOL_S-1][BLOCKSIZE_POOL_S+sizeof(memoryBlock)/sizeof(int)];
/* This is a free list containing only pointers to free blocks in this pool */
static int Pool_Free_S[BLOCKNUM_POOL_S-1][sizeof(memoryBlock)/sizeof(int)];
/* Medium Pool */
#define BLOCKNUM_POOL_M 16 //number of blocks
#define BLOCKSIZE_POOL_M 16 //words per block
static memoryBlock *Pool_Head_M;
static memoryBlock *Pool_Tail_M;
/* The memory that will be dynamically allocated will be stored in this array */
static int Pool_Block_M[BLOCKNUM_POOL_M-1][BLOCKSIZE_POOL_M+sizeof(memoryBlock)/sizeof(int)];
/* This is a free list containing only pointers to free blocks in this pool */
static int Pool_Free_M[BLOCKNUM_POOL_M-1][sizeof(memoryBlock)/sizeof(int)];
void printS();
void printM();
void initPool_S();
void initPool_M();
void main(){
initPool_S();
initPool_M();
printS();
printM();
}
void initPool_S(){
int i;
Pool_Tail_S = NULL;
Pool_Head_S = NULL;
for(i=0;i<BLOCKNUM_POOL_S;i++){
//for each block setup the memory block and pointers
if(Pool_Tail_S){
Pool_Tail_S->Next = (memoryBlock *)&Pool_Free_S[i][0];
Pool_Tail_S->Next->Address = &Pool_Block_S[i][0];
Pool_Tail_S = Pool_Tail_S->Next;
Pool_Tail_S->Next = NULL;
/* There is nothing in this list yet */
}else{
Pool_Head_S = (memoryBlock *)&Pool_Free_S[i][0];
Pool_Head_S->Address = (int *)&Pool_Block_S[i][0];
Pool_Head_S->Next = NULL;
Pool_Tail_S = Pool_Head_S;
}
}
}
void initPool_M(){
int i;
Pool_Tail_M = NULL;
Pool_Head_M = NULL;
for(i=0;i<BLOCKNUM_POOL_M;i++){
//for each block setup the memory block and pointers
if(Pool_Tail_M){
Pool_Tail_M->Next = (memoryBlock *)&Pool_Free_M[i][0];
Pool_Tail_M->Next->Address = (int *)&Pool_Block_M[i][0];
Pool_Tail_M = Pool_Tail_M->Next;
Pool_Tail_M->Next = NULL;
/* There is nothing in this list yet */
}else{
Pool_Head_M = (memoryBlock *)&Pool_Free_M[i][0];
Pool_Head_M->Address = (int *)&Pool_Block_M[i][0];
Pool_Head_M->Next = NULL;
Pool_Tail_M = Pool_Head_M;
}
}
}
void printM(){
memoryBlock *tmpPtr2;
tmpPtr2 = Pool_Head_M;
int j=0;
while(tmpPtr2){
printf(">-------------------------------------------------<\n");
printf("%d\n",j);
printf("Pool_Med_Free: %d\n",tmpPtr2);
printf("Pool_Med_Free->Address: %d\n",tmpPtr2->Address);
printf("Pool_Med_Free->Next: %d\n",tmpPtr2->Next);
tmpPtr2 = tmpPtr2->Next;
j++;
}
}
void printS(){
memoryBlock *tmpPtr1;
tmpPtr1 = Pool_Head_S;
int j=0;
while(tmpPtr1){
printf(">-------------------------------------------------<\n");
printf("%d\n",j);
printf("Pool_Small_Free: %d\n",tmpPtr1);
printf("Pool_Small_Free->Address: %d\n",tmpPtr1->Address);
printf("Pool_Small_Free->Next: %d\n",tmpPtr1->Next);
tmpPtr1 = tmpPtr1->Next;
j++;
}
}
Also the compiler I am using is minGW.
I am still somewhat new to C so this is probably a stupid mistake, but I cannot seem to solve it. Any Help would be appreciated, Thanks!
Pool_Block_S[BLOCKNUM_POOL_S-1] has only 31 elements. n in array[n] is number of elements not index of last element. This is the source of your problem.
What is the meaning of sizeof(memoryBlock)/sizeof(int)? It doesn't look correctly.

Freeing C Stack & Removing Dangling Pointers

I've implemented a stack in C, using a stackADT struct and a set of functions:
#ifndef _stack_h
#define _stack_h
// Macros
#define MaxStackSize 100
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// The type of element that may
// be stored in the stack
typedef int stackElementT;
// The stackADT represents the abstract type used to store
// the elements that have been pushed
typedef struct stackCDT
{
// A pointer to an array of elements
stackElementT* elements;
// Number of elements on the stack
int count;
// Number of elements we can push onto
// the stack before having to resize
int size;
}* stackADT;
// This function allocates and returns a new stack, which is
// initially empty... AKA - The Constructor
stackADT NewStack(void)
{
// The stack to return
stackADT stack;
// Instanitate a new stack
stack = (stackCDT*)(malloc(sizeof(stackCDT)));
// Start with 0 elements of course
stack->count = 0;
// Allocate memory for 50 integers
stack->elements = (stackElementT*)(malloc(50*sizeof(stackElementT)));
// Establish the size of the stack
stack->size = 50;
return stack;
}
/********* GETTER FUNCTIONS *********/
// Returns the number of elements currently pushed
// onto the stack
int StackDepth(stackADT stack)
{
return (stack->count);
}
// This function returns the element a the specified index in
// the stack, where the top is defined as index 0
stackElementT GetStackElement(stackADT stack, int index);
// Function to print contents of stack
void PrintStack(stackADT stack)
{
int i = 0;
printf("count = %d\nsize = %d\n",stack->count,stack->size);
for(i = (stack->count - 1); i >= 0; i--)
{
if((i%10 == 0) && (i != 0))
printf("\n");
printf("%d\t",*(stack->elements + i));
}
}
// Functions to determine if stack is empty or full
int StackIsEmpty(stackADT stack)
{
if(stack->count == 0)
return 1;
else
return 0;
}
int StackIsFull(stackADT stack)
{
if(stack->count == stack->size)
return 1;
else
return 0;
}
// This function pushes the specified element onto the stack
void Push(stackADT stack, stackElementT element)
{
// A temporary array that we may use later on
stackElementT* temp = NULL;
int oldCount = stack->count;
int i = 0;
// If the stack if full we need to do a
// a transfer, resize, and retransfer, then push
if(StackIsFull(stack))
{
// temp will be the same size as the old stack
temp = (stackElementT*)(malloc((oldCount)*sizeof(stackElementT)));
// Now we perform the transfer
for(i = 0; i < oldCount; i++)
{
*(temp + i) = *((stack->elements) + i);
}
// Free the old memory
free(stack->elements);
stack->elements = NULL;
// Recreate the stack with a 50% increase in size/capacity
stack->elements = (stackElementT*)(malloc((3*oldCount/2)*sizeof(stackElementT)));
// Re-establish the size
stack->size = 3*oldCount/2;
// Now we perform the transfer back
for(i = 0; i < oldCount; i++)
{
*((stack->elements) + i) = *(temp + i);
}
// Free the temp array and
// remove dangling pointer
free(temp);
temp = NULL;
// Now we push the element onto the stack
*((stack->elements) + oldCount) = element;
// Increase the count
stack->count = oldCount + 1;
}
// If the stack isn't full
else
{
*((stack->elements) + oldCount) = element;
stack->count = oldCount + 1;
}
}
// This function pops the top element from the stack and returns
// that value
stackElementT Pop(stackADT stack);
// This function frees the storage associated with the stack
void FreeStack(stackADT stack)
{
// Start by freeing the elements on the stack
// and remove dangling pointers
free(stack->elements);
stack->elements = NULL;
// Finally free the stack
free(stack);
stack = NULL;
}
#endif
Obviously I'm not completely finished (needs a pop function). My concern is with the bottom function (FreeStack). I tested the code below as such:
#include <stdio.h>
#include <stdlib.h>
#include "Stack.h"
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
int main(void)
{
stackADT stack;
int i = 0;
stack = NewStack();
PrintStack(stack);
for(i = 0; i < 60; i++)
{
Push(stack,i);
}
PrintStack(stack);
FreeStack(stack);
_CrtDumpMemoryLeaks();
return 0;
}
The _CrtDumpMemoryLeaks() function is for Visual Studio and it indicates if there is a memory leak. Apparently I've sealed off any leaks when calling the FreeStack(stackADT stack) function. However, the stack pointer still holds a memory address, which is the issue because the FreeStack function is supposed to free the memory pointed to by the stack variable and set it equal to NULL. This occurs within the function, but when I return to the main function during debugging, I see the memory address still there. What is it I'm missing here? If I'm able to release the memory, why can't I remove the dangling pointer?
You pass the stack to the function by value, instead of by address, modify the function to receive (stackADT *) and you'll be good to go.
Clarification: as Christian commented, the function call, and the use of stack will have to be changed as well of course (since now it's a pointer to pointer...)
You're passing that stackADT object (pointer) by value in your pop method:
void FreeStack(stackADT stack)
So stack refers to the local copy of that pointer. When you set that pointer = NULL, you modify it only within FreeStack. The main method has its own copy of said pointer, not pointing to NULL.

Implementing LRU page replacement algorithm

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).

Resources