/* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2020-02-23 Jesven first version. * 2023-07-06 Shell update the generation, pending and delivery API * 2023-11-22 Shell support for job control signal */ #ifndef __LWP_SIGNAL_H__ #define __LWP_SIGNAL_H__ #include "syscall_generic.h" #include #include #ifdef __cplusplus extern "C" { #endif #define _USIGNAL_SIGMASK(signo) (1u << ((signo)-1)) #define LWP_SIG_NO_IGN_SET \ (_USIGNAL_SIGMASK(SIGCONT) | _USIGNAL_SIGMASK(SIGSTOP) | \ _USIGNAL_SIGMASK(SIGKILL)) #define LWP_SIG_IGNORE_SET \ (_USIGNAL_SIGMASK(SIGCHLD) | _USIGNAL_SIGMASK(SIGURG) | \ _USIGNAL_SIGMASK(SIGWINCH) /* from 4.3 BSD, not POSIX.1 */) #define LWP_SIG_JOBCTL_SET \ (_USIGNAL_SIGMASK(SIGCONT) | _USIGNAL_SIGMASK(SIGSTOP) | \ _USIGNAL_SIGMASK(SIGTSTP) | _USIGNAL_SIGMASK(SIGTTIN) | \ _USIGNAL_SIGMASK(SIGTTOU)) #define LWP_SIG_STOP_SET \ (_USIGNAL_SIGMASK(SIGSTOP) | _USIGNAL_SIGMASK(SIGTSTP) | \ _USIGNAL_SIGMASK(SIGTTIN) | _USIGNAL_SIGMASK(SIGTTOU)) #define LWP_SIG_ACT_DFL ((lwp_sighandler_t)0) #define LWP_SIG_ACT_IGN ((lwp_sighandler_t)1) #define LWP_SIG_USER_SA_FLAGS \ (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS) #define LWP_SIG_INVALID_TIMER ((timer_t)-1) typedef enum { LWP_SIG_MASK_CMD_BLOCK, LWP_SIG_MASK_CMD_UNBLOCK, LWP_SIG_MASK_CMD_SET_MASK, __LWP_SIG_MASK_CMD_WATERMARK } lwp_sig_mask_cmd_t; /** * LwP implementation of POSIX signal */ struct lwp_signal { timer_t real_timer; struct lwp_sigqueue sig_queue; rt_thread_t sig_dispatch_thr[_LWP_NSIG]; lwp_sighandler_t sig_action[_LWP_NSIG]; lwp_sigset_t sig_action_mask[_LWP_NSIG]; lwp_sigset_t sig_action_nodefer; lwp_sigset_t sig_action_onstack; lwp_sigset_t sig_action_restart; lwp_sigset_t sig_action_siginfo; lwp_sigset_t sig_action_nocldstop; lwp_sigset_t sig_action_nocldwait; }; struct rt_lwp; struct rt_processgroup; #ifndef ARCH_MM_MMU void lwp_sighandler_set(int sig, lwp_sighandler_t func); void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func); #endif rt_inline void lwp_sigqueue_init(lwp_sigqueue_t sigq) { rt_memset(&sigq->sigset_pending, 0, sizeof(lwp_sigset_t)); rt_list_init(&sigq->siginfo_list); } /** * @brief release the signal queue * * @param sigq target signal queue */ void lwp_sigqueue_clear(lwp_sigqueue_t sigq); rt_err_t lwp_signal_init(struct lwp_signal *sig); rt_err_t lwp_signal_detach(struct lwp_signal *signal); rt_inline void lwp_thread_signal_detach(struct lwp_thread_signal *tsig) { lwp_sigqueue_clear(&tsig->sig_queue); } /** * @brief send a signal to the process * * @param lwp the process to be killed * @param signo the signal number * @param code as in siginfo * @param value as in siginfo * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as * successful * * @note the *signal_kill have the same definition of a successful return as * kill() in IEEE Std 1003.1-2017 */ rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code, lwp_siginfo_ext_t value); /** * @brief set or examine the signal action of signo * * @param signo signal number * @param act the signal action * @param oact the old signal action * @return rt_err_t */ rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo, const struct lwp_sigaction *restrict act, struct lwp_sigaction *restrict oact); /** * @brief send a signal to the thread * * @param thread target thread * @param signo the signal number * @param code as in siginfo * @param value as in siginfo * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as * successful */ rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, lwp_siginfo_ext_t value); /** * @brief set signal mask of target thread * * @param thread the target thread * @param how command * @param sigset operand * @param oset the address to old set * @return rt_err_t */ rt_err_t lwp_thread_signal_mask(rt_thread_t thread, lwp_sig_mask_cmd_t how, const lwp_sigset_t *sigset, lwp_sigset_t *oset); /** * @brief Catch signal if exists and no return, otherwise return with no * side effect * * @param exp_frame the exception frame on kernel stack */ void lwp_thread_signal_catch(void *exp_frame); /** * @brief Check if it's okay to suspend for current lwp thread * * @param thread target thread * @param suspend_flag suspend flag of target thread * @return int 1 if can be suspended, otherwise not */ int lwp_thread_signal_suspend_check(rt_thread_t thread, int suspend_flag); /** * @brief Asynchronously wait for signal * * @param thread target thread * @param sigset the signals to be waited * @param info address of user siginfo * @param timeout timeout of waiting * @return rt_err_t */ rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset, siginfo_t *usi, struct timespec *timeout); /** * @brief Examine the set of signals that are blocked from delivery to the * calling thread and that are pending on the process or the calling thread * * @param thread target thread * @param sigset where mask of pending signals is returned */ void lwp_thread_signal_pending(rt_thread_t thread, lwp_sigset_t *sigset); /** * @brief send a signal to the process group * * @param pgrp target process group * @param signo the signal number * @param code as in siginfo * @param value as in siginfo * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as * successful */ rt_err_t lwp_pgrp_signal_kill(struct rt_processgroup *pgrp, long signo, long code, lwp_siginfo_ext_t value); 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)); } } struct itimerspec; rt_bool_t lwp_sigisign(struct rt_lwp *lwp, int _sig); rt_err_t lwp_signal_setitimer(struct rt_lwp *lwp, int which, const struct itimerspec *restrict new, struct itimerspec *restrict old); rt_bool_t lwp_signal_restart_syscall(struct rt_lwp *lwp, int error_code); #ifdef __cplusplus } #endif #endif /* __LWP_SIGNAL_H__ */