linux-user: Split out helpers for sigsuspend
Two new functions: process_sigsuspend_mask and finish_sigsuspend_mask. Move the size check and copy-from-user code. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20220315084308.433109-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
parent
7fb5ef350b
commit
0a99f09383
@ -92,4 +92,30 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
||||
*/
|
||||
int block_signals(void); /* Returns non zero if signal pending */
|
||||
|
||||
/**
|
||||
* process_sigsuspend_mask: read and apply syscall-local signal mask
|
||||
*
|
||||
* Read the guest signal mask from @sigset, length @sigsize.
|
||||
* Convert that to a host signal mask and save it to sigpending_mask.
|
||||
*
|
||||
* Return value: negative target errno, or zero;
|
||||
* store &sigpending_mask into *pset on success.
|
||||
*/
|
||||
int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
|
||||
target_ulong sigsize);
|
||||
|
||||
/**
|
||||
* finish_sigsuspend_mask: finish a sigsuspend-like syscall
|
||||
*
|
||||
* Set in_sigsuspend if we need to use the modified sigset
|
||||
* during process_pending_signals.
|
||||
*/
|
||||
static inline void finish_sigsuspend_mask(int ret)
|
||||
{
|
||||
if (ret != -QEMU_ERESTARTSYS) {
|
||||
TaskState *ts = (TaskState *)thread_cpu->opaque;
|
||||
ts->in_sigsuspend = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1199,3 +1199,26 @@ void process_pending_signals(CPUArchState *cpu_env)
|
||||
}
|
||||
ts->in_sigsuspend = 0;
|
||||
}
|
||||
|
||||
int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
|
||||
target_ulong sigsize)
|
||||
{
|
||||
TaskState *ts = (TaskState *)thread_cpu->opaque;
|
||||
sigset_t *host_set = &ts->sigsuspend_mask;
|
||||
target_sigset_t *target_sigset;
|
||||
|
||||
if (sigsize != sizeof(*target_sigset)) {
|
||||
/* Like the kernel, we enforce correct size sigsets */
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
target_sigset = lock_user(VERIFY_READ, sigset, sigsize, 1);
|
||||
if (!target_sigset) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_to_host_sigset(host_set, target_sigset);
|
||||
unlock_user(target_sigset, sigset, 0);
|
||||
|
||||
*pset = host_set;
|
||||
return 0;
|
||||
}
|
||||
|
@ -9557,41 +9557,35 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
#ifdef TARGET_NR_sigsuspend
|
||||
case TARGET_NR_sigsuspend:
|
||||
{
|
||||
TaskState *ts = cpu->opaque;
|
||||
sigset_t *set;
|
||||
|
||||
#if defined(TARGET_ALPHA)
|
||||
TaskState *ts = cpu->opaque;
|
||||
/* target_to_host_old_sigset will bswap back */
|
||||
abi_ulong mask = tswapal(arg1);
|
||||
target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
|
||||
set = &ts->sigsuspend_mask;
|
||||
target_to_host_old_sigset(set, &mask);
|
||||
#else
|
||||
if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
|
||||
return -TARGET_EFAULT;
|
||||
target_to_host_old_sigset(&ts->sigsuspend_mask, p);
|
||||
unlock_user(p, arg1, 0);
|
||||
#endif
|
||||
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
||||
SIGSET_T_SIZE));
|
||||
if (ret != -QEMU_ERESTARTSYS) {
|
||||
ts->in_sigsuspend = 1;
|
||||
ret = process_sigsuspend_mask(&set, arg1, sizeof(target_sigset_t));
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = get_errno(safe_rt_sigsuspend(set, SIGSET_T_SIZE));
|
||||
finish_sigsuspend_mask(ret);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
case TARGET_NR_rt_sigsuspend:
|
||||
{
|
||||
TaskState *ts = cpu->opaque;
|
||||
sigset_t *set;
|
||||
|
||||
if (arg2 != sizeof(target_sigset_t)) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
|
||||
return -TARGET_EFAULT;
|
||||
target_to_host_sigset(&ts->sigsuspend_mask, p);
|
||||
unlock_user(p, arg1, 0);
|
||||
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
|
||||
SIGSET_T_SIZE));
|
||||
if (ret != -QEMU_ERESTARTSYS) {
|
||||
ts->in_sigsuspend = 1;
|
||||
ret = process_sigsuspend_mask(&set, arg1, arg2);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = get_errno(safe_rt_sigsuspend(set, SIGSET_T_SIZE));
|
||||
finish_sigsuspend_mask(ret);
|
||||
}
|
||||
return ret;
|
||||
#ifdef TARGET_NR_rt_sigtimedwait
|
||||
|
Loading…
Reference in New Issue
Block a user