QEMU 用户模式仿真是否以防止 pthread_join 阻塞的方式退出?
Does QEMU user mode emulation exit in a way that would prevent pthread_join from blocking?
我正在尝试 运行 QEMU 的用户模式模拟器作为我正在编写的更大程序中的一个线程。我修改了 linux-user/main.c
文件,现在标准 int main(int argc, char **argv, char **envp
函数被称为 void *qemu_user_mode_func(void *arg)
。我还在该函数的末尾添加了 pthread_exit(NULL)
,这是 pthreads 的标准做法(或者有人告诉我)。
但是,当我尝试 运行 包含我自己的测试函数的第二个线程(如下面 void *test_func(void *arg)
所示)时,进程在第二个线程完成之前退出,即使调用pthread_join(
tid
)
,我读过它会阻塞调用线程,直到线程 tid
returns。 QEMU 的用户模式仿真是否以阻止 pthread_join
退出的方式退出,或者我只是使用了错误的线程?
这是我的代码(不包括 qemu_user_mode_func
的大部分):
void *qemu_user_mode_func(void *arg)
{
thread_data_t *thread_data;
int argc;
char **argv;
char **envp;
/** QEMU's normal code **/
//return 0;
pthread_exit(NULL);
}
void *test_func(void *arg) {
struct timespec time;
time.tv_sec = 7;
time.tv_nsec = 0;
nanosleep(&time, NULL);
printf("hello, world - from a thread\n");
pthread_exit(NULL);
}
int main(int argc, char**argv, char **envp) {
//Initialize variables to create thread
int rc;
pthread_t threads[2];
thread_data_t main_args;
main_args.tid = 1;
main_args.argc = argc;
main_args.argv = argv;
main_args.envp = envp;
//Create thread
if ((rc = pthread_create(&(threads[0]), NULL, test_func, NULL))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
if ((rc = pthread_create(&(threads[1]), NULL, qemu_user_mode_func, (void *)&main_args))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
//Wait for thread to finish, then terminate process
for (rc = 0; rc < 2; rc++) {
pthread_join(threads[rc], NULL);
}
return 0;
}
编辑: 我在 void cpu_loop(CPUX86State *env)
函数中发现,当模拟程序结束时,QEMU 调用系统调用 231,即 sys_exit_group
(根据 1)。所以我猜这个系统调用正在终止我正在 运行ning 的整个过程。如果有任何关于如何解决该问题的提示,我将不胜感激!
如果将复杂的现有应用程序转换为线程,就会出现问题。一个是应用程序可以调用 exit
或其变体,这将终止您的整个程序。还有许多其他问题可能会导致问题。我建议使用 gdb to determine what is making your program exit.
问题已通过编辑 void cpu_loop(CPUX86State *env)
中的以下部分解决。我在执行之前捕获 sys_exit_group
和 sys_exit
系统调用,而只是从函数中捕获 return。
原文:
void cpu_loop(CPUX86State *env)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
trapnr = cpu_x86_exec(env);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int [=10=]x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
break;
#endif
修改:
void cpu_loop(CPUX86State *env)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
trapnr = cpu_x86_exec(env);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int [=11=]x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
----> if ((env->regs[R_EAX] == __NR_exit_group) || (env->regs[R_EAX] == __NR_exit)) {
return;
}
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
break;
#endif
我正在尝试 运行 QEMU 的用户模式模拟器作为我正在编写的更大程序中的一个线程。我修改了 linux-user/main.c
文件,现在标准 int main(int argc, char **argv, char **envp
函数被称为 void *qemu_user_mode_func(void *arg)
。我还在该函数的末尾添加了 pthread_exit(NULL)
,这是 pthreads 的标准做法(或者有人告诉我)。
但是,当我尝试 运行 包含我自己的测试函数的第二个线程(如下面 void *test_func(void *arg)
所示)时,进程在第二个线程完成之前退出,即使调用pthread_join(
tid
)
,我读过它会阻塞调用线程,直到线程 tid
returns。 QEMU 的用户模式仿真是否以阻止 pthread_join
退出的方式退出,或者我只是使用了错误的线程?
这是我的代码(不包括 qemu_user_mode_func
的大部分):
void *qemu_user_mode_func(void *arg)
{
thread_data_t *thread_data;
int argc;
char **argv;
char **envp;
/** QEMU's normal code **/
//return 0;
pthread_exit(NULL);
}
void *test_func(void *arg) {
struct timespec time;
time.tv_sec = 7;
time.tv_nsec = 0;
nanosleep(&time, NULL);
printf("hello, world - from a thread\n");
pthread_exit(NULL);
}
int main(int argc, char**argv, char **envp) {
//Initialize variables to create thread
int rc;
pthread_t threads[2];
thread_data_t main_args;
main_args.tid = 1;
main_args.argc = argc;
main_args.argv = argv;
main_args.envp = envp;
//Create thread
if ((rc = pthread_create(&(threads[0]), NULL, test_func, NULL))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
if ((rc = pthread_create(&(threads[1]), NULL, qemu_user_mode_func, (void *)&main_args))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
//Wait for thread to finish, then terminate process
for (rc = 0; rc < 2; rc++) {
pthread_join(threads[rc], NULL);
}
return 0;
}
编辑: 我在 void cpu_loop(CPUX86State *env)
函数中发现,当模拟程序结束时,QEMU 调用系统调用 231,即 sys_exit_group
(根据 1)。所以我猜这个系统调用正在终止我正在 运行ning 的整个过程。如果有任何关于如何解决该问题的提示,我将不胜感激!
如果将复杂的现有应用程序转换为线程,就会出现问题。一个是应用程序可以调用 exit
或其变体,这将终止您的整个程序。还有许多其他问题可能会导致问题。我建议使用 gdb to determine what is making your program exit.
问题已通过编辑 void cpu_loop(CPUX86State *env)
中的以下部分解决。我在执行之前捕获 sys_exit_group
和 sys_exit
系统调用,而只是从函数中捕获 return。
原文:
void cpu_loop(CPUX86State *env)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
trapnr = cpu_x86_exec(env);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int [=10=]x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
break;
#endif
修改:
void cpu_loop(CPUX86State *env)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
trapnr = cpu_x86_exec(env);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int [=11=]x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
----> if ((env->regs[R_EAX] == __NR_exit_group) || (env->regs[R_EAX] == __NR_exit)) {
return;
}
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
break;
#endif