1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-02-23     Jesven       first version.
9  * 2023-07-06     Shell        update the generation, pending and delivery API
10  * 2023-11-22     Shell        support for job control signal
11  */
12 
13 #ifndef __LWP_SIGNAL_H__
14 #define __LWP_SIGNAL_H__
15 
16 #include "syscall_generic.h"
17 
18 #include <rtthread.h>
19 #include <sys/signal.h>
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
25 #define _USIGNAL_SIGMASK(signo) (1u << ((signo)-1))
26 #define LWP_SIG_NO_IGN_SET                                   \
27     (_USIGNAL_SIGMASK(SIGCONT) | _USIGNAL_SIGMASK(SIGSTOP) | \
28      _USIGNAL_SIGMASK(SIGKILL))
29 #define LWP_SIG_IGNORE_SET                                  \
30     (_USIGNAL_SIGMASK(SIGCHLD) | _USIGNAL_SIGMASK(SIGURG) | \
31      _USIGNAL_SIGMASK(SIGWINCH) /* from 4.3 BSD, not POSIX.1 */)
32 #define LWP_SIG_JOBCTL_SET                                   \
33     (_USIGNAL_SIGMASK(SIGCONT) | _USIGNAL_SIGMASK(SIGSTOP) | \
34      _USIGNAL_SIGMASK(SIGTSTP) | _USIGNAL_SIGMASK(SIGTTIN) | \
35      _USIGNAL_SIGMASK(SIGTTOU))
36 #define LWP_SIG_STOP_SET                                     \
37     (_USIGNAL_SIGMASK(SIGSTOP) | _USIGNAL_SIGMASK(SIGTSTP) | \
38      _USIGNAL_SIGMASK(SIGTTIN) | _USIGNAL_SIGMASK(SIGTTOU))
39 #define LWP_SIG_ACT_DFL ((lwp_sighandler_t)0)
40 #define LWP_SIG_ACT_IGN ((lwp_sighandler_t)1)
41 #define LWP_SIG_USER_SA_FLAGS                                             \
42     (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \
43      SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS)
44 #define LWP_SIG_INVALID_TIMER ((timer_t)-1)
45 
46 typedef enum
47 {
48     LWP_SIG_MASK_CMD_BLOCK,
49     LWP_SIG_MASK_CMD_UNBLOCK,
50     LWP_SIG_MASK_CMD_SET_MASK,
51     __LWP_SIG_MASK_CMD_WATERMARK
52 } lwp_sig_mask_cmd_t;
53 
54 /**
55  * LwP implementation of POSIX signal
56  */
57 struct lwp_signal
58 {
59     timer_t real_timer;
60     struct lwp_sigqueue sig_queue;
61     rt_thread_t sig_dispatch_thr[_LWP_NSIG];
62 
63     lwp_sighandler_t sig_action[_LWP_NSIG];
64     lwp_sigset_t sig_action_mask[_LWP_NSIG];
65 
66     lwp_sigset_t sig_action_nodefer;
67     lwp_sigset_t sig_action_onstack;
68     lwp_sigset_t sig_action_restart;
69     lwp_sigset_t sig_action_siginfo;
70     lwp_sigset_t sig_action_nocldstop;
71     lwp_sigset_t sig_action_nocldwait;
72 };
73 
74 struct rt_lwp;
75 struct rt_processgroup;
76 
77 #ifndef ARCH_MM_MMU
78 void lwp_sighandler_set(int sig, lwp_sighandler_t func);
79 void lwp_thread_sighandler_set(int sig, lwp_sighandler_t func);
80 #endif
81 
lwp_sigqueue_init(lwp_sigqueue_t sigq)82 rt_inline void lwp_sigqueue_init(lwp_sigqueue_t sigq)
83 {
84     rt_memset(&sigq->sigset_pending, 0, sizeof(lwp_sigset_t));
85     rt_list_init(&sigq->siginfo_list);
86 }
87 
88 /**
89  * @brief release the signal queue
90  *
91  * @param sigq target signal queue
92  */
93 void lwp_sigqueue_clear(lwp_sigqueue_t sigq);
94 
95 rt_err_t lwp_signal_init(struct lwp_signal *sig);
96 
97 rt_err_t lwp_signal_detach(struct lwp_signal *signal);
98 
lwp_thread_signal_detach(struct lwp_thread_signal * tsig)99 rt_inline void lwp_thread_signal_detach(struct lwp_thread_signal *tsig)
100 {
101     lwp_sigqueue_clear(&tsig->sig_queue);
102 }
103 
104 /**
105  * @brief send a signal to the process
106  *
107  * @param lwp the process to be killed
108  * @param signo the signal number
109  * @param code as in siginfo
110  * @param value as in siginfo
111  * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as
112  * successful
113  *
114  * @note the *signal_kill have the same definition of a successful return as
115  *       kill() in IEEE Std 1003.1-2017
116  */
117 rt_err_t lwp_signal_kill(struct rt_lwp *lwp, long signo, long code,
118                          lwp_siginfo_ext_t value);
119 
120 /**
121  * @brief set or examine the signal action of signo
122  *
123  * @param signo signal number
124  * @param act the signal action
125  * @param oact the old signal action
126  * @return rt_err_t
127  */
128 rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo,
129                            const struct lwp_sigaction *restrict act,
130                            struct lwp_sigaction *restrict oact);
131 
132 /**
133  * @brief send a signal to the thread
134  *
135  * @param thread target thread
136  * @param signo the signal number
137  * @param code as in siginfo
138  * @param value as in siginfo
139  * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as
140  * successful
141  */
142 rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code,
143                                 lwp_siginfo_ext_t value);
144 
145 /**
146  * @brief set signal mask of target thread
147  *
148  * @param thread the target thread
149  * @param how command
150  * @param sigset operand
151  * @param oset the address to old set
152  * @return rt_err_t
153  */
154 rt_err_t lwp_thread_signal_mask(rt_thread_t thread, lwp_sig_mask_cmd_t how,
155                                 const lwp_sigset_t *sigset, lwp_sigset_t *oset);
156 
157 /**
158  * @brief Catch signal if exists and no return, otherwise return with no
159  * side effect
160  *
161  * @param exp_frame the exception frame on kernel stack
162  */
163 void lwp_thread_signal_catch(void *exp_frame);
164 
165 /**
166  * @brief Check if it's okay to suspend for current lwp thread
167  *
168  * @param thread target thread
169  * @param suspend_flag suspend flag of target thread
170  * @return int 1 if can be suspended, otherwise not
171  */
172 int lwp_thread_signal_suspend_check(rt_thread_t thread, int suspend_flag);
173 
174 /**
175  * @brief Asynchronously wait for signal
176  *
177  * @param thread target thread
178  * @param sigset the signals to be waited
179  * @param info address of user siginfo
180  * @param timeout timeout of waiting
181  * @return rt_err_t
182  */
183 rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
184                                      siginfo_t *usi, struct timespec *timeout);
185 
186 /**
187  * @brief Examine the set of signals that are blocked from delivery to the
188  * calling thread and that are pending on the process or the calling thread
189  *
190  * @param thread target thread
191  * @param sigset where mask of pending signals is returned
192  */
193 void lwp_thread_signal_pending(rt_thread_t thread, lwp_sigset_t *sigset);
194 
195 /**
196  * @brief send a signal to the process group
197  *
198  * @param pgrp target process group
199  * @param signo the signal number
200  * @param code as in siginfo
201  * @param value as in siginfo
202  * @return rt_err_t RT_EINVAL if the parameter is invalid, RT_EOK as
203  * successful
204  */
205 rt_err_t lwp_pgrp_signal_kill(struct rt_processgroup *pgrp, long signo,
206                               long code, lwp_siginfo_ext_t value);
207 
lwp_sigismember(lwp_sigset_t * set,int _sig)208 rt_inline int lwp_sigismember(lwp_sigset_t *set, int _sig)
209 {
210     unsigned long sig = _sig - 1;
211 
212     if (_LWP_NSIG_WORDS == 1)
213     {
214         return 1 & (set->sig[0] >> sig);
215     }
216     else
217     {
218         return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
219     }
220 }
221 
222 struct itimerspec;
223 
224 rt_bool_t lwp_sigisign(struct rt_lwp *lwp, int _sig);
225 
226 rt_err_t lwp_signal_setitimer(struct rt_lwp *lwp, int which,
227                               const struct itimerspec *restrict new,
228                               struct itimerspec *restrict old);
229 
230 rt_bool_t lwp_signal_restart_syscall(struct rt_lwp *lwp, int error_code);
231 
232 rt_err_t lwp_signal_kill_all(long signo, long code, lwp_siginfo_ext_t value);
233 
234 #ifdef __cplusplus
235 }
236 #endif
237 
238 #endif /* __LWP_SIGNAL_H__ */
239