[smart] Fix bugs on lwp kill (#7892)

Signed-off-by: Shell <smokewood@qq.com>
This commit is contained in:
Shell 2023-08-03 20:25:13 +08:00 committed by GitHub
parent e5c8dd3b05
commit 325c3d2a48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 54 deletions

View File

@ -130,7 +130,6 @@ void *arch_signal_ucontext_restore(rt_base_t user_sp)
void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo, void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo,
struct rt_hw_exp_stack *exp_frame, struct rt_hw_exp_stack *exp_frame,
rt_base_t elr, rt_base_t spsr,
lwp_sigset_t *save_sig_mask) lwp_sigset_t *save_sig_mask)
{ {
struct signal_ucontext *new_sp; struct signal_ucontext *new_sp;
@ -147,11 +146,6 @@ void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo,
/* exp frame is already aligned as AAPCS64 required */ /* exp frame is already aligned as AAPCS64 required */
memcpy(&new_sp->frame, exp_frame, sizeof(*exp_frame)); memcpy(&new_sp->frame, exp_frame, sizeof(*exp_frame));
/* fix the 3 fields in exception frame, so that memcpy will be fine */
new_sp->frame.pc = elr;
new_sp->frame.cpsr = spsr;
new_sp->frame.sp_el0 = user_sp;
/* copy the save_sig_mask */ /* copy the save_sig_mask */
memcpy(&new_sp->save_sigmask, save_sig_mask, sizeof(lwp_sigset_t)); memcpy(&new_sp->save_sigmask, save_sig_mask, sizeof(lwp_sigset_t));

View File

@ -48,7 +48,6 @@ rt_inline void icache_invalid_all(void)
*/ */
void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo, void *arch_signal_ucontext_save(rt_base_t user_sp, siginfo_t *psiginfo,
struct rt_hw_exp_stack *exp_frame, struct rt_hw_exp_stack *exp_frame,
rt_base_t elr, rt_base_t spsr,
lwp_sigset_t *save_sig_mask); lwp_sigset_t *save_sig_mask);
/** /**

View File

@ -193,7 +193,7 @@ arch_syscall_exit:
add sp, sp, #0x40 add sp, sp, #0x40
RESTORE_FPU sp RESTORE_FPU sp
/* the sp is reset to the outer most level */ /* the sp is reset to the outer most level, irq and fiq are disabled */
START_POINT(arch_ret_to_user) START_POINT(arch_ret_to_user)
/* save exception frame */ /* save exception frame */
SAVE_FPU sp SAVE_FPU sp
@ -245,11 +245,18 @@ START_POINT(arch_ret_to_user)
/** /**
* push 2 dummy words to simulate a exception frame of interrupt * push 2 dummy words to simulate a exception frame of interrupt
* @note in kernel state, the context switch dont saved the context
*/ */
add sp, sp, #-0x10 mrs x0, spsr_el1
mrs x1, elr_el1
stp x1, x0, [sp, #-0x10]!
mov x0, sp mov x0, sp
msr daifclr, #3
bl lwp_thread_signal_catch bl lwp_thread_signal_catch
add sp, sp, #0x10 msr daifset, #3
ldp x1, x0, [sp], #0x10
msr spsr_el1, x0
msr elr_el1, x1
/* check debug */ /* check debug */
/* restore exception frame */ /* restore exception frame */
@ -405,7 +412,6 @@ arch_signal_quit:
msr spsr_el1, x3 msr spsr_el1, x3
ldp x29, x30, [sp], #0x10 ldp x29, x30, [sp], #0x10
// msr sp_el0, x29
ldp x28, x29, [sp], #0x10 ldp x28, x29, [sp], #0x10
msr fpcr, x28 msr fpcr, x28
@ -452,12 +458,9 @@ arch_thread_signal_enter:
* move exception frame to user stack * move exception frame to user stack
*/ */
mrs x0, sp_el0 mrs x0, sp_el0
mrs x3, elr_el1 mov x3, x4
mov x5, x4
/** FIXME: spsr must restore from exception frame */
mrs x4, spsr_el1
/* arch_signal_ucontext_save(user_sp, psiginfo, exp_frame, elr, spsr, save_sig_mask); */ /* arch_signal_ucontext_save(user_sp, psiginfo, exp_frame, save_sig_mask); */
bl arch_signal_ucontext_save bl arch_signal_ucontext_save
dc cvau, x0 dc cvau, x0
@ -469,7 +472,16 @@ arch_thread_signal_enter:
* @brief Prepare the environment for signal handler * @brief Prepare the environment for signal handler
*/ */
/** drop exp frame on kernel stack, reset kernel sp */ /**
* reset the cpsr
* and drop exp frame on kernel stack, reset kernel sp
*
* @note Since we will reset spsr, but the reschedule will
* corrupt the spsr, we diable irq for a short period here
*/
msr daifset, #3
ldr x1, [x20, #CONTEXT_OFFSET_SPSR_EL1]
msr spsr_el1, x1
add sp, x20, #CONTEXT_SIZE add sp, x20, #CONTEXT_SIZE
/** reset user sp */ /** reset user sp */

View File

@ -983,26 +983,31 @@ void lwp_terminate(struct rt_lwp *lwp)
return; return;
} }
LOG_D("%s(lwp=%p \"%s\")", __func__, lwp, lwp->cmd);
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
/* stop the receiving of signals */ /* stop the receiving of signals */
lwp->terminated = RT_TRUE; if (!lwp->terminated)
/* broadcast exit request for sibling threads */
for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
{ {
rt_thread_t thread; lwp->terminated = RT_TRUE;
thread = rt_list_entry(list, struct rt_thread, sibling); /* broadcast exit request for sibling threads */
if (thread->exit_request == LWP_EXIT_REQUEST_NONE) for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
{ {
thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED; rt_thread_t thread;
}
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) thread = rt_list_entry(list, struct rt_thread, sibling);
{ if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
thread->error = RT_EINTR; {
rt_hw_dsb(); thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
rt_thread_wakeup(thread); }
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
{
thread->error = RT_EINTR;
rt_hw_dsb();
rt_thread_wakeup(thread);
}
} }
} }
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
@ -1031,6 +1036,7 @@ void lwp_wait_subthread_exit(void)
while (1) while (1)
{ {
int subthread_is_terminated; int subthread_is_terminated;
LOG_D("%s: wait for subthread exiting", __func__);
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
subthread_is_terminated = (int)(thread->sibling.prev == &lwp->t_grp); subthread_is_terminated = (int)(thread->sibling.prev == &lwp->t_grp);

View File

@ -546,32 +546,36 @@ void lwp_thread_signal_catch(void *exp_frame)
* @note that the p_usi is release before entering signal action by * @note that the p_usi is release before entering signal action by
* reseting the kernel sp. * reseting the kernel sp.
*/ */
LOG_D("%s: enter signal handler(signo=%d) at %p", __func__, signo, handler);
arch_thread_signal_enter(signo, p_usi, exp_frame, handler, &save_sig_mask); arch_thread_signal_enter(signo, p_usi, exp_frame, handler, &save_sig_mask);
/* the arch_thread_signal_enter() never return */ /* the arch_thread_signal_enter() never return */
RT_ASSERT(0); RT_ASSERT(0);
} }
} }
static int _do_signal_wakeup(rt_thread_t thread, int sig) static int _do_signal_wakeup(rt_thread_t thread, int sig)
{ {
int need_schedule; int need_schedule;
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) if (!_sigismember(&thread->signal.sigset_mask, sig))
{ {
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK)
{ {
rt_thread_wakeup(thread); if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK)
need_schedule = 1; {
} rt_thread_wakeup(thread);
else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK)) need_schedule = 1;
{ }
rt_thread_wakeup(thread); else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK))
need_schedule = 1; {
rt_thread_wakeup(thread);
need_schedule = 1;
}
else
{
need_schedule = 0;
}
} }
else else
{
need_schedule = 0; need_schedule = 0;
}
} }
else else
need_schedule = 0; need_schedule = 0;
@ -633,7 +637,7 @@ static int _siginfo_deliver_to_lwp(struct rt_lwp *lwp, lwp_siginfo_t siginfo)
return _do_signal_wakeup(catcher, siginfo->ksiginfo.signo); return _do_signal_wakeup(catcher, siginfo->ksiginfo.signo);
} }
static int _siginfo_deliver_to_thread(struct rt_lwp *lwp, rt_thread_t thread, lwp_siginfo_t siginfo) static int _siginfo_deliver_to_thread(rt_thread_t thread, lwp_siginfo_t siginfo)
{ {
sigqueue_enqueue(_SIGQ(thread), siginfo); sigqueue_enqueue(_SIGQ(thread), siginfo);
return _do_signal_wakeup(thread, siginfo->ksiginfo.signo); return _do_signal_wakeup(thread, siginfo->ksiginfo.signo);
@ -679,6 +683,9 @@ rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code, long value)
} }
else else
{ {
LOG_D("%s(lwp=%p \"%s\",signo=%ld,code=%ld,value=%ld)",
__func__, lwp, lwp->cmd, signo, code, value);
need_schedule = RT_FALSE; need_schedule = RT_FALSE;
/* FIXME: acquire READ lock to lwp */ /* FIXME: acquire READ lock to lwp */
@ -848,7 +855,7 @@ rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, long
if (siginfo) if (siginfo)
{ {
need_schedule = _siginfo_deliver_to_thread(lwp, thread, siginfo); need_schedule = _siginfo_deliver_to_thread(thread, siginfo);
ret = 0; ret = 0;
} }
else else
@ -943,10 +950,10 @@ static int _dequeue_signal(rt_thread_t thread, lwp_sigset_t *mask, siginfo_t *us
rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset, rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
siginfo_t *usi, struct timespec *timeout) siginfo_t *usi, struct timespec *timeout)
{ {
LOG_D("%s", __func__);
rt_base_t level; rt_base_t level;
rt_err_t ret; rt_err_t ret;
lwp_sigset_t saved_sigset;
lwp_sigset_t blocked_sigset;
int sig; int sig;
/** /**
@ -960,6 +967,7 @@ rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
_sigdelset(sigset, SIGSTOP); _sigdelset(sigset, SIGSTOP);
_signotsets(sigset, sigset); _signotsets(sigset, sigset);
/* FIXME: acquire READ lock to lwp */ /* FIXME: acquire READ lock to lwp */
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
sig = _dequeue_signal(thread, sigset, usi); sig = _dequeue_signal(thread, sigset, usi);
@ -967,17 +975,19 @@ rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
if (sig) if (sig)
return sig; return sig;
/* WARNING atomic problem, what if pending signal arrives before we sleep */
/** /**
* @brief POSIX * @brief POSIX
* if none of the signals specified by set are pending, sigtimedwait() shall * if none of the signals specified by set are pending, sigtimedwait() shall
* wait for the time interval specified in the timespec structure referenced * wait for the time interval specified in the timespec structure referenced
* by timeout. * by timeout.
*
* @note If the pending signal arrives before thread suspend, the suspend
* operation will return a failure
*/ */
_sigandsets(&blocked_sigset, &thread->signal.sigset_mask, sigset);
_thread_signal_mask(thread, LWP_SIG_MASK_CMD_SET_MASK, &blocked_sigset, &saved_sigset);
if (timeout) if (timeout)
{ {
/* TODO: verify timeout valid ? not overflow 32bits, nanosec valid, ... */
rt_uint32_t time; rt_uint32_t time;
time = rt_timespec_to_tick(timeout); time = rt_timespec_to_tick(timeout);
@ -1006,9 +1016,14 @@ rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
if (ret == RT_EOK) if (ret == RT_EOK)
{ {
rt_schedule(); rt_schedule();
ret = -EAGAIN; /* If thread->error reliable? */
if (thread->error == -RT_EINTR)
ret = -EINTR;
else
ret = -EAGAIN;
} }
/* else ret == -EINTR */ /* else ret == -EINTR */
_thread_signal_mask(thread, LWP_SIG_MASK_CMD_SET_MASK, &saved_sigset, RT_NULL);
/* FIXME: acquire READ lock to lwp */ /* FIXME: acquire READ lock to lwp */
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();

View File

@ -347,10 +347,11 @@ void sys_exit(int value)
lwp_put_to_user(clear_child_tid, &t, sizeof t); lwp_put_to_user(clear_child_tid, &t, sizeof t);
sys_futex(clear_child_tid, FUTEX_WAKE, 1, RT_NULL, RT_NULL, 0); sys_futex(clear_child_tid, FUTEX_WAKE, 1, RT_NULL, RT_NULL, 0);
} }
lwp_terminate(lwp);
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling); main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
if (main_thread == tid) if (main_thread == tid)
{ {
lwp_terminate(lwp);
lwp_wait_subthread_exit(); lwp_wait_subthread_exit();
lwp->lwp_ret = value; lwp->lwp_ret = value;
} }
@ -3495,6 +3496,7 @@ sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct
} }
else else
{ {
/* if sigset of user is smaller, clear extra space */
memset(&lwpset, 0, sizeof(lwpset)); memset(&lwpset, 0, sizeof(lwpset));
} }
@ -3527,7 +3529,7 @@ sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct
sig = lwp_thread_signal_timedwait(rt_thread_self(), &lwpset, &kinfo, ptimeout); sig = lwp_thread_signal_timedwait(rt_thread_self(), &lwpset, &kinfo, ptimeout);
if (info) if (sig > 0 && info)
{ {
if (!lwp_user_accessable((void *)info, sizeof(*info))) if (!lwp_user_accessable((void *)info, sizeof(*info)))
return -EFAULT; return -EFAULT;