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.
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...