corporateWhore corporateWhore - 2 months ago 12
C Question

Queue loses pointers after call to swapcontext()

First off, let me apologize for the length of the code "sample", I was trying to provide the smallest executable example I could.

I should mention, the queue is of the form:

circular queue

When run is called, the first element is successfully removed from the queue which is then referenced by the global pointer

Curr_Thread
. I check the form of the queue before and after, everything is where its supposed to be.

Swapcontext works and control is passed to
func_1()
, but this is where the problem lies. As soon as it enters
func_1()
, the queue gets mangled somehow, meaning, the head pointer still points to the "dummy" element as it did before the switch (with the next and previous pointers pointing where they should), but everything after the dummy element now points to some garbage element with random next and previous pointer addresses. When
func_1
calls
yield()
, the call to
AddTcb()
inside crashes because it can never find the end of the queue to add
Curr_Thread
.

Before entry into
func_1()
from
swapcontext
:

pointer pointing where they should

Immediately after entry into
func_1()
from
swapcontext


pointers to nowhere

Why is the structure of my queue suddenly changed after calling
swapcontext
? Why is it changing with no other interaction?

Thank you.

#include <ucontext.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <ctype.h>
#include <stdlib.h>

#define MAX_QUEUE 100
TCB_t *ReadyQ;
TCB_t *Curr_Thread;
int global_thread_id = 0;

typedef struct TCB_t {
struct TCB_t *next;
struct TCB_t *prev;
ucontext_t context;
int thread_id;
} TCB_t;

void start_thread(void (*function) (void));
void run();
void yield();
void print_id(TCB_t *tcb);
void func_1();
void (*f1)();
TCB_t* newItem();
TCB_t* newTcb(TCB_t* head);
void AddTcb(TCB_t* head_node, TCB_t* new_node);
TCB_t* DelTcb(TCB_t* head);

void init_TCB (TCB_t *tcb, void *function, void *stackP, int stack_size)
{
memset(tcb, '\0', sizeof(TCB_t));
getcontext(&tcb->context);
tcb->context.uc_stack.ss_sp = stackP;
tcb->context.uc_stack.ss_size = (size_t) stack_size;
tcb->thread_id = global_thread_id ++;
makecontext(&tcb->context, function, 0);// context is now cooked
}

void start_thread(void (*function) (void)){
void *stack; //generic stack pointer
TCB_t *new_tcb; //new TCB

stack = malloc(STACK_SIZE);
new_tcb = (TCB_t*) malloc(sizeof(TCB_t));

init_TCB(new_tcb, function, stack, sizeof(stack));

AddTcb(ReadyQ, new_tcb);
}

void run(){
Curr_Thread = DelTcb(ReadyQ);
ucontext_t parent;
getcontext(&parent); //get the current running context
swapcontext(&parent, &(Curr_Thread->context)); //switch it to the next q element
}

void yield(){
TCB_t *prev_thread;

AddTcb(ReadyQ, Curr_Thread);
prev_thread = Curr_Thread;
Curr_Thread = DelTcb(ReadyQ);
//swap the context from the previous thread to the thread pointed to by Curr_Thread
swapcontext(&(prev_thread->context), &(Curr_Thread->context));
}

struct TCB_t* newItem(){
TCB_t* new_tcb; //create new node on heap
new_tcb = (TCB_t*) malloc(sizeof(TCB_t));
return new_tcb; //return the new node
}

TCB_t* newQueue(){
TCB_t *dummy = newItem(); //create dummy node
TCB_t *head = newItem();

dummy->next = NULL; //set dummy elements to NULL
dummy->prev = NULL;

head->next = dummy; //point head at dummy
head->prev = NULL;

return head; //return head
}
//Add new item to queue
void AddTcb(TCB_t* head_tcb_node, TCB_t* new_tcb_node){
TCB_t* tmp, *dummy;
dummy = head_tcb_node->next; //tmp is header node
if(dummy->next == NULL){
dummy->next = new_tcb_node;
dummy->prev = new_tcb_node;
new_tcb_node->next = dummy;
new_tcb_node->prev = dummy;
}else{
tmp = dummy->next;
while(tmp->next != dummy){
tmp = tmp->next;
}
new_tcb_node->next = tmp->next;
new_tcb_node->prev = tmp;
tmp->next = new_tcb_node;
dummy->prev = new_tcb_node;
}
}
//Remove and return first queue element
TCB_t* DelTcb(TCB_t *head){
TCB_t *dummy, *pop, *tmp;
dummy = head->next;

if (dummy->next == NULL){
pop = NULL;
}else{
pop = dummy->next;
if(pop->next == dummy){
dummy->next = NULL;
dummy->prev = NULL;
}else{
tmp = pop->next;
tmp->prev = dummy;
dummy->next = tmp;
}
pop->next = pop->prev = NULL;
}
return pop;
}
void func_1(){
int local_1 = 0;
while(1){
//print_id(ReadyQ);
printf("\n");
printf("Global int: %d\t", gbl_num);
printf("Local int, function 1: %d\n\n", local_1);
gbl_num++;
local_1++;
yield();
sleep(1);
}
}
int main(){
ReadyQ = newQueue();

f1 = func_1;
start_thread(f1);
run();

return 0;
}

Answer

I had the similar issue. I assigned the values directly like below and it worked for me.

tcb->context.uc_stack.ss_sp = malloc(8192);
tcb->context.uc_stack.ss_size = 8192;