J'essaye d'implémenter la commutation de contexte en utilisant C++ et l'assemblage en ligne (AT & T) sur x86-64.
Il semble fonctionner correctement si je sauvegarde et recharge le contexte pour la même fonction.
Cependant, lorsque j'essaie de céder les fonctions, il m'a donné une erreur de seg/pile corrompue en utilisant GDB après avoir essayé de charger le contexte de la 2ème fonction.Implémentation de changement de contexte - La deuxième fonction ne fonctionne plus
Par exemple, il imprime
Print1
Print2
Print1
// La pile Corrupt et arrête le programme en cours d'exécution
Cependant, si je devais sauver le contexte de fil 1 (1ère fonction) avant rechargeant , il n'y aurait pas de problèmes.
Par exemple, il imprime
Print1
Print1
Print1
Je crée l'espace mémoire pour le contexte enregistrement et pile. Lors de l'enregistrement du contexte, le pointeur de la pile et le pointeur de base seraient sauvegardés dans une structure. Après cela, pointeur de pile pointera vers la mémoire de contexte pour pousser les valeurs de registre.
Je voudrais savoir ce qui cause la pile corrompue et pourquoi je ne peux pas charger le contexte de la 2ème fonction. Et si possible, s'il vous plaît aidez-moi à signaler les erreurs dans mon code. Je vous remercie!
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include <memory>
#include <algorithm>
namespace CORO
{
using ThreadID = unsigned;
static int thread_count;
enum STATE
{
READY,
ACTIVE,
WAITING,
ENDED
};
struct thd_data
{
int parent_ID = 0;
int id = 0;
STATE state = READY;
int * stack_mem;
void * stackptr;
void * stackbp;
void*(*funcptr)(void*);
void * param = nullptr;
int * context_mem;
int * context_sp;
thd_data()
:stack_mem{new int[1024]}, context_mem{new int[1024]}
{
}
thd_data(const thd_data & rhs)
:stack_mem{new int[1024]}, context_mem{new int[1024]}
{
}
thd_data & operator=(const thd_data & rhs)
{
}
};
static thd_data* curr_thd;
std::map<int, std::shared_ptr<thd_data>> threadmap;
std::vector<int>activeListID;
// Returns a pointer to next thread
thd_data * FindNextThread()
{
int new_id;
for(const auto & elem : activeListID)
{
if(elem != curr_thd->id)
{
new_id = elem;
break;
}
}
auto threadmap_elem = threadmap.find(new_id);
if(threadmap_elem != threadmap.end())
{
return &(*threadmap_elem->second);
}
else
{
return nullptr;
}
}
void thd_init()
{
threadmap[0] = std::make_shared<thd_data>();
auto main_thd = threadmap.find(0)->second;
main_thd->state = ACTIVE;
main_thd->id = 0;
main_thd->param = nullptr;
main_thd->funcptr = nullptr;
activeListID.push_back(main_thd->id);
curr_thd = &(*main_thd);
}
ThreadID new_thd(void*(*func)(void*), void *param)
{
thread_count += 1; // increment counter
threadmap[thread_count] = std::make_shared<thd_data>();
auto thd = threadmap.find(thread_count)->second;
thd->state = READY;
thd->id = thread_count;
activeListID.push_back(thd->id);
thd->stackptr = thd->stack_mem+1024;
thd->stackbp = thd->stack_mem;
thd->funcptr = func;
thd->param = param;
return thd->id;
}
void thd_yield()
{
// Find the next ready thread
thd_data* thd = FindNextThread();
if(thd == nullptr)
return;
// Move ID to the end of vector
activeListID.erase(std::remove(activeListID.begin(), activeListID.end(), curr_thd->id), activeListID.end());
activeListID.push_back(curr_thd->id);
// Save context
{
asm volatile
(
"movq %%rsp, %0\n\t" // save stack pointer
"movq %%rbp, %1\n\t" // save rbp
"movq %3, %%rsp\n\t" // point to context mem then push register values into it
"pushq %%rax\n\t"
"pushq %%rbx\n\t"
"pushq %%rcx\n\t"
"pushq %%rdx\n\t"
"pushq %%rsi\n\t"
"pushq %%rdi\n\t"
"pushq %%r8\n\t"
"pushq %%r9\n\t"
"pushq %%r10\n\t"
"pushq %%r11\n\t"
"pushq %%r12\n\t"
"pushq %%r13\n\t"
"pushq %%r14\n\t"
"pushq %%r15\n\t"
"pushfq\n\t"
"movq %%rsp, %2\n\t" // save rsp into context sp (end of context mem)
"movq %4, %%rsp\n\t" // restore stackptr into rsp
:"+m"(curr_thd->stackptr)
,"+m"(curr_thd->stackbp)
,"+m"(curr_thd->context_sp)
:"m"(curr_thd->context_mem)
,"m"(curr_thd->stackptr)
:"rsp"
);
}
curr_thd->state = WAITING;
curr_thd = thd;
// Calls function if thread is not running
if(thd->state == READY)
{
thd->state = ACTIVE;
thd->funcptr(thd->param);
}
else
{
// Restore context
{
asm volatile
(
"movq %0, %%rbp\n\t" // restore stackbp into rbp
"movq %1, %%rsp\n\t" // point to context memory to pop
"popfq\n\t"
"popq %%r15\n\t"
"popq %%r14\n\t"
"popq %%r13\n\t"
"popq %%r12\n\t"
"popq %%r11\n\t"
"popq %%r10\n\t"
"popq %%r9\n\t"
"popq %%r8\n\t"
"popq %%rdi\n\t"
"popq %%rsi\n\t"
"popq %%rdx\n\t"
"popq %%rcx\n\t"
"popq %%rbx\n\t"
"popq %%rax\n\t"
"movq %2, %%rsp\n\t" // point to TCB stack pointer
:
:"m"(thd->stackbp)
,"m"(thd->context_sp)
,"m"(thd->stackptr)
:"rsp"
);
}
}
}
} // end namespace
void* print1(void *a)
{
int i;
for(i=0; i< 20; i++)
{
std::cout<<"Print1 i: "<<i<<std::endl;
if((i+1)%4==0)
CORO::thd_yield();
}
return NULL;
}
void* print2(void *a)
{
int i;
for(i=0; i< 20; i++)
{
std::cout<<"Print2 i: "<<i<<std::endl;
if((i+1)%4==0)
CORO::thd_yield();
}
return NULL;
}
int main()
{
CORO::ThreadID id;
CORO::thd_init();
id = CORO::new_thd(print2, NULL);
print1(NULL);
}
Que supposez-vous dans RSP lorsque vous faites '' movq% 3, %% rsp \ n \ t "'? Et que pensez-vous que cela va se passer quand vous faites '' "movq% 1, %% rsp \ n \ t" '? –
Je crois que RSP pointerait vers le début de la mémoire de contexte pour movq% 3. Pour movq% 1, RSP pointerait vers la fin de la mémoire de contexte, qui est le début de la mémoire de contexte + nombre de fois que j'ai poussé. – Aeria