Search code examples
c++ucontext

Seg-fault when trying to swapcontext() into a struct member that is stored in a queue


I've defined a struct called thread with a member called ucontext* tctx.

In a function called create_thread(), I create a thread object on the heap and define each one of its members (including the members of the ucontext object). I then add the pointer to that thread object into a queue-container.

When I pop the queue to swap into a thread's context, I seg-fault. I'm not sure why this happens.

Here is the full code:

#include <iostream> 
#include <queue>
#include <ucontext.h> 

#define STACK_SIZE 262144

using namespace std; 

typedef struct thread
{
   int thread_id; 
   ucontext* tctx; 
   char* sp;  
}thread; 

int thread_id; 
ucontext_t* ctx1; //Unused, currently 
ucontext_t* cur; 
queue<thread*> ready_queue; 

/* Function Declaration */
thread* create_thread(int,int); 
void foo1(int); 


int main(int argc, char** argv)
{
   cout << " PROGRAM START ***** \n";

   /* Create 'i' number of threads */  
   for(int i = 0; i < 2; i++) 
   {
      cout << "\nready_queue size before creating thread = " << ready_queue.size() << endl;
      cout << "Calling create thread ... id=" << i << endl;
      create_thread(i, i*1000);    
      cout << "ready_queue size after creating thread = " << ready_queue.size() << endl; 
   }

   cout << " \t>> THREADS CREATED \n"; 
   cout << " \t>> SWITCHING CONTEXT \n";   


   /* Save current context to cur, swap context to first thread in queue */ 
   swapcontext(cur, ready_queue.front()->tctx); //Seg fault!

   cout << " PROGRAM TERMI ***** \n"; 
   return 0; 
}


thread* create_thread(int id, int arg)
{
   static int num_threads = 0; 

   /* Create a new thread struct, ucontxt for the thread, and put in ready queue */  
   thread* n = new thread;
   getcontext(n->tctx); 
   n -> thread_id = id; 
   n -> tctx = new ucontext_t;
   n -> sp   = new char[STACK_SIZE];   

   n->tctx->uc_stack.ss_sp = n->sp; 
   n->tctx->uc_stack.ss_size = STACK_SIZE; 
   n->tctx->uc_stack.ss_flags = 0; 
   n->tctx->uc_link = NULL;    
   makecontext(n->tctx, (void(*)()) foo1, 1, arg); //Thread shall call foo() with argument 'arg' 

   /* Push new thread into ready_queue */ 
   ready_queue.push(n);

   num_threads++; 
   cout << "Thread #" << num_threads << " was created. Thread.ID[" << id << "]\n"; 

   return n; 
}


//Application function
void foo1(int arg)
{
   cout << "Calling from foo1(). I have " << arg << "!\n"; 
}

Edited:

I noticed that if I call getcontext(n->tctx); after n -> tctx = new ucontext_t; the problem is resolved. It seems to be that the problem might be that getcontext was trying to initialize something in the heap that had not yet been allocated.


Solution

  • The ucontext_t* cur pointer is dangling, that is why it swapcontext crashes. You could allocate a valid value (new ucontext_t), but it's better to make its type ucontext_t rather than a pointer. The same also counts for thread.tctx and there is no need to keep thread.sp a pointer either.

    However, C++11 has std::thread which is a much better alternative to what you are trying to do and this would be the proper C++ approach. Also if you want to learn something new, I'd recommend to focus on std::thread instead. There's a nice tutorial here: https://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/

    By the way, in your example getcontext(n->tctx); is also called on an uninitialized tctx and you have a lot of unfreed memory at the end of your program...