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 * 2017/10/1 Bernard The first version
9 */
10
11 #include <rthw.h>
12 #include <rtthread.h>
13
14 #include <sys/time.h>
15 #include <sys/errno.h>
16
17 #include "posix_signal.h"
18
19 #define sig_valid(sig_no) (sig_no >= 0 && sig_no < RT_SIG_MAX)
20
signal(int sig,void (* func)(int))21 void (*signal(int sig, void (*func)(int))) (int)
22 {
23 return rt_signal_install(sig, func);
24 }
25
26 /**
27 * @brief This function will examines, changes, or examines and changes the signal mask of the calling thread.
28 *
29 * @param how indicates the way in which the existing set of blocked signals should be changed.
30 * The following are the possible values for option:
31 *
32 * SIG_BLOCK The set of blocked signals is the union of the current set and the set argument.
33 *
34 * SIG_UNBLOCK The signals in set are removed from the current set of blocked signals.
35 * It is permissible to attempt to unblock a signal which is not blocked.
36 *
37 * SIG_SETMASK The set of blocked signals is set to the argument set.
38 *
39 * @param set is a pointer to a sigset_t object that specifies the new set of blocked signals.
40 * If set is NULL, then the signal mask is unchanged (i.e., how is ignored)
41 *
42 * @param oset is a pointer to a sigset_t object that is used to return the previous set of blocked signals.
43 * If oset is non-NULL, the previous value of the signal mask is stored in it.
44 *
45 * @return Returns 0 on success.
46 */
sigprocmask(int how,const sigset_t * set,sigset_t * oset)47 int sigprocmask (int how, const sigset_t *set, sigset_t *oset)
48 {
49 rt_base_t level;
50 rt_thread_t tid;
51
52 tid = rt_thread_self();
53
54 level = rt_hw_interrupt_disable();
55 if (oset) *oset = tid->sig_mask;
56
57 if (set)
58 {
59 switch(how)
60 {
61 case SIG_BLOCK:
62 tid->sig_mask |= *set;
63 break;
64 case SIG_UNBLOCK:
65 tid->sig_mask &= ~*set;
66 break;
67 case SIG_SETMASK:
68 tid->sig_mask = *set;
69 break;
70 default:
71 break;
72 }
73 }
74 rt_hw_interrupt_enable(level);
75
76 return 0;
77 }
78
79 /**
80 * @brief This function will examines the signal mask of the calling thread.
81 *
82 * @param set is a pointer to a sigset_t object that is used to return the previous set of blocked signals.
83 * If set is non-NULL, the previous value of the signal mask is stored in it.
84 *
85 * @return Returns 0 on success.
86 */
sigpending(sigset_t * set)87 int sigpending (sigset_t *set)
88 {
89 sigprocmask(SIG_SETMASK, RT_NULL, set);
90 return 0;
91 }
92 /**
93 * @brief This function will temporarily replace the signal mask of the calling thread
94 * with the mask given and then suspends the thread until delivery of an expected signal
95 * or a signal whose action is to terminate a process.
96 *
97 * @param set is a pointer of a sigset_t object that is used to replace the original mask of the calling thread.
98 *
99 * @return Returns 0 on success.
100 * If the return value is any other values, it means that the signal wait failed.
101 */
sigsuspend(const sigset_t * set)102 int sigsuspend (const sigset_t *set)
103 {
104 int ret = 0;
105 sigset_t origin_set;
106 sigset_t suspend_set;
107 siginfo_t info; /* unless paremeter */
108
109 /* get the origin signal information */
110 sigpending(&origin_set);
111
112 /* set the new signal information */
113 sigprocmask(SIG_BLOCK, set, RT_NULL);
114 sigpending(&suspend_set);
115
116 ret = rt_signal_wait(&suspend_set, &info, RT_WAITING_FOREVER);
117
118 /* restore the original sigprocmask */
119 sigprocmask(SIG_UNBLOCK, (sigset_t *)0xffffUL, RT_NULL);
120 sigprocmask(SIG_BLOCK, &origin_set, RT_NULL);
121
122 return ret;
123 }
124
125 /**
126 * @brief This function will install or confirm action for specified signal.
127 *
128 * @param signum is the signal to be handled.
129 *
130 * @param act is the new signal action, or NULL to restore default action.
131 *
132 * @param oldact returns the previous signal action, or NULL if not required.
133 *
134 * @return Returns 0 on success or -1 on failure.
135 */
sigaction(int signum,const struct sigaction * act,struct sigaction * oldact)136 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
137 {
138 rt_sighandler_t old = RT_NULL;
139
140 if (!sig_valid(signum)) return -RT_ERROR;
141
142 if (act)
143 old = rt_signal_install(signum, act->sa_handler);
144 else
145 {
146 old = rt_signal_install(signum, RT_NULL);
147 rt_signal_install(signum, old);
148 }
149
150 if (oldact)
151 oldact->sa_handler = old;
152
153 return 0;
154 }
155 /**
156 * @brief This function will suspends execution of the calling thread until one of
157 * the signals in the given set is pending. If none of the signals specified
158 * are pending, it will wait for the specified time interval.
159 *
160 * @param set is the set of signal values to be waited for.
161 *
162 * @param info is a pointer to the received signal info.
163 *
164 * @param timeout is a pointer to a timespec structure that specifys the waiting time.
165 *
166 * @return Return 0 on success. Otherwise, return -1 and set errno to indicate the error.
167 */
sigtimedwait(const sigset_t * set,siginfo_t * info,const struct timespec * timeout)168 int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout)
169 {
170 int ret = 0;
171 int tick = RT_WAITING_FOREVER;
172
173 if (timeout)
174 {
175 tick = timeout->tv_sec * RT_TICK_PER_SECOND + timeout->tv_nsec * RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND;
176 }
177
178 ret = rt_signal_wait(set, info, tick);
179 if (ret == 0) return 0;
180
181 errno = ret;
182 return -1;
183 }
184 /**
185 * @brief This function will suspend execution of the calling thread until one of
186 * the specified signal becomes pending and return the signal number.
187 *
188 * @param set is the set of signal values to be waited for.
189 *
190 * @param sig is a pointer to the received signal number.
191 *
192 * @return Return 0 on success or -1 on failure.
193 */
sigwait(const sigset_t * set,int * sig)194 int sigwait(const sigset_t *set, int *sig)
195 {
196 siginfo_t si;
197 if (sigtimedwait(set, &si, 0) < 0)
198 return -1;
199
200 *sig = si.si_signo;
201 return 0;
202 }
203 /**
204 * @brief This function will suspend execution of the calling thread until one of
205 * the specified signal is pending.
206 *
207 * @param set is the set of signal values to be waited for.
208 *
209 * @param info is a pointer to the received signal info.
210 *
211 * @return Return 0 on success or -1 on failure.
212 */
sigwaitinfo(const sigset_t * set,siginfo_t * info)213 int sigwaitinfo(const sigset_t *set, siginfo_t *info)
214 {
215 return sigtimedwait(set, info, NULL);
216 }
217
218 /**
219 * @brief This function willsend a signal to the caller
220 *
221 * @param sig is the signal that is to be sent.
222 *
223 * @return Returns 0 on success.
224 */
raise(int sig)225 int raise(int sig)
226 {
227 rt_thread_kill(rt_thread_self(), sig);
228 return 0;
229 }
230
231 #include <sys/types.h>
232 /**
233 * @brief Sends a signal to the caller.
234 *
235 * This function sends the signal specified by @p sig to the caller.
236 *
237 * @param sig The signal to be sent.
238 * This should be one of the standard signal macros such as SIGUSR1, SIGUSR2, etc.
239 *
240 * @return Returns 0 on success. If an error occurs, -1 is returned and errno is set appropriately.
241 */
sigqueue(pid_t pid,int signo,const union sigval value)242 int sigqueue (pid_t pid, int signo, const union sigval value)
243 {
244 /* no support, signal queue */
245
246 return -1;
247 }
248
249