1 /*
2  * Copyright (c) 2006-2021, 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     #ifdef ARCH_CPU_64BIT
23         #define RT_SIG_INFO_MAX 64
24     #else
25         #define RT_SIG_INFO_MAX 32
26     #endif /* ARCH_CPU_64BIT */
27 #endif /* RT_SIG_INFO_MAX */
28 
29 #define DBG_TAG     "SIGN"
30 #define DBG_LVL     DBG_WARNING
31 #include <rtdbg.h>
32 
33 #ifdef RT_USING_MUSLLIBC
34     #define sig_mask(sig_no)    (1u << (sig_no - 1))
35 #else
36     #define sig_mask(sig_no)    (1u << sig_no)
37 #endif
38 #define sig_valid(sig_no)   (sig_no >= 0 && sig_no < RT_SIG_MAX)
39 
40 static struct rt_spinlock _thread_signal_lock = RT_SPINLOCK_INIT;
41 
42 struct siginfo_node
43 {
44     siginfo_t si;
45     struct rt_slist_node list;
46 };
47 
48 static struct rt_mempool *_siginfo_pool;
49 static void _signal_deliver(rt_thread_t tid);
50 void rt_thread_handle_sig(rt_bool_t clean_state);
51 
_signal_default_handler(int signo)52 static void _signal_default_handler(int signo)
53 {
54     RT_UNUSED(signo);
55     LOG_I("handled signo[%d] with default action.", signo);
56     return ;
57 }
58 
_signal_entry(void * parameter)59 static void _signal_entry(void *parameter)
60 {
61     RT_UNUSED(parameter);
62 
63     rt_thread_t tid = rt_thread_self();
64 
65     /* handle signal */
66     rt_thread_handle_sig(RT_FALSE);
67 
68 #ifdef RT_USING_SMP
69 #else
70     /* return to thread */
71     tid->sp = tid->sig_ret;
72     tid->sig_ret = RT_NULL;
73 #endif /* RT_USING_SMP */
74 
75     LOG_D("switch back to: 0x%08x\n", tid->sp);
76     RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL;
77 
78 #ifdef RT_USING_SMP
79     rt_hw_context_switch_to((rt_uintptr_t)&parameter, tid);
80 #else
81     rt_hw_context_switch_to((rt_uintptr_t)&(tid->sp));
82 #endif /* RT_USING_SMP */
83 }
84 
85 /*
86  * To deliver a signal to thread, there are cases:
87  * 1. When thread is suspended, function resumes thread and
88  * set signal stat;
89  * 2. When thread is ready:
90  *   - If function delivers a signal to self thread, just handle
91  *    it.
92  *   - If function delivers a signal to another ready thread, OS
93  *    should build a slice context to handle it.
94  */
_signal_deliver(rt_thread_t tid)95 static void _signal_deliver(rt_thread_t tid)
96 {
97     rt_base_t level;
98 
99     level = rt_spin_lock_irqsave(&_thread_signal_lock);
100 
101     /* thread is not interested in pended signals */
102     if (!(tid->sig_pending & tid->sig_mask))
103     {
104         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
105         return;
106     }
107 
108     if ((RT_SCHED_CTX(tid).stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
109     {
110         /* resume thread to handle signal */
111 #ifdef RT_USING_SMART
112         rt_thread_wakeup(tid);
113 #else
114         rt_thread_resume(tid);
115 #endif
116         /* add signal state */
117         RT_SCHED_CTX(tid).stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
118 
119         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
120 
121         /* re-schedule */
122         rt_schedule();
123     }
124     else
125     {
126         if (tid == rt_thread_self())
127         {
128             /* add signal state */
129             RT_SCHED_CTX(tid).stat |= RT_THREAD_STAT_SIGNAL;
130 
131             rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
132 
133             /* do signal action in self thread context */
134             if (rt_interrupt_get_nest() == 0)
135             {
136                 rt_thread_handle_sig(RT_TRUE);
137             }
138         }
139         else if (!((RT_SCHED_CTX(tid).stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL))
140         {
141             /* add signal state */
142             RT_SCHED_CTX(tid).stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
143 
144 #ifdef RT_USING_SMP
145             {
146                 int cpu_id;
147 
148                 cpu_id = RT_SCHED_CTX(tid).oncpu;
149                 if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_cpu_get_id()))
150                 {
151                     rt_uint32_t cpu_mask;
152 
153                     cpu_mask = RT_CPU_MASK ^ (1 << cpu_id);
154                     rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
155                 }
156             }
157 #else
158             /* point to the signal handle entry */
159             RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
160             tid->sig_ret = tid->sp;
161             tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL,
162                                        (void *)((char *)tid->sig_ret - 32), RT_NULL);
163 #endif /* RT_USING_SMP */
164 
165             rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
166             LOG_D("signal stack pointer @ 0x%08x", tid->sp);
167 
168             /* re-schedule */
169             rt_schedule();
170         }
171         else
172         {
173             rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
174         }
175     }
176 }
177 
178 #ifdef RT_USING_SMP
rt_signal_check(void * context)179 void *rt_signal_check(void* context)
180 {
181     rt_sched_lock_level_t level;
182     int cpu_id;
183     struct rt_cpu* pcpu;
184     struct rt_thread *current_thread;
185 
186     level = rt_spin_lock_irqsave(&_thread_signal_lock);
187 
188     cpu_id = rt_cpu_get_id();
189     pcpu   = rt_cpu_index(cpu_id);
190     current_thread = pcpu->current_thread;
191 
192     if (pcpu->irq_nest)
193     {
194         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
195         return context;
196     }
197 
198     if (current_thread->cpus_lock_nest == 1)
199     {
200         if (RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_SIGNAL_PENDING)
201         {
202             void *sig_context;
203 
204             RT_SCHED_CTX(current_thread).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
205 
206             rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
207             sig_context = rt_hw_stack_init((void *)_signal_entry, context,
208                     (void*)((char*)context - 32), RT_NULL);
209             return sig_context;
210         }
211     }
212     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
213     return context;
214 }
215 #endif /* RT_USING_SMP */
216 
217 /**
218  * @brief    This function will install a processing function to a specific
219  *           signal and return the old processing function of this signal.
220  *
221  * @note     This function needs to be used in conjunction with the
222  *           rt_signal_unmask() function to make the signal effective.
223  *
224  * @see      rt_signal_unmask()
225  *
226  * @param    signo is a specific signal value (range: 0 ~ RT_SIG_MAX).
227  *
228  * @param    handler is sets the processing of signal value.
229  *
230  * @return   Return the old processing function of this signal. ONLY When the
231  *           return value is SIG_ERR, the operation is failed.
232  */
rt_signal_install(int signo,rt_sighandler_t handler)233 rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
234 {
235     rt_base_t level;
236     rt_sighandler_t old = RT_NULL;
237     rt_thread_t tid = rt_thread_self();
238 
239     if (!sig_valid(signo)) return SIG_ERR;
240 
241     level = rt_spin_lock_irqsave(&_thread_signal_lock);
242     if (tid->sig_vectors == RT_NULL)
243     {
244         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
245 
246         rt_thread_alloc_sig(tid);
247 
248         level = rt_spin_lock_irqsave(&_thread_signal_lock);
249     }
250 
251     if (tid->sig_vectors)
252     {
253         old = tid->sig_vectors[signo];
254 
255         if (handler == SIG_IGN) tid->sig_vectors[signo] = RT_NULL;
256         else if (handler == SIG_DFL) tid->sig_vectors[signo] = _signal_default_handler;
257         else tid->sig_vectors[signo] = handler;
258     }
259     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
260 
261     return old;
262 }
263 
264 /**
265  * @brief    This function will block the specified signal.
266  *
267  * @note     This function will block the specified signal, even if the
268  *           rt_thread_kill() function is called to send this signal to
269  *           the current thread, it will no longer take effect.
270  *
271  * @see      rt_thread_kill()
272  *
273  * @param    signo is a specific signal value (range: 0 ~ RT_SIG_MAX).
274  */
rt_signal_mask(int signo)275 void rt_signal_mask(int signo)
276 {
277     rt_base_t level;
278     rt_thread_t tid = rt_thread_self();
279 
280     level = rt_spin_lock_irqsave(&_thread_signal_lock);
281 
282     tid->sig_mask &= ~sig_mask(signo);
283 
284     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
285 }
286 
287 /**
288  * @brief    This function will unblock the specified signal.
289  *
290  * @note     This function will unblock the specified signal. After calling
291  *           the rt_thread_kill() function to send this signal to the current
292  *           thread, it will take effect.
293  *
294  * @see      rt_thread_kill()
295  *
296  * @param    signo is a specific signal value (range: 0 ~ RT_SIG_MAX).
297  */
rt_signal_unmask(int signo)298 void rt_signal_unmask(int signo)
299 {
300     rt_base_t level;
301     rt_thread_t tid = rt_thread_self();
302 
303     level = rt_spin_lock_irqsave(&_thread_signal_lock);
304 
305     tid->sig_mask |= sig_mask(signo);
306 
307     /* let thread handle pended signals */
308     if (tid->sig_mask & tid->sig_pending)
309     {
310         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
311         _signal_deliver(tid);
312     }
313     else
314     {
315         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
316     }
317 }
318 
319 /**
320  * @brief    This function will wait for the arrival of the set signal. If it does not wait for this signal, the thread will be
321  *           suspended until it waits for this signal or the waiting time exceeds the specified timeout: timeout.
322  *
323  * @param    set is the set of signal values to be waited for. Use the function
324  *           sigaddset() to add the signal.
325  *
326  * @param    si is a pointer to the received signal info. If you don't care about this value, you can use RT_NULL to set.
327  *
328  * @param    timeout is a timeout period (unit: an OS tick).
329  *
330  * @return   Return the operation status. When the return value is RT_EOK, the operation is successful.
331  *           If the return value is any other values, it means that the signal wait failed.
332  */
rt_signal_wait(const rt_sigset_t * set,rt_siginfo_t * si,rt_int32_t timeout)333 int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
334 {
335     int ret = RT_EOK;
336     rt_base_t level;
337     rt_thread_t tid = rt_thread_self();
338     struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL;
339 
340     /* current context checking */
341     RT_DEBUG_IN_THREAD_CONTEXT;
342 
343     /* parameters check */
344     if (set == NULL || *set == 0 || si == NULL )
345     {
346         ret = -RT_EINVAL;
347         goto __done_return;
348     }
349 
350     /* clear siginfo to avoid unknown value */
351     memset(si, 0x0, sizeof(rt_siginfo_t));
352 
353     level = rt_spin_lock_irqsave(&_thread_signal_lock);
354 
355     /* already pending */
356     if (tid->sig_pending & *set) goto __done;
357 
358     if (timeout == 0)
359     {
360         ret = -RT_ETIMEOUT;
361         goto __done_int;
362     }
363 
364     /* suspend self thread */
365     rt_thread_suspend_with_flag(tid, RT_UNINTERRUPTIBLE);
366     /* set thread stat as waiting for signal */
367     RT_SCHED_CTX(tid).stat |= RT_THREAD_STAT_SIGNAL_WAIT;
368 
369     /* start timeout timer */
370     if (timeout != RT_WAITING_FOREVER)
371     {
372         /* reset the timeout of thread timer and start it */
373         rt_timer_control(&(tid->thread_timer),
374                          RT_TIMER_CTRL_SET_TIME,
375                          &timeout);
376         rt_timer_start(&(tid->thread_timer));
377     }
378     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
379 
380     /* do thread scheduling */
381     rt_schedule();
382 
383     level = rt_spin_lock_irqsave(&_thread_signal_lock);
384 
385     /* remove signal waiting flag */
386     RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;
387 
388     /* check errno of thread */
389     if (tid->error == -RT_ETIMEOUT)
390     {
391         tid->error = RT_EOK;
392         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
393 
394         /* timer timeout */
395         ret = -RT_ETIMEOUT;
396         goto __done_return;
397     }
398 
399 __done:
400     /* to get the first matched pending signals */
401     si_node = (struct siginfo_node *)tid->si_list;
402     while (si_node)
403     {
404         int signo;
405 
406         signo = si_node->si.si_signo;
407         if (sig_mask(signo) & *set)
408         {
409             *si  = si_node->si;
410 
411             LOG_D("sigwait: %d sig raised!", signo);
412             if (si_prev) si_prev->list.next = si_node->list.next;
413             else
414             {
415                 struct siginfo_node *node_next;
416 
417                 if (si_node->list.next)
418                 {
419                     node_next = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
420                     tid->si_list = node_next;
421                 }
422                 else
423                 {
424                     tid->si_list = RT_NULL;
425                 }
426             }
427 
428             /* clear pending */
429             tid->sig_pending &= ~sig_mask(signo);
430             rt_mp_free(si_node);
431             break;
432         }
433 
434         si_prev = si_node;
435         if (si_node->list.next)
436         {
437             si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
438         }
439         else
440         {
441             si_node = RT_NULL;
442         }
443      }
444 
445 __done_int:
446     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
447 
448 __done_return:
449     return ret;
450 }
451 
rt_thread_handle_sig(rt_bool_t clean_state)452 void rt_thread_handle_sig(rt_bool_t clean_state)
453 {
454     rt_base_t level;
455 
456     rt_thread_t tid = rt_thread_self();
457     struct siginfo_node *si_node;
458 
459     level = rt_spin_lock_irqsave(&_thread_signal_lock);
460     if (tid->sig_pending & tid->sig_mask)
461     {
462         /* if thread is not waiting for signal */
463         if (!(RT_SCHED_CTX(tid).stat & RT_THREAD_STAT_SIGNAL_WAIT))
464         {
465             while (tid->sig_pending & tid->sig_mask)
466             {
467                 int signo, error;
468                 rt_sighandler_t handler;
469 
470                 si_node = (struct siginfo_node *)tid->si_list;
471                 if (!si_node) break;
472 
473                 /* remove this sig info node from list */
474                 if (si_node->list.next == RT_NULL)
475                     tid->si_list = RT_NULL;
476                 else
477                     tid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
478 
479                 signo   = si_node->si.si_signo;
480                 handler = tid->sig_vectors[signo];
481                 tid->sig_pending &= ~sig_mask(signo);
482                 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
483 
484                 LOG_D("handle signal: %d, handler 0x%08x", signo, handler);
485                 if (handler) handler(signo);
486 
487                 level = rt_spin_lock_irqsave(&_thread_signal_lock);
488                 error = -RT_EINTR;
489 
490                 rt_mp_free(si_node); /* release this siginfo node */
491                 /* set errno in thread tcb */
492                 tid->error = error;
493             }
494 
495             /* whether clean signal status */
496             if (clean_state == RT_TRUE)
497             {
498                 RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL;
499             }
500             else
501             {
502                 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
503                 return;
504             }
505         }
506     }
507     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
508 }
509 
rt_thread_alloc_sig(rt_thread_t tid)510 void rt_thread_alloc_sig(rt_thread_t tid)
511 {
512     int index;
513     rt_bool_t need_free = RT_FALSE;
514     rt_base_t level;
515     rt_sighandler_t *vectors;
516 
517     vectors = (rt_sighandler_t *)RT_KERNEL_MALLOC(sizeof(rt_sighandler_t) * RT_SIG_MAX);
518     RT_ASSERT(vectors != RT_NULL);
519 
520     for (index = 0; index < RT_SIG_MAX; index ++)
521     {
522         vectors[index] = _signal_default_handler;
523     }
524 
525     level = rt_spin_lock_irqsave(&_thread_signal_lock);
526 
527     if (tid->sig_vectors == RT_NULL)
528     {
529         tid->sig_vectors = vectors;
530     }
531     else
532     {
533         need_free = RT_TRUE;
534     }
535 
536     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
537 
538     if (need_free)
539     {
540         rt_free(vectors);
541     }
542 }
543 
rt_thread_free_sig(rt_thread_t tid)544 void rt_thread_free_sig(rt_thread_t tid)
545 {
546     rt_base_t level;
547     struct siginfo_node *si_node;
548     rt_sighandler_t *sig_vectors;
549 
550     level = rt_spin_lock_irqsave(&_thread_signal_lock);
551     si_node = (struct siginfo_node *)tid->si_list;
552     tid->si_list = RT_NULL;
553 
554     sig_vectors = tid->sig_vectors;
555     tid->sig_vectors = RT_NULL;
556     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
557 
558     if (si_node)
559     {
560         struct rt_slist_node *node;
561         struct rt_slist_node *node_to_free;
562 
563         LOG_D("free signal info list");
564         node = &(si_node->list);
565         do
566         {
567             node_to_free = node;
568             node = node->next;
569             si_node = rt_slist_entry(node_to_free, struct siginfo_node, list);
570             rt_mp_free(si_node);
571         } while (node);
572     }
573 
574     if (sig_vectors)
575     {
576         RT_KERNEL_FREE(sig_vectors);
577     }
578 }
579 
580 /**
581  * @brief    This function can be used to send any signal to any thread.
582  *
583  * @param    tid is a pointer to the thread that receives the signal.
584  *
585  * @param    sig is a specific signal value (range: 0 ~ RT_SIG_MAX).
586  *
587  * @return   Return the operation status. When the return value is RT_EOK, the operation is successful.
588  *           If the return value is any other values, it means that the signal send failed.
589  */
rt_thread_kill(rt_thread_t tid,int sig)590 int rt_thread_kill(rt_thread_t tid, int sig)
591 {
592     siginfo_t si;
593     rt_base_t level;
594     struct siginfo_node *si_node;
595 
596     RT_ASSERT(tid != RT_NULL);
597     if (!sig_valid(sig)) return -RT_EINVAL;
598 
599     LOG_I("send signal: %d", sig);
600     si.si_signo = sig;
601     si.si_code  = SI_USER;
602     si.si_value.sival_ptr = RT_NULL;
603 
604     level = rt_spin_lock_irqsave(&_thread_signal_lock);
605     if (tid->sig_pending & sig_mask(sig))
606     {
607         /* whether already emits this signal? */
608         struct rt_slist_node *node;
609         struct siginfo_node  *entry;
610 
611         si_node = (struct siginfo_node *)tid->si_list;
612         if (si_node)
613             node = (struct rt_slist_node *)&si_node->list;
614         else
615             node = RT_NULL;
616 
617         /* update sig info */
618         for (; (node) != RT_NULL; node = node->next)
619         {
620             entry = rt_slist_entry(node, struct siginfo_node, list);
621             if (entry->si.si_signo == sig)
622             {
623                 memcpy(&(entry->si), &si, sizeof(siginfo_t));
624                 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
625                 return 0;
626             }
627         }
628     }
629     rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
630 
631     si_node = (struct siginfo_node *) rt_mp_alloc(_siginfo_pool, 0);
632     if (si_node)
633     {
634         rt_slist_init(&(si_node->list));
635         memcpy(&(si_node->si), &si, sizeof(siginfo_t));
636 
637         level = rt_spin_lock_irqsave(&_thread_signal_lock);
638 
639         if (tid->si_list)
640         {
641             struct siginfo_node *si_list;
642 
643             si_list = (struct siginfo_node *)tid->si_list;
644             rt_slist_append(&(si_list->list), &(si_node->list));
645         }
646         else
647         {
648             tid->si_list = si_node;
649         }
650 
651         /* a new signal */
652         tid->sig_pending |= sig_mask(sig);
653 
654         rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
655     }
656     else
657     {
658         LOG_E("The allocation of signal info node failed.");
659         return -RT_EEMPTY;
660     }
661 
662     /* deliver signal to this thread */
663     _signal_deliver(tid);
664 
665     return RT_EOK;
666 }
667 
rt_system_signal_init(void)668 int rt_system_signal_init(void)
669 {
670     _siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node));
671     if (_siginfo_pool == RT_NULL)
672     {
673         LOG_E("create memory pool for signal info failed.");
674         RT_ASSERT(0);
675     }
676 
677     return 0;
678 }
679 
680 #endif /* RT_USING_SIGNALS */
681