RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
signal.c
浏览该文件的文档.
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
40static struct rt_spinlock _thread_signal_lock = RT_SPINLOCK_INIT;
41
42struct siginfo_node
43{
44 siginfo_t si;
45 struct rt_slist_node list;
46};
47
48static struct rt_mempool *_siginfo_pool;
49static void _signal_deliver(rt_thread_t tid);
50void rt_thread_handle_sig(rt_bool_t clean_state);
51
52static 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
59static void _signal_entry(void *parameter)
60{
61 RT_UNUSED(parameter);
62
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);
77
78#ifdef RT_USING_SMP
79 rt_hw_context_switch_to((rt_uintptr_t)&parameter, tid);
80#else
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 */
95static 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
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 */
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 */
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 }
140 {
141 /* add signal state */
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 */
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
179void *rt_signal_check(void* context)
180{
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
233rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
234{
235 rt_base_t level;
236 rt_sighandler_t old = RT_NULL;
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
275void rt_signal_mask(int signo)
276{
277 rt_base_t level;
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
298void rt_signal_unmask(int signo)
299{
300 rt_base_t level;
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
333int 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;
338 struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL;
339
340 /* current context checking */
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 */
366 /* set thread stat as waiting for signal */
368
369 /* start timeout timer */
370 if (timeout != RT_WAITING_FOREVER)
371 {
372 /* reset the timeout of thread timer and start it */
375 &timeout);
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 */
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
452void rt_thread_handle_sig(rt_bool_t clean_state)
453{
454 rt_base_t level;
455
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 */
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 {
499 }
500 else
501 {
502 return;
503 }
504 }
505 }
506 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
507}
508
509void rt_thread_alloc_sig(rt_thread_t tid)
510{
511 int index;
512 rt_bool_t need_free = RT_FALSE;
513 rt_base_t level;
514 rt_sighandler_t *vectors;
515
516 vectors = (rt_sighandler_t *)RT_KERNEL_MALLOC(sizeof(rt_sighandler_t) * RT_SIG_MAX);
517 RT_ASSERT(vectors != RT_NULL);
518
519 for (index = 0; index < RT_SIG_MAX; index ++)
520 {
521 vectors[index] = _signal_default_handler;
522 }
523
524 level = rt_spin_lock_irqsave(&_thread_signal_lock);
525
526 if (tid->sig_vectors == RT_NULL)
527 {
528 tid->sig_vectors = vectors;
529 }
530 else
531 {
532 need_free = RT_TRUE;
533 }
534
535 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
536
537 if (need_free)
538 {
539 rt_free(vectors);
540 }
541}
542
543void rt_thread_free_sig(rt_thread_t tid)
544{
545 rt_base_t level;
546 struct siginfo_node *si_node;
547 rt_sighandler_t *sig_vectors;
548
549 level = rt_spin_lock_irqsave(&_thread_signal_lock);
550 si_node = (struct siginfo_node *)tid->si_list;
551 tid->si_list = RT_NULL;
552
553 sig_vectors = tid->sig_vectors;
554 tid->sig_vectors = RT_NULL;
555 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
556
557 if (si_node)
558 {
559 struct rt_slist_node *node;
560 struct rt_slist_node *node_to_free;
561
562 LOG_D("free signal info list");
563 node = &(si_node->list);
564 do
565 {
566 node_to_free = node;
567 node = node->next;
568 si_node = rt_slist_entry(node_to_free, struct siginfo_node, list);
569 rt_mp_free(si_node);
570 } while (node);
571 }
572
573 if (sig_vectors)
574 {
575 RT_KERNEL_FREE(sig_vectors);
576 }
577}
578
589int rt_thread_kill(rt_thread_t tid, int sig)
590{
591 siginfo_t si;
592 rt_base_t level;
593 struct siginfo_node *si_node;
594
595 RT_ASSERT(tid != RT_NULL);
596 if (!sig_valid(sig)) return -RT_EINVAL;
597
598 LOG_I("send signal: %d", sig);
599 si.si_signo = sig;
600 si.si_code = SI_USER;
601 si.si_value.sival_ptr = RT_NULL;
602
603 level = rt_spin_lock_irqsave(&_thread_signal_lock);
604 if (tid->sig_pending & sig_mask(sig))
605 {
606 /* whether already emits this signal? */
607 struct rt_slist_node *node;
608 struct siginfo_node *entry;
609
610 si_node = (struct siginfo_node *)tid->si_list;
611 if (si_node)
612 node = (struct rt_slist_node *)&si_node->list;
613 else
614 node = RT_NULL;
615
616 /* update sig info */
617 for (; (node) != RT_NULL; node = node->next)
618 {
619 entry = rt_slist_entry(node, struct siginfo_node, list);
620 if (entry->si.si_signo == sig)
621 {
622 memcpy(&(entry->si), &si, sizeof(siginfo_t));
623 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
624 return 0;
625 }
626 }
627 }
628 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
629
630 si_node = (struct siginfo_node *) rt_mp_alloc(_siginfo_pool, 0);
631 if (si_node)
632 {
633 rt_slist_init(&(si_node->list));
634 memcpy(&(si_node->si), &si, sizeof(siginfo_t));
635
636 level = rt_spin_lock_irqsave(&_thread_signal_lock);
637
638 if (tid->si_list)
639 {
640 struct siginfo_node *si_list;
641
642 si_list = (struct siginfo_node *)tid->si_list;
643 rt_slist_append(&(si_list->list), &(si_node->list));
644 }
645 else
646 {
647 tid->si_list = si_node;
648 }
649
650 /* a new signal */
651 tid->sig_pending |= sig_mask(sig);
652
653 rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
654 }
655 else
656 {
657 LOG_E("The allocation of signal info node failed.");
658 return -RT_EEMPTY;
659 }
660
661 /* deliver signal to this thread */
662 _signal_deliver(tid);
663
664 return RT_EOK;
665}
666
667int rt_system_signal_init(void)
668{
669 _siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node));
670 if (_siginfo_pool == RT_NULL)
671 {
672 LOG_E("create memory pool for signal info failed.");
673 RT_ASSERT(0);
674 }
675
676 return 0;
677}
678
679#endif /* RT_USING_SIGNALS */
struct rt_cpu * rt_cpu_index(int index)
This fucntion will return the cpu object corresponding to index.
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
This function will get or set some options of the timer
rt_err_t rt_timer_start(rt_timer_t timer)
This function will start the timer
#define RT_TIMER_CTRL_SET_TIME
int stat(const char *file, struct stat *buf)
rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock)
This function will disable the local interrupt and then lock the spinlock, will lock the thread sched...
#define RT_WAITING_FOREVER
void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
This function will unlock the spinlock and then restore current cpu interrupt status,...
rt_weak rt_uint8_t rt_interrupt_get_nest(void)
This function will return the nest of interrupt.
定义 irq.c:136
rt_inline void rt_slist_init(rt_slist_t *l)
initialize a single list
#define RT_ASSERT(EX)
#define rt_slist_entry(node, type, member)
get the struct for this single list node
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
rt_inline void rt_slist_append(rt_slist_t *l, rt_slist_t *n)
#define RT_DEBUG_IN_THREAD_CONTEXT
void * rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
This function will allocate a block from memory pool.
void rt_mp_free(void *block)
This function will release a memory block.
rt_mp_t rt_mp_create(const char *name, rt_size_t block_count, rt_size_t block_size)
This function will create a mempool object and allocate the memory pool from heap.
#define RT_THREAD_STAT_SIGNAL_MASK
#define RT_THREAD_STAT_SIGNAL_WAIT
rt_err_t rt_thread_suspend_with_flag(rt_thread_t thread, int suspend_flag)
This function will suspend the specified thread and change it to suspend state.
rt_thread_t rt_thread_self(void)
This function will return self thread object.
#define RT_THREAD_STAT_SIGNAL_PENDING
rt_err_t rt_thread_resume(rt_thread_t thread)
This function will resume a thread and put it to system ready queue.
struct rt_thread * rt_thread_t
#define RT_THREAD_SUSPEND_MASK
void rt_schedule(void)
This function will perform one scheduling. It will select one thread with the highest priority level ...
#define RT_THREAD_STAT_SIGNAL
@ RT_UNINTERRUPTIBLE
#define LOG_D(...)
#define LOG_E(fmt,...)
#define LOG_I(...)
#define RT_UNUSED(x)
#define RT_KERNEL_FREE(ptr)
#define RT_KERNEL_MALLOC(sz)
void rt_hw_context_switch_to(rt_ubase_t to)
rt_uint8_t * rt_hw_stack_init(void *entry, void *parameter, rt_uint8_t *stack_addr, void *exit)
#define RT_SCHED_CTX(thread)
rt_ubase_t rt_sched_lock_level_t
#define rt_cpu_get_id()
rt_int32_t rt_base_t
rt_base_t rt_uintptr_t
int rt_bool_t
#define RT_TRUE
unsigned int rt_uint32_t
#define RT_FALSE
#define RT_NULL
#define RT_SPINLOCK_INIT
signed int rt_int32_t
struct rt_thread * current_thread
struct rt_slist_node * next
rt_err_t error
void * sp
RT_SCHED_THREAD_CTX struct rt_timer thread_timer