C QEMU用户模式仿真是否以防止pthread_join阻塞的方式退出?
我正在尝试将QEMU的用户模式模拟器作为一个线程运行在我正在编写的更大程序中。我修改了C QEMU用户模式仿真是否以防止pthread_join阻塞的方式退出?,c,multithreading,pthreads,qemu,system-calls,C,Multithreading,Pthreads,Qemu,System Calls,我正在尝试将QEMU的用户模式模拟器作为一个线程运行在我正在编写的更大程序中。我修改了linux user/main.c文件,使标准的int main(int-argc,char**argv,char**envp函数现在被称为void*qemu\u user\u mode\u func(void*arg)。我还将pthread\u exit(NULL)添加到该函数的末尾,这是pthreads的标准做法(或者我已经被告知) 但是,当我尝试运行包含我自己的测试函数的第二个线程时(如下面的void*t
linux user/main.c
文件,使标准的int main(int-argc,char**argv,char**envp
函数现在被称为void*qemu\u user\u mode\u func(void*arg)
。我还将pthread\u exit(NULL)
添加到该函数的末尾,这是pthreads的标准做法(或者我已经被告知)
但是,当我尝试运行包含我自己的测试函数的第二个线程时(如下面的void*test\u func(void*arg)
中所示),即使调用pthread\u join(
tid
),进程也会在第二个线程完成之前退出
,我已经读过它,它会阻止调用线程,直到线程tid
返回。QEMU的用户模式模拟退出时是否会阻止pthread\u join
退出,或者我只是使用了错误的线程
这是我的代码(不包括大部分的qemu\u user\u mode\u func
):
void*qemu\u user\u mode\u func(void*arg)
{
线程数据*线程数据;
int-argc;
字符**argv;
炭**envp;
/**QEMU标准码**/
//返回0;
pthread_exit(NULL);
}
void*test_func(void*arg){
结构时间段时间;
time.tv_sec=7;
time.tv_nsec=0;
纳秒睡眠(&时间,空);
printf(“你好,世界-来自线程\n”);
pthread_exit(NULL);
}
内部主(内部argc、字符**argv、字符**envp){
//初始化变量以创建线程
int rc;
pthread_t线程[2];
线程数据主参数;
main_args.tid=1;
main_args.argc=argc;
main_args.argv=argv;
main_args.envp=envp;
//创建线程
if((rc=pthread_create(&(threads[0]),NULL,test_func,NULL))){
fprintf(stderr,“错误:pthread_create,rc:%d\n”,rc);
返回退出失败;
}
if((rc=pthread_create(&(threads[1]),NULL,qemu_user_mode_func,(void*)和main_args))){
fprintf(stderr,“错误:pthread_create,rc:%d\n”,rc);
返回退出失败;
}
//等待线程完成,然后终止进程
对于(rc=0;rc<2;rc++){
pthread_join(线程[rc],NULL);
}
返回0;
}
编辑:我在
无效cpu_循环(CPUX86State*env)
函数中发现,当仿真程序得出结论时,QEMU调用syscall 231,这是系统退出_组
(根据)。因此,我猜这个系统调用将终止我正在运行的整个进程。我希望您能提供一些有关如何绕过这个问题的提示!如果您将一个复杂的预先存在的应用程序转换为线程,将会出现一些问题。其中之一是,应用程序可以调用exit
或其变体,从而终止整个程序。Th有许多其他问题可能会导致问题。我建议使用。如果您将一个复杂的现有应用程序转换为线程,则会出现一些问题。其中一个问题是,应用程序可以调用exit
或其变体,从而终止您的整个程序。还有许多其他问题可以解决使用问题。我建议使用。问题通过编辑无效cpu\u循环(CPUX86State*env)
中的以下部分得到解决。在执行系统调用之前,我捕获sys\u exit\u group
和sys\u exit
系统调用,然后从函数返回
原件:
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 $0x80 */
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 $0x80 */
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
通过编辑
void cpu\u loop(CPUX86State*env)
中的以下部分,问题得以解决。我在执行系统调用之前捕获了sys\u exit\u group
和sys\u exit
系统调用,而只是从函数返回
原件:
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 $0x80 */
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 $0x80 */
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
我非常清楚这一点——不幸的是,没有其他虚拟化程序执行(1)动态二进制转换,并且(2)具有AARCH64支持(我知道)。幸运的是,这有一个简单(尽管很难看)的修复。我非常清楚这一点——不幸的是,没有其他虚拟化程序执行(1)动态二进制翻译,并且(2)支持AARCH64(我知道)。幸运的是,它有一个简单的(尽管很难看)修复。你能解释一下你所做的改变,以便其他人将来能从中受益吗?@SevenBits是的-刚刚编辑了解决方案。也切换到了原来的标题-它认为它更好地抓住了问题的本质。谢谢你的建议!你能解释一下你所做的改变,以便其他人将来能从中受益吗?@SevenBits是的-刚刚编辑了解决方案。也切换到了原始标题-它认为它更好地抓住了问题的本质。谢谢你的建议!你为什么不干脆
fork()
并在forked child中调用qemu main函数?@caf-这与我如何使用qemu有关-主要是,我正在利用其中的动态二进制翻译系统,称为微型代码生成器。我试图在程序执行的一部分开始使用DBT-例如,程序从本机硬件启动,然后迁移到虚拟机执行的一部分。由于二进制文件的文本+数据部分在线程之间共享,因此对这些部分的任何内存引用在两个线程中都是有效的;所有更改都是堆栈(这是另一个野兽)。我同意fork
通常是更好的解决方案!为什么不干脆fork()
并在forked child中调用qemu main函数?@caf-这与我如何使用qemu有关-主要是,我正在利用其中的动态二进制翻译系统,称为微型代码生成器。我试图在程序执行的一部分开始使用DBT-例如,程序从本机硬件启动,然后迁移到虚拟机执行的一部分。由于