Search code examples
clinked-listfree

How can I free information in a linked list?


I have a doubly linked list with *head and **ptail. I wrote code to add to the list and remove from the list, but my problem is freeing the information.

This is the declaration of my node and my linked list:

struct tcb_t { //Node
    int         thread_id;
    int         thread_priority;
    ucontext_t *thread_context;
    struct tcb_t *next;
}; typedef struct tcb_t tcb_t; 
struct queue_t { //Linked List
    tcb_t *head, **ptail; 
}; typedef struct queue_t queue_t;

This is my code for initializing a doubly linked list:

struct queue_t* queue_create() { //Good
  struct queue_t *q = (queue_t *) calloc(1,sizeof(queue_t));
  q->head = NULL;
  q->ptail = &q->head; // problem
  return q;
}

My problem stems from the following function. This function is intended to free all the nodes in the list, but the while loop is infinite. I think this is due to the tail pointing to the head in the linked list creation, but I am not sure if there is a way for me to fix it without rewriting the queue_create().

void t_shutdown() { //Fix
  if(ready != NULL){
    tcb_t *helper = ready->head;
    while(helper->next != NULL){ 
      tcb_t *temp = helper;
      helper = helper->next;
      if(temp->thread_id > 0){
        free(temp->thread_context->uc_stack.ss_sp);
      }
      free(temp->thread_context);
      free(temp);
    }
    free(ready);
  }
  
  ready = NULL;
}

I would like to loop through the list and free all the data but the helper->next is ever NULL.

Any help would be greatly appreciated.

Edit 1

These functions show how data is added and removed from the lists:

void queue_add(struct queue_t *q, tcb_t *ptr) { //Good
    *q->ptail = ptr;
    q->ptail = &ptr->next;
}
tcb_t *queue_remove(struct queue_t *q) { //Good
    struct tcb_t *ptr = q->head;
    if (ptr) {
        q->head = ptr->next;
        if (q->ptail == &ptr->next) {
            q->head == NULL;
            q->ptail = &q->head; // problem
        }
    }
    return ptr;
}

Solution

  • Quick fix:

    #include <stdlib.h>
    
    typedef int ucontext_t;
    
    typedef struct tcb_tag {
        int         thread_id;
        int         thread_priority;
        ucontext_t *thread_context;
        struct tcb_tag *prev;
        struct tcb_tag *next;
    } tcb_t;
    
    typedef struct queue_tag {
        tcb_t *head;
        tcb_t *tail;
    } queue_t;
    
    queue_t queue_create()
    {
        queue_t queue = { NULL, NULL };
        return queue;
    }
    
    void queue_add(queue_t *queue, tcb_t *node)  // aka push_back()
    {
        if (queue->tail) {
            queue->tail->next = node;
            node->prev = queue->tail;
            node->next = NULL;  // just to make sure. Idk where those nodes come from.
        }
    
        queue->tail = node;
    
        if (!queue->head)
            queue->head = queue->tail;
    }
    
    tcb_t* queue_remove(queue_t *queue)  // aka pop_front()
    {
        if (!queue->head)
            return NULL;
    
        tcb_t *old_head = queue->head;
        queue->head = old_head->next;
    
        if (queue->head)
            queue->head->prev = NULL;
        else queue->tail = NULL;  // No head - no tail.
    
        return old_head;
    }
    
    void t_shutdown(queue_t *queue)
    {
        for (tcb_t *curr_node = queue->head, *next_node; curr_node; curr_node = next_node) {
            next_node = curr_node->next;
    
            // do what you have to with curr_node->thread_context here
    
            free(curr_node);
        }
    }
    
    int main(void)
    {
        queue_t q = queue_create();
        queue_add(&q, calloc(1, sizeof(tcb_t)));
        queue_add(&q, calloc(1, sizeof(tcb_t)));
        queue_add(&q, calloc(1, sizeof(tcb_t)));
        queue_add(&q, calloc(1, sizeof(tcb_t)));
        queue_add(&q, calloc(1, sizeof(tcb_t)));
        queue_remove(&q);
        queue_remove(&q);
        queue_remove(&q);
        t_shutdown(&q);
    }