I've seen a few questions on user thread libraries, but none that seem to answer my question. I am able to create threads, run them, cancel them, and exit from them. What I cannot do for some reason is get a thread to return data.
When I initialize my thread library, I set my exit thread context as follows:
getcontext(&threadEnd);
threadEnd.uc_stack.ss_sp = (char *)malloc(SIGSTKSZ);
threadEnd.uc_stack.ss_size = SIGSTKSZ;
makecontext(&threadEnd, (void *) thread_exit, 1, &ReturnValue);
I create a thread and assign it as follows:
thread->myContext.uc_stack.ss_sp = (char *) malloc(SIGSTKSZ);
thread->myContext.uc_stack.ss_size = SIGSTKSZ;
thread->myContext.uc_link = &threadEnd;
When the function returns and thread_exit() is called:
void thread_exit(void* retval){
int* test;
if (retval != NULL)
{
test = (int*) retval;
printf("Returned value: %i\n", *test);
fflush(stdout);
}
The printout is always "Returned value: 0"
The called function is returning a pointer to an integer.
What am I doing wrong?
If you step through your program in GBD makecontext dose not save the return for the function used to make the context.
Example from my experiments: (observe the rax register):
at return statement:
thread1 (arg=0x1) at test_create_join.c:14
14 return (void *)11;
Value returned is $1 = 19
(gdb) info registers
rax 0x13 19
---
after return:
(gdb) step
15 }
(gdb) info registers
rax 0xb 11
inside context switch:
__start_context () at ../sysdeps/unix/sysv/linux/x86_64/__start_context.S:32
32 ../sysdeps/unix/sysv/linux/x86_64/__start_context.S: No such file or directory.
(gdb) info registers
rax 0xb 11
you can see for few instructions the return value is preserved but after few steps it becomes 0. Obviously its specific to x86_64 arch but I presume it might be same to most arch (ie the behavior of makecontext)
Now if you need the return value to your thread function you can go another way about it. Just create a thread handler for running your threads and use the handler for making new contexts. Here you can get the return for the functions you want to run as threads and save it in your thread control block structure for later use.
typedef struct {
thread_start_routine start;
void *arg;
} entry_point;
static void thread_runner(void *args) {
exit_critical_section();
entry_point *entry = (entry_point *) args;
// run the thread and get the exit code
current->retcode = entry->start(entry->arg);
}