In the OS X pthreads implementation (http://www.opensource.apple.com/source/Libc/Libc-825.26/pthreads/thread_setup.c?txt) they provide a fake return address on the thread stack (line 140):
ts->rip = (uintptr_t) routine;
/*
** We need to simulate a 16-byte aligned stack frame as if we had
** executed a call instruction. The stack should already be aligned
** before it comes to us and we don't need to push any arguments,
** so we shouldn't need to change it.
*/
ts->rdi = (uintptr_t) thread; /* argument to function */
*--sp = 0; /* fake return address */
ts->rsp = (uintptr_t) sp; /* set stack pointer */
I do not understand how this will not crash with an illegal instruction/segfault when the function that the thread is executing calls 'ret' and pops that return address from the stack. Can anyone explain how this is prevented/handled?
Without looking at the rest of the code, I can only venture a guess. My intuition says, the called thread procedure (the user-supplied start_routine
parameter) should never return to the calling function.
Think about it: if the new thread did return, you would have two threads running over the same original code path. I imagine that the thread function that is actually called is a wrapper that calls the user-supplied start_routine
. When the start_routine
returns, the wrapper then calls pthread_exit
.
(main thread)
v
pthread_create
v
thread_setup (sets up stack), and spawns new thread
v |
return to main thread |
|
|
v
wrapper_function
v
user-supplied start_routine
| (returns)
v
wrapper_function calls
v
pthread_exit
Again, this is just a guess, but the whole point is, the new thread should never return to the code that called pthread_create
. The purpose of the wrapper then would be to ensure that pthread_exit
gets called.
I would have to see what they are passing as routine
to thread_setup
.
My feelings are confirmed by the fact that you don't have to call pthread_exit
.