corporateWhore corporateWhore - 11 months ago 65
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

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

Swapcontext works and control is passed to
, but this is where the problem lies. As soon as it enters
, 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
, the call to
inside crashes because it can never find the end of the queue to add

Before entry into

pointer pointing where they should

Immediately after entry into

pointers to nowhere

Why is the structure of my queue suddenly changed after calling
? 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));
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;
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;
pop = dummy->next;
if(pop->next == dummy){
dummy->next = NULL;
dummy->prev = NULL;
tmp = pop->next;
tmp->prev = dummy;
dummy->next = tmp;
pop->next = pop->prev = NULL;
return pop;
void func_1(){
int local_1 = 0;
printf("Global int: %d\t", gbl_num);
printf("Local int, function 1: %d\n\n", local_1);
int main(){
ReadyQ = newQueue();

f1 = func_1;

return 0;

Answer Source

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;