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