Reputation: 4332
Here is what I want to do as part of a larger thread scheduling api.
I want to create a thread and when the main thread (the one creating the thread) exits, the thread I just created should execute. I am trying to do this with ucontext and the uc_link, but it is not working. It appears that my uc_link does not work when I try to set it for the current thread.
Here is a slightly modified example from this link which is what I tired to make this work.
http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.html
#include <stdio.h>
#include <ucontext.h>
static ucontext_t ctx[3];
static void
f1 (void)
{
puts("start f1");
swapcontext(&ctx[1], &ctx[2]);
puts("finish f1");
}
static void
f2 (void)
{
puts("start f2");
swapcontext(&ctx[2], &ctx[1]);
puts("finish f2");
}
int
main (void)
{
char st1[8192];
char st2[8192];
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = sizeof st1;
ctx[1].uc_link = 0;
makecontext(&ctx[1], f1, 0);
getcontext(&ctx[2]);
ctx[2].uc_stack.ss_sp = st2;
ctx[2].uc_stack.ss_size = sizeof st2;
ctx[2].uc_link = &ctx[1];
makecontext(&ctx[2], f2, 0);
getcontext(&ctx[0]);
ctx[0].uc_link = &ctx[2];
return 0;
}
Expected output :
finished main
start f2
start f1
finish f2
finish f1
Given output :
finished main
How do I go about setting the uc_link for the current thread/process in a meaningful manner ?
Upvotes: 1
Views: 3074
Reputation: 19375
At the link you provided they say
The uc_link member is used to determine the context that shall be resumed when the context being modified by makecontext() returns.
Since your program doesn't resume (execute) any context modified by makecontext(), the above does not apply and the program ends without resuming any context.
To achieve what you want, you have to define some function like
void main_context()
{
// do everything you yet wanted to do in main()
puts("finished main");
}
and replace the
return 0;
with
char st0[8192];
ctx[0].uc_stack.ss_sp = st0;
ctx[0].uc_stack.ss_size = sizeof st0;
makecontext(&ctx[0], main_context, 0);
return -setcontext(&ctx[0]);
Upvotes: 0
Reputation: 1184
Replacing main in the above code with the following produces the expected output.
int
main (void)
{
char st1[8192];
char st2[8192];
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = sizeof st1;
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], f1, 0);
getcontext(&ctx[2]);
ctx[2].uc_stack.ss_sp = st2;
ctx[2].uc_stack.ss_size = sizeof st2;
ctx[2].uc_link = &ctx[1];
makecontext(&ctx[2], f2, 0);
getcontext(&ctx[0]);
ctx[0].uc_mcontext.gregs[16] += 0x26;
puts("finish main");
setcontext(&ctx[2]);
return 0;
}
BUT this doesn't do what you say you want.
The context functions are a way to put a specific return address on the stack.
This program above has only one thread of control. I think you really want multiple threads, in which case you wouldn't use these context functions.
For more information about the stack and the C calling convention, Eli Bendersky has two nice articles with diagrams:
FWIW, to get the 0x26 constant in the above code, I had to disassemble main to find the first address after the setcontext call.
Upvotes: 1