Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP3:GA
qemu-linux-user.11147
0002-XXX-work-around-SA_RESTART-race-wit.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0002-XXX-work-around-SA_RESTART-race-wit.patch of Package qemu-linux-user.11147
From 5f2f6db896424bf3b581f83b685f48c04096eca4 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Thu, 1 Dec 2011 19:00:01 +0100 Subject: [PATCH] XXX work around SA_RESTART race with boehm-gc (ARM only) [AF: CPUState -> CPUArchState, adapt to reindentation] [BR: fix references to opaque] --- linux-user/main.c | 25 +++++++----- linux-user/qemu.h | 3 ++ linux-user/signal.c | 22 +++++++++++ linux-user/syscall.c | 90 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 130 insertions(+), 10 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index af924dcc9d..c7423e615a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -814,15 +814,22 @@ void cpu_loop(CPUARMState *env) break; } } else { - env->regs[0] = do_syscall(env, - n, - env->regs[0], - env->regs[1], - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - 0, 0); + TaskState *ts = cs->opaque; + target_ulong r; + r = do_syscall(env, n, env->regs[0], env->regs[1], + env->regs[2], env->regs[3], env->regs[4], + env->regs[5], 0, 0); + if ((r == -EINTR) && ts->signal_restart && + syscall_restartable(n)) { + if (env->thumb) { + env->regs[15] -= 2; + } else { + env->regs[15] -= 4; + } + } else { + env->regs[0] = r; + } + ts->signal_restart = 0; } } else { goto error; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 36d4a738ea..a2c4e3546f 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -134,6 +134,8 @@ typedef struct TaskState { struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ struct sigqueue *first_free; /* first free siginfo queue entry */ int signal_pending; /* non zero if a signal may be pending */ + int signal_in_syscall; /* non zero if we are in do_syscall() */ + int signal_restart; /* non zero if we need to restart a syscall */ } __attribute__((aligned(16))) TaskState; extern char *exec_path; @@ -199,6 +201,7 @@ int get_osversion(void); void init_qemu_uname_release(void); void fork_start(void); void fork_end(int child); +int syscall_restartable(int syscall_nr); /* Creates the initial guest address space in the host memory space using * the given host start address hint and size. The guest_start parameter diff --git a/linux-user/signal.c b/linux-user/signal.c index 1bcf16f3be..cfaf501ee5 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -25,6 +25,7 @@ #include <assert.h> #include <sys/ucontext.h> #include <sys/resource.h> +#include <sched.h> #include "qemu.h" #include "qemu-common.h" @@ -571,6 +572,11 @@ int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) k->pending = 1; /* signal that a new signal is pending */ ts->signal_pending = 1; + /* check if we have to restart the current syscall */ + if ((sigact_table[sig - 1].sa_flags & SA_RESTART) && + ts->signal_in_syscall) { + ts->signal_restart = 1; + } return 1; /* indicates that the signal was queued */ } } @@ -706,8 +712,24 @@ int do_sigaction(int sig, const struct target_sigaction *act, if (host_sig != SIGSEGV && host_sig != SIGBUS) { sigfillset(&act1.sa_mask); act1.sa_flags = SA_SIGINFO; +#ifdef TARGET_ARM + /* Breaks boehm-gc, we have to do this manually */ + /* + * Unfortunately our hacks only work as long as we don't do parallel + * signal delivery and futexes, so let's do a dirty hack here to + * pin our guest process to a single host CPU if we're using the + * boehm-gc. + */ + if ((k->sa_flags & TARGET_SA_RESTART) && host_sig == SIGPWR) { + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(0, &mask); + sched_setaffinity(0, sizeof(mask), &mask); + } +#else if (k->sa_flags & TARGET_SA_RESTART) act1.sa_flags |= SA_RESTART; +#endif /* NOTE: it is important to update the host kernel signal ignore state to avoid getting unexpected interrupted syscalls */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2d28bdbe6b..e491bec1ee 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5259,6 +5259,87 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) return get_errno(open(path(pathname), flags, mode)); } +int syscall_restartable(int syscall_nr) +{ + switch (syscall_nr) { +#ifdef TARGET_NR_sigsuspend + case TARGET_NR_sigsuspend: +#endif +#ifdef TARGET_NR_pause + case TARGET_NR_pause: +#endif +#ifdef TARGET_NR_setsockopt + case TARGET_NR_setsockopt: +#endif +#ifdef TARGET_NR_accept + case TARGET_NR_accept: +#endif +#ifdef TARGET_NR_recv + case TARGET_NR_recv: +#endif +#ifdef TARGET_NR_recvfrom + case TARGET_NR_recvfrom: +#endif +#ifdef TARGET_NR_recvmsg + case TARGET_NR_recvmsg: +#endif +#ifdef TARGET_NR_socketcall + case TARGET_NR_socketcall: +#endif +#ifdef TARGET_NR_connect + case TARGET_NR_connect: +#endif +#ifdef TARGET_NR_send + case TARGET_NR_send: +#endif +#ifdef TARGET_NR_sendmsg + case TARGET_NR_sendmsg: +#endif +#ifdef TARGET_NR_sendto + case TARGET_NR_sendto: +#endif +#ifdef TARGET_NR_poll + case TARGET_NR_poll: +#endif +#ifdef TARGET_NR_ppoll + case TARGET_NR_ppoll: +#endif +#if defined(TARGET_NR_select) + case TARGET_NR_select: +#endif +#ifdef TARGET_NR_pselect6 + case TARGET_NR_pselect6: +#endif +#ifdef TARGET_NR__newselect + case TARGET_NR__newselect: +#endif +#ifdef TARGET_NR_msgrcv + case TARGET_NR_msgrcv: +#endif +#ifdef TARGET_NR_msgsnd + case TARGET_NR_msgsnd: +#endif +#ifdef TARGET_NR_semop + case TARGET_NR_semop: +#endif +#ifdef TARGET_NR_ipc + case TARGET_NR_ipc: +#endif +#ifdef TARGET_NR_clock_nanosleep + case TARGET_NR_clock_nanosleep: +#endif + case TARGET_NR_rt_sigsuspend: + case TARGET_NR_rt_sigtimedwait: + case TARGET_NR_nanosleep: + case TARGET_NR_close: + /* can not be restarted */ + return 0; + } + + /* every other syscall can be restarted */ + return 1; +} + /* do_syscall() should always have a single exit point at the end so that actions, such as logging of syscall results, can be performed. All errnos that do_syscall() returns must be -TARGET_<errcode>. */ @@ -5272,6 +5353,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct stat st; struct statfs stfs; void *p; + TaskState *ts = (TaskState*)cpu->opaque; + + if (!ts->signal_restart) { + /* remember syscall info for restart */ + ts->signal_in_syscall = 1; + } #ifdef DEBUG gemu_log("syscall %d", num); @@ -8473,7 +8560,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, cmd = target_to_host_fcntl_cmd(arg2); if (cmd == -TARGET_EINVAL) { ret = cmd; - break; + goto fail; } switch(arg2) { @@ -9411,6 +9498,7 @@ fail: #endif if(do_strace) print_syscall_ret(num, ret); + ts->signal_in_syscall = 0; return ret; efault: ret = -TARGET_EFAULT;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor