123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- /*
- * Copyright (c) 2006-2020, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2019-11-12 Jesven first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include "lwp.h"
- #include "lwp_arch.h"
- #include "sys/signal.h"
- rt_inline void lwp_sigaddset(lwp_sigset_t *set, int _sig)
- {
- unsigned long sig = _sig - 1;
- if (_LWP_NSIG_WORDS == 1)
- {
- set->sig[0] |= 1UL << sig;
- }
- else
- {
- set->sig[sig / _LWP_NSIG_BPW] |= 1UL << (sig % _LWP_NSIG_BPW);
- }
- }
- rt_inline void lwp_sigdelset(lwp_sigset_t *set, int _sig)
- {
- unsigned long sig = _sig - 1;
- if (_LWP_NSIG_WORDS == 1)
- {
- set->sig[0] &= ~(1UL << sig);
- }
- else
- {
- set->sig[sig / _LWP_NSIG_BPW] &= ~(1UL << (sig % _LWP_NSIG_BPW));
- }
- }
- rt_inline int lwp_sigisemptyset(lwp_sigset_t *set)
- {
- switch (_LWP_NSIG_WORDS)
- {
- case 4:
- return (set->sig[3] | set->sig[2] |
- set->sig[1] | set->sig[0]) == 0;
- case 2:
- return (set->sig[1] | set->sig[0]) == 0;
- case 1:
- return set->sig[0] == 0;
- default:
- return 1;
- }
- }
- rt_inline int lwp_sigismember(lwp_sigset_t *set, int _sig)
- {
- unsigned long sig = _sig - 1;
- if (_LWP_NSIG_WORDS == 1)
- {
- return 1 & (set->sig[0] >> sig);
- }
- else
- {
- return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
- }
- }
- rt_inline int next_signal(lwp_sigset_t *pending, lwp_sigset_t *mask)
- {
- unsigned long i, *s, *m, x;
- int sig = 0;
- s = pending->sig;
- m = mask->sig;
- x = *s & ~*m;
- if (x)
- {
- sig = rt_hw_ffz(~x) + 1;
- return sig;
- }
- switch (_LWP_NSIG_WORDS)
- {
- default:
- for (i = 1; i < _LWP_NSIG_WORDS; ++i)
- {
- x = *++s &~ *++m;
- if (!x)
- continue;
- sig = rt_hw_ffz(~x) + i*_LWP_NSIG_BPW + 1;
- break;
- }
- break;
- case 2:
- x = s[1] &~ m[1];
- if (!x)
- break;
- sig = rt_hw_ffz(~x) + _LWP_NSIG_BPW + 1;
- break;
- case 1:
- /* Nothing to do */
- break;
- }
- return sig;
- }
- int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag)
- {
- struct rt_lwp *lwp = (struct rt_lwp*)thread->lwp;
- int ret = 0;
- switch (suspend_flag)
- {
- case RT_INTERRUPTIBLE:
- if (!lwp_sigisemptyset(&thread->signal))
- {
- break;
- }
- if (thread->lwp && !lwp_sigisemptyset(&lwp->signal))
- {
- break;
- }
- ret = 1;
- break;
- case RT_KILLABLE:
- if (lwp_sigismember(&thread->signal, SIGKILL))
- {
- break;
- }
- if (thread->lwp && lwp_sigismember(&lwp->signal, SIGKILL))
- {
- break;
- }
- ret = 1;
- break;
- case RT_UNINTERRUPTIBLE:
- ret = 1;
- break;
- default:
- RT_ASSERT(0);
- break;
- }
- return ret;
- }
- int lwp_signal_check(void)
- {
- rt_base_t level;
- struct rt_thread *thread;
- struct rt_lwp *lwp;
- uint32_t have_signal = 0;
- level = rt_hw_interrupt_disable();
- thread = rt_thread_self();
- if (thread->signal_in_process)
- {
- goto out;
- }
- lwp = (struct rt_lwp*)thread->lwp;
- if (lwp->signal_in_process)
- {
- goto out;
- }
- have_signal = !lwp_sigisemptyset(&thread->signal);
- if (have_signal)
- {
- thread->signal_in_process = 1;
- goto out;
- }
- have_signal = !lwp_sigisemptyset(&lwp->signal);
- if (have_signal)
- {
- lwp->signal_in_process = 1;
- }
- out:
- rt_hw_interrupt_enable(level);
- return have_signal;
- }
- int lwp_signal_backup(void *user_sp, void *user_pc, void* user_flag)
- {
- rt_base_t level;
- struct rt_thread *thread;
- struct rt_lwp *lwp;
- int signal;
- level = rt_hw_interrupt_disable();
- thread = rt_thread_self();
- if (thread->signal_in_process)
- {
- thread->user_ctx.sp = user_sp;
- thread->user_ctx.pc = user_pc;
- thread->user_ctx.flag = user_flag;
- signal = next_signal(&thread->signal, &thread->signal_mask);
- RT_ASSERT(signal != 0);
- lwp_sigaddset(&thread->signal_mask, signal);
- thread->signal_mask_bak = signal;
- lwp_sigdelset(&thread->signal, signal);
- }
- else
- {
- lwp = (struct rt_lwp*)thread->lwp;
- lwp->user_ctx.sp = user_sp;
- lwp->user_ctx.pc = user_pc;
- lwp->user_ctx.flag = user_flag;
- signal = next_signal(&lwp->signal, &lwp->signal_mask);
- RT_ASSERT(signal != 0);
- lwp_sigaddset(&lwp->signal_mask, signal);
- lwp->signal_mask_bak = signal;
- lwp_sigdelset(&lwp->signal, signal);
- }
- rt_hw_interrupt_enable(level);
- return signal;
- }
- struct rt_user_context *lwp_signal_restore(void)
- {
- rt_base_t level;
- struct rt_thread *thread;
- struct rt_lwp *lwp;
- struct rt_user_context *ctx;
- level = rt_hw_interrupt_disable();
- thread = rt_thread_self();
- if (thread->signal_in_process)
- {
- ctx = &thread->user_ctx;
- thread->signal_in_process = 0;
- lwp_sigdelset(&thread->signal_mask, thread->signal_mask_bak);
- thread->signal_mask_bak = 0;
- }
- else
- {
- lwp = (struct rt_lwp*)thread->lwp;
- ctx = &lwp->user_ctx;
- RT_ASSERT(lwp->signal_in_process != 0);
- lwp->signal_in_process = 0;
- lwp_sigdelset(&lwp->signal_mask, lwp->signal_mask_bak);
- lwp->signal_mask_bak = 0;
- }
- rt_hw_interrupt_enable(level);
- return ctx;
- }
- rt_inline int _lwp_check_ignore(int sig)
- {
- if (sig == SIGCHLD || sig == SIGCONT)
- {
- return 1;
- }
- return 0;
- }
- void sys_exit(int value);
- lwp_sighandler_t lwp_sighandler_get(int sig)
- {
- lwp_sighandler_t func = RT_NULL;
- struct rt_lwp *lwp;
- rt_thread_t thread;
- rt_base_t level;
- if (sig == 0 || sig > _LWP_NSIG)
- {
- return func;
- }
- level = rt_hw_interrupt_disable();
- thread = rt_thread_self();
- #ifndef ARCH_MM_MMU
- if (thread->signal_in_process)
- {
- func = thread->signal_handler[sig - 1];
- goto out;
- }
- #endif
- lwp = (struct rt_lwp*)thread->lwp;
- func = lwp->signal_handler[sig - 1];
- if (!func)
- {
- if (_lwp_check_ignore(sig))
- {
- goto out;
- }
- if (lwp->signal_in_process)
- {
- lwp_terminate(lwp);
- }
- sys_exit(0);
- }
- out:
- rt_hw_interrupt_enable(level);
- if (func == (lwp_sighandler_t)SIG_IGN)
- {
- func = RT_NULL;
- }
- return func;
- }
- void lwp_sighandler_set(int sig, lwp_sighandler_t func)
- {
- rt_base_t level;
- if (sig == 0 || sig > _LWP_NSIG)
- return;
- if (sig == SIGKILL || sig == SIGSTOP)
- return;
- level = rt_hw_interrupt_disable();
- ((struct rt_lwp*)rt_thread_self()->lwp)->signal_handler[sig - 1] = func;
- rt_hw_interrupt_enable(level);
- }
- #ifndef ARCH_MM_MMU
- void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func)
- {
- rt_base_t level;
- if (sig == 0 || sig > _LWP_NSIG)
- return;
- level = rt_hw_interrupt_disable();
- rt_thread_self()->signal_handler[sig - 1] = func;
- rt_hw_interrupt_enable(level);
- }
- #endif
- int lwp_sigaction(int sig, const struct lwp_sigaction *act,
- struct lwp_sigaction *oact, size_t sigsetsize)
- {
- rt_base_t level;
- struct rt_lwp *lwp;
- int ret = -RT_EINVAL;
- lwp_sigset_t newset;
- level = rt_hw_interrupt_disable();
- lwp = (struct rt_lwp*)rt_thread_self()->lwp;
- if (!lwp)
- {
- goto out;
- }
- if (sigsetsize != sizeof(lwp_sigset_t))
- {
- goto out;
- }
- if (!act && !oact)
- {
- goto out;
- }
- if (oact)
- {
- oact->sa_flags = lwp->sa_flags;
- oact->sa_mask = lwp->signal_mask;
- oact->sa_restorer = RT_NULL;
- oact->__sa_handler._sa_handler = lwp->signal_handler[sig - 1];
- }
- if (act)
- {
- lwp->sa_flags = act->sa_flags;
- newset = act->sa_mask;
- lwp_sigdelset(&newset, SIGKILL);
- lwp_sigdelset(&newset, SIGSTOP);
- lwp->signal_mask = newset;
- lwp_sighandler_set(sig, act->__sa_handler._sa_handler);
- }
- ret = 0;
- out:
- rt_hw_interrupt_enable(level);
- return ret;
- }
- rt_inline void sigorsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1)
- {
- switch (_LWP_NSIG_WORDS)
- {
- case 4:
- dset->sig[3] = set0->sig[3] | set1->sig[3];
- dset->sig[2] = set0->sig[2] | set1->sig[2];
- case 2:
- dset->sig[1] = set0->sig[1] | set1->sig[1];
- case 1:
- dset->sig[0] = set0->sig[0] | set1->sig[0];
- default:
- return;
- }
- }
- rt_inline void sigandsets(lwp_sigset_t *dset, const lwp_sigset_t *set0, const lwp_sigset_t *set1)
- {
- switch (_LWP_NSIG_WORDS)
- {
- case 4:
- dset->sig[3] = set0->sig[3] & set1->sig[3];
- dset->sig[2] = set0->sig[2] & set1->sig[2];
- case 2:
- dset->sig[1] = set0->sig[1] & set1->sig[1];
- case 1:
- dset->sig[0] = set0->sig[0] & set1->sig[0];
- default:
- return;
- }
- }
- int lwp_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset)
- {
- int ret = -1;
- rt_base_t level;
- struct rt_lwp *lwp;
- struct rt_thread *thread;
- lwp_sigset_t newset;
- level = rt_hw_interrupt_disable();
- thread = rt_thread_self();
- lwp = (struct rt_lwp*)thread->lwp;
- if (!lwp)
- {
- goto out;
- }
- if (oset)
- {
- rt_memcpy(oset, &lwp->signal_mask, sizeof(lwp_sigset_t));
- }
- if (sigset)
- {
- switch (how)
- {
- case SIG_BLOCK:
- sigorsets(&newset, &lwp->signal_mask, sigset);
- break;
- case SIG_UNBLOCK:
- sigandsets(&newset, &lwp->signal_mask, sigset);
- break;
- case SIG_SETMASK:
- newset = *sigset;
- break;
- default:
- ret = -RT_EINVAL;
- goto out;
- }
- lwp_sigdelset(&newset, SIGKILL);
- lwp_sigdelset(&newset, SIGSTOP);
- lwp->signal_mask = newset;
- }
- ret = 0;
- out:
- rt_hw_interrupt_enable(level);
- return ret;
- }
- int lwp_thread_sigprocmask(int how, const lwp_sigset_t *sigset, lwp_sigset_t *oset)
- {
- rt_base_t level;
- struct rt_thread *thread;
- lwp_sigset_t newset;
- level = rt_hw_interrupt_disable();
- thread = rt_thread_self();
- if (oset)
- {
- rt_memcpy(oset, &thread->signal_mask, sizeof(lwp_sigset_t));
- }
- if (sigset)
- {
- switch (how)
- {
- case SIG_BLOCK:
- sigorsets(&newset, &thread->signal_mask, sigset);
- break;
- case SIG_UNBLOCK:
- sigandsets(&newset, &thread->signal_mask, sigset);
- break;
- case SIG_SETMASK:
- newset = *sigset;
- break;
- default:
- goto out;
- }
- lwp_sigdelset(&newset, SIGKILL);
- lwp_sigdelset(&newset, SIGSTOP);
- thread->signal_mask = newset;
- }
- out:
- rt_hw_interrupt_enable(level);
- return 0;
- }
- static void _do_signal_wakeup(rt_thread_t thread, int sig)
- {
- if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
- {
- int need_schedule = 1;
- if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK)
- {
- rt_thread_wakeup(thread);
- }
- else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK))
- {
- rt_thread_wakeup(thread);
- }
- else
- {
- need_schedule = 0;
- }
- /* do schedule */
- if (need_schedule)
- {
- rt_schedule();
- }
- }
- }
- int lwp_kill(pid_t pid, int sig)
- {
- rt_base_t level;
- struct rt_lwp *lwp;
- int ret = -1;
- rt_thread_t thread;
- if (sig < 0 || sig >= _LWP_NSIG)
- {
- rt_set_errno(EINVAL);
- return ret;
- }
- level = rt_hw_interrupt_disable();
- lwp = lwp_from_pid(pid);
- if (!lwp || lwp->finish)
- {
- rt_set_errno(ESRCH);
- goto out;
- }
- if (sig)
- {
- /* check main thread */
- thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
- if (!lwp_sigismember(&lwp->signal_mask, sig)) /* if signal masked */
- {
- lwp_sigaddset(&lwp->signal, sig);
- _do_signal_wakeup(thread, sig);
- }
- }
- ret = 0;
- out:
- rt_hw_interrupt_enable(level);
- return ret;
- }
- int lwp_thread_kill(rt_thread_t thread, int sig)
- {
- rt_base_t level;
- int ret = -RT_EINVAL;
- if (!thread)
- {
- rt_set_errno(ESRCH);
- return ret;
- }
- if (sig < 0 || sig >= _LWP_NSIG)
- {
- rt_set_errno(EINVAL);
- return ret;
- }
- level = rt_hw_interrupt_disable();
- if (!thread->lwp)
- {
- rt_set_errno(EPERM);
- goto out;
- }
- if (!lwp_sigismember(&thread->signal_mask, sig)) /* if signal masked */
- {
- lwp_sigaddset(&thread->signal, sig);
- _do_signal_wakeup(thread, sig);
- }
- ret = 0;
- out:
- rt_hw_interrupt_enable(level);
- return ret;
- }
|