Merge pull request #1241 from BernardXiong/feature_signal

[Kernel] add sigwait implementation
This commit is contained in:
Bernard Xiong 2018-03-01 14:08:53 +08:00 committed by GitHub
commit 44def114fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 227 additions and 138 deletions

View File

@ -89,7 +89,22 @@ int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
int sigtimedwait(const sigset_t *set, siginfo_t *info, int sigtimedwait(const sigset_t *set, siginfo_t *info,
const struct timespec *timeout) const struct timespec *timeout)
{ {
return 0; int ret = 0;
int tick = RT_WAITING_FOREVER;
#ifdef RT_USING_PTHREADS
if (timeout)
{
extern int clock_time_to_tick(const struct timespec *time);
tick = clock_time_to_tick(timeout);
}
#endif
ret = rt_signal_wait(set, info, tick);
if (ret == 0) return 0;
errno = ret;
return -1;
} }
int sigwait(const sigset_t *set, int *sig) int sigwait(const sigset_t *set, int *sig)

View File

@ -30,6 +30,7 @@ extern "C" {
#endif #endif
#include <rtthread.h> #include <rtthread.h>
#include <sys/signal.h>
enum rt_signal_value{ enum rt_signal_value{
SIG1 = SIGHUP, SIG1 = SIGHUP,
@ -68,56 +69,6 @@ enum rt_signal_value{
SIGMAX = NSIG, SIGMAX = NSIG,
}; };
/*
The structure definitions on newlib:
typedef void (*_sig_func_ptr)(int);
struct sigaction
{
_sig_func_ptr sa_handler;
sigset_t sa_mask;
int sa_flags;
};
typedef int sig_atomic_t;
typedef _sig_func_ptr sig_t;
typedef _sig_func_ptr sighandler_t;
When enable POSIX_REALTIME_SIGNALS/POSIX_THREADS:
union sigval {
int sival_int;
void *sival_ptr;
};
struct sigevent {
int sigev_notify;
int sigev_signo;
union sigval sigev_value;
void (*sigev_notify_function)( union sigval );
pthread_attr_t *sigev_notify_attributes;
};
typedef struct {
int si_signo;
int si_code;
union sigval si_value;
} siginfo_t;
*/
rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler);
void rt_signal_mask(int signo);
void rt_signal_unmask(int signo);
int rt_thread_kill(rt_thread_t tid, int sig);
int rt_system_signal_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -30,6 +30,7 @@
extern "C" { extern "C" {
#endif #endif
#ifndef HAVE_SYS_SIGNALS
/* Signal Generation and Delivery, P1003.1b-1993, p. 63 /* Signal Generation and Delivery, P1003.1b-1993, p. 63
NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and
sigev_notify_attributes to the sigevent structure. */ sigev_notify_attributes to the sigevent structure. */
@ -59,6 +60,7 @@ struct siginfo
union sigval si_value; union sigval si_value;
}; };
typedef struct siginfo siginfo_t; typedef struct siginfo siginfo_t;
#endif
#define SI_USER 0x01 /* Signal sent by kill(). */ #define SI_USER 0x01 /* Signal sent by kill(). */
#define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */ #define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */

View File

@ -451,8 +451,10 @@ typedef struct rt_timer *rt_timer_t;
* @addtogroup Signal * @addtogroup Signal
*/ */
#ifdef RT_USING_SIGNALS #ifdef RT_USING_SIGNALS
#include <libc/libc_signal.h>
typedef unsigned long rt_sigset_t; typedef unsigned long rt_sigset_t;
typedef void (*rt_sighandler_t)(int signo); typedef void (*rt_sighandler_t)(int signo);
typedef siginfo_t rt_siginfo_t;
#define RT_SIG_MAX 32 #define RT_SIG_MAX 32
#endif #endif
@ -481,7 +483,7 @@ typedef void (*rt_sighandler_t)(int signo);
#define RT_THREAD_STAT_SIGNAL 0x10 #define RT_THREAD_STAT_SIGNAL 0x10
#define RT_THREAD_STAT_SIGNAL_READY (RT_THREAD_STAT_SIGNAL | RT_THREAD_READY) #define RT_THREAD_STAT_SIGNAL_READY (RT_THREAD_STAT_SIGNAL | RT_THREAD_READY)
#define RT_THREAD_STAT_SIGNAL_SUSPEND 0x20 #define RT_THREAD_STAT_SIGNAL_WAIT 0x20
#define RT_THREAD_STAT_SIGNAL_MASK 0xf0 #define RT_THREAD_STAT_SIGNAL_MASK 0xf0
/** /**

View File

@ -204,6 +204,7 @@ void rt_scheduler_sethook(void (*hook)(rt_thread_t from, rt_thread_t to));
void rt_signal_mask(int signo); void rt_signal_mask(int signo);
void rt_signal_unmask(int signo); void rt_signal_unmask(int signo);
rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler); rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler);
int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout);
int rt_system_signal_init(void); int rt_system_signal_init(void);
#endif #endif

View File

@ -293,7 +293,7 @@ void rt_schedule_insert_thread(struct rt_thread *thread)
temp = rt_hw_interrupt_disable(); temp = rt_hw_interrupt_disable();
/* change stat */ /* change stat */
thread->stat = RT_THREAD_READY; thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
/* insert thread to ready list */ /* insert thread to ready list */
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]), rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),

View File

@ -80,6 +80,16 @@ static void _signal_entry(void *parameter)
rt_hw_context_switch_to((rt_uint32_t) & (tid->sp)); rt_hw_context_switch_to((rt_uint32_t) & (tid->sp));
} }
/*
* To deliver a signal to thread, there are cases:
* 1. When thread is suspended, function resumes thread and
* set signal stat;
* 2. When thread is ready:
* - If function delivers a signal to self thread, just handle
* it.
* - If function delivers a signal to another ready thread, OS
* should build a slice context to handle it.
*/
static void _signal_deliver(rt_thread_t tid) static void _signal_deliver(rt_thread_t tid)
{ {
rt_ubase_t level; rt_ubase_t level;
@ -88,7 +98,7 @@ static void _signal_deliver(rt_thread_t tid)
if (!(tid->sig_pending & tid->sig_mask)) return; if (!(tid->sig_pending & tid->sig_mask)) return;
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
if (tid->stat == RT_THREAD_SUSPEND) if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
{ {
/* resume thread to handle signal */ /* resume thread to handle signal */
rt_thread_resume(tid); rt_thread_resume(tid);
@ -106,14 +116,17 @@ static void _signal_deliver(rt_thread_t tid)
{ {
/* add signal state */ /* add signal state */
tid->stat |= RT_THREAD_STAT_SIGNAL; tid->stat |= RT_THREAD_STAT_SIGNAL;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
/* do signal action in self thread context */ /* do signal action in self thread context */
rt_thread_handle_sig(RT_TRUE); rt_thread_handle_sig(RT_TRUE);
} }
else if (!(tid->stat & RT_THREAD_STAT_SIGNAL)) else if (!((tid->stat & RT_THREAD_STAT_MASK) & RT_THREAD_STAT_SIGNAL))
{ {
/* add signal state */
tid->stat |= RT_THREAD_STAT_SIGNAL; tid->stat |= RT_THREAD_STAT_SIGNAL;
/* point to the signal handle entry */ /* point to the signal handle entry */
tid->sig_ret = tid->sp; tid->sig_ret = tid->sp;
tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL, tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL,
@ -191,6 +204,105 @@ void rt_signal_unmask(int signo)
} }
} }
int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
{
int ret = RT_EOK;
rt_base_t level;
rt_thread_t tid = rt_thread_self();
struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL;
/* current context checking */
RT_DEBUG_IN_THREAD_CONTEXT;
/* parameters check */
if (set == NULL || *set == 0 || si == NULL )
{
ret = -RT_EINVAL;
goto __done_return;
}
/* clear siginfo to avoid unknown value */
memset(si, 0x0, sizeof(rt_siginfo_t));
level = rt_hw_interrupt_disable();
/* already pending */
if (tid->sig_pending & *set) goto __done;
if (timeout == 0)
{
ret = -RT_ETIMEOUT;
goto __done_int;
}
/* suspend self thread */
rt_thread_suspend(tid);
/* set thread stat as waiting for signal */
tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT;
/* start timeout timer */
if (timeout != RT_WAITING_FOREVER)
{
/* reset the timeout of thread timer and start it */
rt_timer_control(&(tid->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
rt_timer_start(&(tid->thread_timer));
}
rt_hw_interrupt_enable(level);
/* do thread scheduling */
rt_schedule();
level = rt_hw_interrupt_disable();
/* remove signal waiting flag */
tid->stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;
/* check errno of thread */
if (tid->error == -RT_ETIMEOUT)
{
tid->error = RT_EOK;
rt_hw_interrupt_enable(level);
/* timer timeout */
ret = -RT_ETIMEOUT;
goto __done_return;
}
__done:
/* to get the first matched pending signals */
si_node = (struct siginfo_node *)tid->si_list;
while (si_node)
{
int signo;
signo = si_node->si.si_signo;
if (sig_mask(signo) & *set)
{
*si = si_node->si;
dbg_log(DBG_LOG, "sigwait: %d sig raised!\n", signo);
if (si_prev) si_prev->list.next = si_node->list.next;
else tid->si_list = si_node->list.next;
/* clear pending */
tid->sig_pending &= ~sig_mask(signo);
rt_mp_free(si_node);
break;
}
si_prev = si_node;
si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
}
__done_int:
rt_hw_interrupt_enable(level);
__done_return:
return ret;
}
void rt_thread_handle_sig(rt_bool_t clean_state) void rt_thread_handle_sig(rt_bool_t clean_state)
{ {
rt_base_t level; rt_base_t level;
@ -199,6 +311,11 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
struct siginfo_node *si_node; struct siginfo_node *si_node;
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
if (tid->sig_pending & tid->sig_mask)
{
/* if thread is not waiting for signal */
if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT))
{
while (tid->sig_pending & tid->sig_mask) while (tid->sig_pending & tid->sig_mask)
{ {
int signo, error; int signo, error;
@ -231,6 +348,8 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
/* whether clean signal status */ /* whether clean signal status */
if (clean_state == RT_TRUE) tid->stat &= ~RT_THREAD_STAT_SIGNAL; if (clean_state == RT_TRUE) tid->stat &= ~RT_THREAD_STAT_SIGNAL;
}
}
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
} }
@ -315,7 +434,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
node = (struct rt_slist_node *)tid->si_list; node = (struct rt_slist_node *)tid->si_list;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
/* update sig infor */ /* update sig info */
rt_enter_critical(); rt_enter_critical();
for (; (node) != RT_NULL; node = node->next) for (; (node) != RT_NULL; node = node->next)
{ {
@ -358,7 +477,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
} }
else else
{ {
dbg_log(DBG_ERROR, "The allocation of signal infor node failed.\n"); dbg_log(DBG_ERROR, "The allocation of signal info node failed.\n");
} }
/* deliver signal to this thread */ /* deliver signal to this thread */
@ -380,4 +499,3 @@ int rt_system_signal_init(void)
} }
#endif #endif

View File

@ -638,7 +638,7 @@ rt_err_t rt_thread_suspend(rt_thread_t thread)
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY) if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
{ {
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, %d\n", RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
thread->stat)); thread->stat));
return -RT_ERROR; return -RT_ERROR;
@ -648,7 +648,7 @@ rt_err_t rt_thread_suspend(rt_thread_t thread)
temp = rt_hw_interrupt_disable(); temp = rt_hw_interrupt_disable();
/* change thread stat */ /* change thread stat */
thread->stat = RT_THREAD_SUSPEND; thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
rt_schedule_remove_thread(thread); rt_schedule_remove_thread(thread);
/* stop thread timer anyway */ /* stop thread timer anyway */

View File

@ -396,7 +396,7 @@ rt_err_t rt_timer_start(rt_timer_t timer)
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{ {
/* check whether timer thread is ready */ /* check whether timer thread is ready */
if (timer_thread.stat != RT_THREAD_READY) if ((timer_thread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
{ {
/* resume timer thread to check soft timer */ /* resume timer thread to check soft timer */
rt_thread_resume(&timer_thread); rt_thread_resume(&timer_thread);