1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2017/10/5 Bernard the first version
9 * 2018/09/17 Jesven fix: in _signal_deliver RT_THREAD_STAT_MASK to RT_THREAD_STAT_SIGNAL_MASK
10 * 2018/11/22 Jesven in smp version rt_hw_context_switch_to add a param
11 */
12
13 #include <stdint.h>
14 #include <string.h>
15
16 #include <rthw.h>
17 #include <rtthread.h>
18
19 #ifdef RT_USING_SIGNALS
20
21 #ifndef RT_SIG_INFO_MAX
22 #define RT_SIG_INFO_MAX 32
23 #endif
24
25 // #define DBG_ENABLE
26 #define DBG_SECTION_NAME "SIGN"
27 #define DBG_COLOR
28 #define DBG_LEVEL DBG_LOG
29 #include <rtdbg.h>
30
31 #define sig_mask(sig_no) (1u << sig_no)
32 #define sig_valid(sig_no) (sig_no >= 0 && sig_no < RT_SIG_MAX)
33
34 struct siginfo_node
35 {
36 siginfo_t si;
37 struct rt_slist_node list;
38 };
39
40 static struct rt_mempool *_rt_siginfo_pool;
41 static void _signal_deliver(rt_thread_t tid);
42 void rt_thread_handle_sig(rt_bool_t clean_state);
43
_signal_default_handler(int signo)44 static void _signal_default_handler(int signo)
45 {
46 LOG_I("handled signo[%d] with default action.", signo);
47 return ;
48 }
49
_signal_entry(void * parameter)50 static void _signal_entry(void *parameter)
51 {
52 rt_thread_t tid = rt_thread_self();
53
54 dbg_enter;
55
56 /* handle signal */
57 rt_thread_handle_sig(RT_FALSE);
58
59 /* never come back... */
60 rt_hw_interrupt_disable();
61 /* return to thread */
62 tid->sp = tid->sig_ret;
63 tid->sig_ret = RT_NULL;
64
65 LOG_D("switch back to: 0x%08x\n", tid->sp);
66 tid->stat &= ~RT_THREAD_STAT_SIGNAL;
67
68 #ifdef RT_USING_SMP
69 rt_hw_context_switch_to((rt_ubase_t)&(tid->sp), tid);
70 #else
71 rt_hw_context_switch_to((rt_ubase_t)&(tid->sp));
72 #endif /*RT_USING_SMP*/
73 }
74
75 /*
76 * To deliver a signal to thread, there are cases:
77 * 1. When thread is suspended, function resumes thread and
78 * set signal stat;
79 * 2. When thread is ready:
80 * - If function delivers a signal to self thread, just handle
81 * it.
82 * - If function delivers a signal to another ready thread, OS
83 * should build a slice context to handle it.
84 */
_signal_deliver(rt_thread_t tid)85 static void _signal_deliver(rt_thread_t tid)
86 {
87 rt_ubase_t level;
88
89 /* thread is not interested in pended signals */
90 if (!(tid->sig_pending & tid->sig_mask)) return;
91
92 level = rt_hw_interrupt_disable();
93 if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
94 {
95 /* resume thread to handle signal */
96 rt_thread_resume(tid);
97 /* add signal state */
98 tid->stat |= RT_THREAD_STAT_SIGNAL;
99
100 rt_hw_interrupt_enable(level);
101
102 /* re-schedule */
103 rt_schedule();
104 }
105 else
106 {
107 if (tid == rt_thread_self())
108 {
109 /* add signal state */
110 tid->stat |= RT_THREAD_STAT_SIGNAL;
111
112 rt_hw_interrupt_enable(level);
113
114 /* do signal action in self thread context */
115 rt_thread_handle_sig(RT_TRUE);
116 }
117 else if (!((tid->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL))
118 {
119 /* add signal state */
120 tid->stat |= RT_THREAD_STAT_SIGNAL;
121
122 /* point to the signal handle entry */
123 tid->sig_ret = tid->sp;
124 tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL,
125 (void *)((char *)tid->sig_ret - 32), RT_NULL);
126
127 rt_hw_interrupt_enable(level);
128 LOG_D("signal stack pointer @ 0x%08x", tid->sp);
129
130 /* re-schedule */
131 rt_schedule();
132 }
133 else
134 {
135 rt_hw_interrupt_enable(level);
136 }
137 }
138 }
139
rt_signal_install(int signo,rt_sighandler_t handler)140 rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
141 {
142 rt_sighandler_t old = RT_NULL;
143 rt_thread_t tid = rt_thread_self();
144
145 if (!sig_valid(signo)) return SIG_ERR;
146
147 rt_enter_critical();
148 if (tid->sig_vectors == RT_NULL)
149 {
150 rt_thread_alloc_sig(tid);
151 }
152
153 if (tid->sig_vectors)
154 {
155 old = tid->sig_vectors[signo];
156
157 if (handler == SIG_IGN) tid->sig_vectors[signo] = RT_NULL;
158 else if (handler == SIG_DFL) tid->sig_vectors[signo] = _signal_default_handler;
159 else tid->sig_vectors[signo] = handler;
160 }
161 rt_exit_critical();
162
163 return old;
164 }
165
rt_signal_mask(int signo)166 void rt_signal_mask(int signo)
167 {
168 rt_base_t level;
169 rt_thread_t tid = rt_thread_self();
170
171 level = rt_hw_interrupt_disable();
172
173 tid->sig_mask &= ~sig_mask(signo);
174
175 rt_hw_interrupt_enable(level);
176 }
177
rt_signal_unmask(int signo)178 void rt_signal_unmask(int signo)
179 {
180 rt_base_t level;
181 rt_thread_t tid = rt_thread_self();
182
183 level = rt_hw_interrupt_disable();
184
185 tid->sig_mask |= sig_mask(signo);
186
187 /* let thread handle pended signals */
188 if (tid->sig_mask & tid->sig_pending)
189 {
190 rt_hw_interrupt_enable(level);
191 _signal_deliver(tid);
192 }
193 else
194 {
195 rt_hw_interrupt_enable(level);
196 }
197 }
198
rt_signal_wait(const rt_sigset_t * set,rt_siginfo_t * si,rt_int32_t timeout)199 int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
200 {
201 int ret = RT_EOK;
202 rt_base_t level;
203 rt_thread_t tid = rt_thread_self();
204 struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL;
205
206 /* current context checking */
207 RT_DEBUG_IN_THREAD_CONTEXT;
208
209 /* parameters check */
210 if (set == NULL || *set == 0 || si == NULL )
211 {
212 ret = -RT_EINVAL;
213 goto __done_return;
214 }
215
216 /* clear siginfo to avoid unknown value */
217 memset(si, 0x0, sizeof(rt_siginfo_t));
218
219 level = rt_hw_interrupt_disable();
220
221 /* already pending */
222 if (tid->sig_pending & *set) goto __done;
223
224 if (timeout == 0)
225 {
226 ret = -RT_ETIMEOUT;
227 goto __done_int;
228 }
229
230 /* suspend self thread */
231 rt_thread_suspend(tid);
232 /* set thread stat as waiting for signal */
233 tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT;
234
235 /* start timeout timer */
236 if (timeout != RT_WAITING_FOREVER)
237 {
238 /* reset the timeout of thread timer and start it */
239 rt_timer_control(&(tid->thread_timer),
240 RT_TIMER_CTRL_SET_TIME,
241 &timeout);
242 rt_timer_start(&(tid->thread_timer));
243 }
244 rt_hw_interrupt_enable(level);
245
246 /* do thread scheduling */
247 rt_schedule();
248
249 level = rt_hw_interrupt_disable();
250
251 /* remove signal waiting flag */
252 tid->stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;
253
254 /* check errno of thread */
255 if (tid->error == -RT_ETIMEOUT)
256 {
257 tid->error = RT_EOK;
258 rt_hw_interrupt_enable(level);
259
260 /* timer timeout */
261 ret = -RT_ETIMEOUT;
262 goto __done_return;
263 }
264
265 __done:
266 /* to get the first matched pending signals */
267 si_node = (struct siginfo_node *)tid->si_list;
268 while (si_node)
269 {
270 int signo;
271
272 signo = si_node->si.si_signo;
273 if (sig_mask(signo) & *set)
274 {
275 *si = si_node->si;
276
277 LOG_D("sigwait: %d sig raised!", signo);
278 if (si_prev) si_prev->list.next = si_node->list.next;
279 else tid->si_list = si_node->list.next;
280
281 /* clear pending */
282 tid->sig_pending &= ~sig_mask(signo);
283 rt_mp_free(si_node);
284 break;
285 }
286
287 si_prev = si_node;
288 si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
289 }
290
291 __done_int:
292 rt_hw_interrupt_enable(level);
293
294 __done_return:
295 return ret;
296 }
297
rt_thread_handle_sig(rt_bool_t clean_state)298 void rt_thread_handle_sig(rt_bool_t clean_state)
299 {
300 rt_base_t level;
301
302 rt_thread_t tid = rt_thread_self();
303 struct siginfo_node *si_node;
304
305 level = rt_hw_interrupt_disable();
306 if (tid->sig_pending & tid->sig_mask)
307 {
308 /* if thread is not waiting for signal */
309 if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT))
310 {
311 while (tid->sig_pending & tid->sig_mask)
312 {
313 int signo, error;
314 rt_sighandler_t handler;
315
316 si_node = (struct siginfo_node *)tid->si_list;
317 if (!si_node) break;
318
319 /* remove this sig info node from list */
320 if (si_node->list.next == RT_NULL)
321 tid->si_list = RT_NULL;
322 else
323 tid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
324
325 signo = si_node->si.si_signo;
326 handler = tid->sig_vectors[signo];
327 rt_hw_interrupt_enable(level);
328
329 LOG_D("handle signal: %d, handler 0x%08x", signo, handler);
330 if (handler) handler(signo);
331
332 level = rt_hw_interrupt_disable();
333 tid->sig_pending &= ~sig_mask(signo);
334 error = -RT_EINTR;
335
336 rt_mp_free(si_node); /* release this siginfo node */
337 /* set errno in thread tcb */
338 tid->error = error;
339 }
340
341 /* whether clean signal status */
342 if (clean_state == RT_TRUE) tid->stat &= ~RT_THREAD_STAT_SIGNAL;
343 }
344 }
345
346 rt_hw_interrupt_enable(level);
347 }
348
rt_thread_alloc_sig(rt_thread_t tid)349 void rt_thread_alloc_sig(rt_thread_t tid)
350 {
351 int index;
352 rt_base_t level;
353 rt_sighandler_t *vectors;
354
355 vectors = (rt_sighandler_t *)RT_KERNEL_MALLOC(sizeof(rt_sighandler_t) * RT_SIG_MAX);
356 RT_ASSERT(vectors != RT_NULL);
357
358 for (index = 0; index < RT_SIG_MAX; index ++)
359 {
360 vectors[index] = _signal_default_handler;
361 }
362
363 level = rt_hw_interrupt_disable();
364 tid->sig_vectors = vectors;
365 rt_hw_interrupt_enable(level);
366 }
367
rt_thread_free_sig(rt_thread_t tid)368 void rt_thread_free_sig(rt_thread_t tid)
369 {
370 rt_base_t level;
371 struct siginfo_node *si_list;
372 rt_sighandler_t *sig_vectors;
373
374 level = rt_hw_interrupt_disable();
375 si_list = (struct siginfo_node *)tid->si_list;
376 tid->si_list = RT_NULL;
377
378 sig_vectors = tid->sig_vectors;
379 tid->sig_vectors = RT_NULL;
380 rt_hw_interrupt_enable(level);
381
382 if (si_list)
383 {
384 struct rt_slist_node *node;
385 struct siginfo_node *si_node;
386
387 LOG_D("free signal info list");
388 node = &(si_list->list);
389 do
390 {
391 si_node = rt_slist_entry(node, struct siginfo_node, list);
392 rt_mp_free(si_node);
393
394 node = node->next;
395 } while (node);
396 }
397
398 if (sig_vectors)
399 {
400 RT_KERNEL_FREE(sig_vectors);
401 }
402 }
403
rt_thread_kill(rt_thread_t tid,int sig)404 int rt_thread_kill(rt_thread_t tid, int sig)
405 {
406 siginfo_t si;
407 rt_base_t level;
408 struct siginfo_node *si_node;
409
410 RT_ASSERT(tid != RT_NULL);
411 if (!sig_valid(sig)) return -RT_EINVAL;
412
413 LOG_I("send signal: %d", sig);
414 si.si_signo = sig;
415 si.si_code = SI_USER;
416 si.si_value.sival_ptr = RT_NULL;
417
418 level = rt_hw_interrupt_disable();
419 if (tid->sig_pending & sig_mask(sig))
420 {
421 /* whether already emits this signal? */
422 struct rt_slist_node *node;
423 struct siginfo_node *entry;
424
425 node = (struct rt_slist_node *)tid->si_list;
426 rt_hw_interrupt_enable(level);
427
428 /* update sig info */
429 rt_enter_critical();
430 for (; (node) != RT_NULL; node = node->next)
431 {
432 entry = rt_slist_entry(node, struct siginfo_node, list);
433 if (entry->si.si_signo == sig)
434 {
435 memcpy(&(entry->si), &si, sizeof(siginfo_t));
436 rt_exit_critical();
437 return 0;
438 }
439 }
440 rt_exit_critical();
441
442 /* disable interrupt to protect tcb */
443 level = rt_hw_interrupt_disable();
444 }
445 else
446 {
447 /* a new signal */
448 tid->sig_pending |= sig_mask(sig);
449 }
450 rt_hw_interrupt_enable(level);
451
452 si_node = (struct siginfo_node *) rt_mp_alloc(_rt_siginfo_pool, 0);
453 if (si_node)
454 {
455 rt_slist_init(&(si_node->list));
456 memcpy(&(si_node->si), &si, sizeof(siginfo_t));
457
458 level = rt_hw_interrupt_disable();
459 if (!tid->si_list) tid->si_list = si_node;
460 else
461 {
462 struct siginfo_node *si_list;
463
464 si_list = (struct siginfo_node *)tid->si_list;
465 rt_slist_append(&(si_list->list), &(si_node->list));
466 }
467 rt_hw_interrupt_enable(level);
468 }
469 else
470 {
471 LOG_E("The allocation of signal info node failed.");
472 }
473
474 /* deliver signal to this thread */
475 _signal_deliver(tid);
476
477 return RT_EOK;
478 }
479
rt_system_signal_init(void)480 int rt_system_signal_init(void)
481 {
482 _rt_siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node));
483 if (_rt_siginfo_pool == RT_NULL)
484 {
485 LOG_E("create memory pool for signal info failed.");
486 RT_ASSERT(0);
487 }
488
489 return 0;
490 }
491
492 #endif
493