Tout d'abord, permettez-moi de m'excuser pour la longueur du code "sample", j'essayais de fournir le plus petit exemple exécutable possible.La file d'attente perd des pointeurs après l'appel à swapcontext()
Je dois mentionner, la file d'attente est de la forme:
Lorsque l'exécution est appelée, le premier élément est supprimé de la file d'attente qui est ensuite référencé par le pointeur global Curr_Thread
. Je vérifie la forme de la file d'attente avant et après, tout est supposé être. Swapcontext fonctionne et le contrôle est passé à func_1()
, mais c'est là que réside le problème. Dès qu'il entre func_1()
, la file d'attente est mutilée, ce qui signifie que le pointeur de la tête pointe toujours sur l'élément "factice" comme avant le changement (avec les pointeurs suivant et précédent pointant où ils devraient), mais tout après le mannequin element pointe maintenant vers un élément poubelle avec des adresses de pointeur aléatoires suivantes et précédentes. Lorsque func_1
appelle yield()
, l'appel à AddTcb()
se bloque à l'intérieur car il ne peut jamais trouver la fin de la file d'attente pour ajouter Curr_Thread
.
Avant l'entrée en func_1()
de swapcontext
:
Immédiatement après l'entrée en func_1()
de swapcontext
Pourquoi la structure de ma file d'attente a soudainement changé après avoir appelé swapcontext
? Pourquoi change-t-il sans autre interaction?
Merci.
#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;
}
Reportez-vous à cette réponse: http://stackoverflow.com/questions/25841144/seg-fault-when-returning-to-function-execution-after-successful-swapcontext – Murali
Merci. J'avais déjà essayé cette solution mais j'avais un autre problème qui masquait les résultats. Fonctionne bien maintenant. – corporateWhore
Ajoutez-le comme une réponse et je l'accepterai – corporateWhore