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:
Richard Henderson 2022-03-15 01:43:05 -07:00 committed by Laurent Vivier
parent 7fb5ef350b
commit 0a99f09383
3 changed files with 66 additions and 23 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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