我的问题是关于PC寄存器值给予创建的线程。
如果我用fork()
创建一个新进程,PC值将从父进程复制到子进程,因为PC值是代码中的下一个命令。
但是如果我按照以下方式创建一个新线程
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg)
with:
err = pthread_create(&thready, NULL, &doSomeThing, NULL);
我只是命令线程运行一个程序但我不明白创建的线程从哪里得到它的PC值?它肯定不是父亲的PC。如何将PC值设置为doSomeThing代码的第一行?
答案 0 :(得分:2)
(粗略)它的PC被设置为你给出的功能的地址。实际上它被设置为一些调用你的函数的存根。在该存根中,有一些调用系统例程,它设置了在系统中支持线程所需的一切。 PC如何完全设置非常特定于内核和硬件。如果您对系统代码感到满意,可以浏览Linux内核源代码,看看它是如何完成的。
例如,glibc 2.0有一个start_thread
函数,它接受系统构建的struct pthread的地址(该例程是存根)。在该函数中,调用一些宏CALL_THREAD_FCT(thread_struct_address)
,其目的是开始运行您的函数。它对i386平台的定义是:
#define CALL_THREAD_FCT ( descr ) \
({ void *__res; \
int __ignore1, __ignore2; \
asm volatile ("pushl %%eax\n\t" \
"pushl %%eax\n\t" \
"pushl %%eax\n\t" \
"pushl %%gs:%P4\n\t" \
"call *%%gs:%P3\n\t" \
"addl $16, %%esp" \
: "=a" (__res), "=c" (__ignore1), "=d" (__ignore2) \
: "i" (offsetof (struct pthread, start_routine)), \
"i" (offsetof (struct pthread, arg))); \
__res; })
例如,请参阅http://fossies.org/dox/glibc-2.20/pthread__create_8c_source.html。