summaryrefslogtreecommitdiff
path: root/components/libc/posix/signal/posix_signal.c
blob: 780d872faf498b3b4b729d2d9e0b40cb8d261d28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*
 * Copyright (c) 2006-2023, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017/10/1      Bernard      The first version
 */

#include <rthw.h>
#include <rtthread.h>

#include <sys/time.h>
#include <sys/errno.h>

#include "posix_signal.h"

#define sig_valid(sig_no)   (sig_no >= 0 && sig_no < RT_SIG_MAX)

void (*signal(int sig, void (*func)(int))) (int)
{
    return rt_signal_install(sig, func);
}

/**
 * @brief    This function will examines, changes, or examines and changes the signal mask of the calling thread.
 *
 * @param    how indicates the way in which the existing set of blocked signals should be changed.
 *           The following are the possible values for option:
 *
 *              SIG_BLOCK       The set of blocked signals is the union of the current set and the set argument.
 *
 *              SIG_UNBLOCK     The signals in set are removed from the current set of blocked signals.
 *                              It is permissible to attempt to unblock a signal which is not blocked.
 *
 *              SIG_SETMASK     The set of blocked signals is set to the argument set.
 *
 * @param    set is a pointer to a sigset_t object that specifies the new set of blocked signals.
 *           If set is NULL, then the signal mask is unchanged (i.e., how is ignored)
 *
 * @param    oset is a pointer to a sigset_t object that is used to return the previous set of blocked signals.
 *           If oset is non-NULL, the previous value of the signal mask is stored in it.
 *
 * @return   Returns 0 on success.
 */
int sigprocmask (int how, const sigset_t *set, sigset_t *oset)
{
    rt_base_t level;
    rt_thread_t tid;

    tid = rt_thread_self();

    level = rt_hw_interrupt_disable();
    if (oset) *oset = tid->sig_mask;

    if (set)
    {
        switch(how)
        {
        case SIG_BLOCK:
            tid->sig_mask |= *set;
            break;
        case SIG_UNBLOCK:
            tid->sig_mask &= ~*set;
            break;
        case SIG_SETMASK:
            tid->sig_mask =  *set;
            break;
        default:
            break;
        }
    }
    rt_hw_interrupt_enable(level);

    return 0;
}

/**
 * @brief    This function will examines the signal mask of the calling thread.
 *
 * @param    set is a pointer to a sigset_t object that is used to return the previous set of blocked signals.
 *           If set is non-NULL, the previous value of the signal mask is stored in it.
 *
 * @return   Returns 0 on success.
 */
int sigpending (sigset_t *set)
{
    sigprocmask(SIG_SETMASK, RT_NULL, set);
    return 0;
}
/**
 * @brief    This function will temporarily replace the signal mask of the calling thread
 *           with the mask given and then suspends the thread until delivery of an expected signal
 *           or a signal whose action is to terminate a process.
 *
 * @param    set is a pointer of a sigset_t object that is used to replace the original mask of the calling thread.
 *
 * @return   Returns 0 on success.
 *           If the return value is any other values, it means that the signal wait failed.
 */
int sigsuspend (const sigset_t *set)
{
    int ret  = 0;
    sigset_t origin_set;
    sigset_t suspend_set;
    siginfo_t info;            /* unless paremeter */

    /* get the origin signal information */
    sigpending(&origin_set);

    /* set the new signal information */
    sigprocmask(SIG_BLOCK, set, RT_NULL);
    sigpending(&suspend_set);

    ret = rt_signal_wait(&suspend_set, &info, RT_WAITING_FOREVER);

    /* restore the original sigprocmask */
    sigprocmask(SIG_UNBLOCK, (sigset_t *)0xffffUL, RT_NULL);
    sigprocmask(SIG_BLOCK, &origin_set, RT_NULL);

    return ret;
}

/**
 * @brief    This function will install or confirm action for specified signal.
 *
 * @param    signum is the signal to be handled.
 *
 * @param    act is the new signal action, or NULL to restore default action.
 *
 * @param    oldact returns the previous signal action, or NULL if not required.
 *
 * @return   Returns 0 on success or -1 on failure.
 */
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
{
    rt_sighandler_t old = RT_NULL;

    if (!sig_valid(signum)) return -RT_ERROR;

    if (act)
        old = rt_signal_install(signum, act->sa_handler);
    else
    {
        old = rt_signal_install(signum, RT_NULL);
        rt_signal_install(signum, old);
    }

    if (oldact)
        oldact->sa_handler = old;

    return 0;
}
/**
 * @brief    This function will suspends execution of the calling thread until one of
 *           the signals in the given set is pending. If none of the signals specified
 *           are pending, it will wait for the specified time interval.
 *
 * @param    set is the set of signal values to be waited for.
 *
 * @param    info is a pointer to the received signal info.
 *
 * @param    timeout is a pointer to a timespec structure that specifys the waiting time.
 *
 * @return   Return 0 on success. Otherwise, return -1 and set errno to indicate the error.
 */
int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout)
{
    int ret  = 0;
    int tick = RT_WAITING_FOREVER;

    if (timeout)
    {
        tick = timeout->tv_sec * RT_TICK_PER_SECOND + timeout->tv_nsec * RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND;
    }

    ret = rt_signal_wait(set, info, tick);
    if (ret == 0) return 0;

    errno = ret;
    return -1;
}
/**
 * @brief    This function will suspend execution of the calling thread until one of
 *           the specified signal becomes pending and return the signal number.
 *
 * @param    set is the set of signal values to be waited for.
 *
 * @param    sig is a pointer to the received signal number.
 *
 * @return   Return 0 on success or -1 on failure.
 */
int sigwait(const sigset_t *set, int *sig)
{
    siginfo_t si;
    if (sigtimedwait(set, &si, 0) < 0)
        return -1;

    *sig = si.si_signo;
    return 0;
}
/**
 * @brief    This function will suspend execution of the calling thread until one of
 *           the specified signal is pending.
 *
 * @param    set is the set of signal values to be waited for.
 *
 * @param    info is a pointer to the received signal info.
 *
 * @return   Return 0 on success or -1 on failure.
 */
int sigwaitinfo(const sigset_t *set, siginfo_t *info)
{
    return sigtimedwait(set, info, NULL);
}

/**
 * @brief    This function willsend a signal to the caller
 *
 * @param    sig is the signal that is to be sent.
 *
 * @return   Returns 0 on success.
 */
int raise(int sig)
{
    rt_thread_kill(rt_thread_self(), sig);
    return 0;
}

#include <sys/types.h>
/**
 * @brief    Sends a signal to the caller.
 *
 * This function sends the signal specified by @p sig to the caller.
 *
 * @param    sig The signal to be sent.
 *           This should be one of the standard signal macros such as SIGUSR1, SIGUSR2, etc.
 *
 * @return   Returns 0 on success. If an error occurs, -1 is returned and errno is set appropriately.
 */
int sigqueue (pid_t pid, int signo, const union sigval value)
{
    /* no support, signal queue */

    return -1;
}