summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernardXiong <[email protected]>2018-03-01 13:36:22 +0800
committerBernardXiong <[email protected]>2018-03-01 13:36:22 +0800
commit38b9ed3118f7df9fd683b9d3bd4425ab604ee2bc (patch)
tree2b7acaf70ec61499d4266d74a8c0551a85260111
parentef668bc3aa99992208ba6808fe430e5d00849b2f (diff)
[Kernel] add sigwait implementation
-rw-r--r--components/libc/signal/posix_signal.c85
-rw-r--r--components/libc/signal/posix_signal.h51
-rw-r--r--include/libc/libc_signal.h38
-rw-r--r--include/rtdef.h4
-rw-r--r--include/rtthread.h1
-rw-r--r--src/scheduler.c4
-rw-r--r--src/signal.c176
-rw-r--r--src/thread.c4
-rw-r--r--src/timer.c2
9 files changed, 227 insertions, 138 deletions
diff --git a/components/libc/signal/posix_signal.c b/components/libc/signal/posix_signal.c
index 1bf61aad70..b950fc956c 100644
--- a/components/libc/signal/posix_signal.c
+++ b/components/libc/signal/posix_signal.c
@@ -31,37 +31,37 @@
void (*signal(int sig, void (*func)(int))) (int)
{
- return rt_signal_install(sig, func);
+ return rt_signal_install(sig, func);
}
int sigprocmask (int how, const sigset_t *set, sigset_t *oset)
{
- rt_base_t level;
+ rt_base_t level;
rt_thread_t tid;
tid = rt_thread_self();
- level = rt_hw_interrupt_disable();
- if (oset) *oset = tid->sig_mask;
+ 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);
+ 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;
}
@@ -70,18 +70,18 @@ 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 (!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 (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;
+ if (oldact)
+ oldact->sa_handler = old;
return 0;
}
@@ -89,7 +89,22 @@ int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
int sigtimedwait(const sigset_t *set, siginfo_t *info,
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)
@@ -104,12 +119,12 @@ int sigwait(const sigset_t *set, int *sig)
int sigwaitinfo(const sigset_t *set, siginfo_t *info)
{
- return sigtimedwait(set, info, NULL);
+ return sigtimedwait(set, info, NULL);
}
int raise(int sig)
{
- rt_thread_kill(rt_thread_self(), sig);
+ rt_thread_kill(rt_thread_self(), sig);
return 0;
}
diff --git a/components/libc/signal/posix_signal.h b/components/libc/signal/posix_signal.h
index fbb33e7821..5ec721c921 100644
--- a/components/libc/signal/posix_signal.h
+++ b/components/libc/signal/posix_signal.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
#include <rtthread.h>
+#include <sys/signal.h>
enum rt_signal_value{
SIG1 = SIGHUP,
@@ -68,56 +69,6 @@ enum rt_signal_value{
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
}
#endif
diff --git a/include/libc/libc_signal.h b/include/libc/libc_signal.h
index cc4552f990..dabcad1a34 100644
--- a/include/libc/libc_signal.h
+++ b/include/libc/libc_signal.h
@@ -30,6 +30,7 @@
extern "C" {
#endif
+#ifndef HAVE_SYS_SIGNALS
/* Signal Generation and Delivery, P1003.1b-1993, p. 63
NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and
sigev_notify_attributes to the sigevent structure. */
@@ -59,14 +60,15 @@ struct siginfo
union sigval si_value;
};
typedef struct siginfo siginfo_t;
+#endif
-#define SI_USER 0x01 /* Signal sent by kill(). */
-#define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */
-#define SI_TIMER 0x03 /* Signal generated by expiration of a
+#define SI_USER 0x01 /* Signal sent by kill(). */
+#define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */
+#define SI_TIMER 0x03 /* Signal generated by expiration of a
timer set by timer_settime(). */
-#define SI_ASYNCIO 0x04 /* Signal generated by completion of an
- asynchronous I/O request. */
-#define SI_MESGQ 0x05 /* Signal generated by arrival of a
+#define SI_ASYNCIO 0x04 /* Signal generated by completion of an
+ asynchronous I/O request. */
+#define SI_MESGQ 0x05 /* Signal generated by arrival of a
message on an empty message queue. */
#ifdef RT_USING_NEWLIB
@@ -107,17 +109,17 @@ typedef unsigned long sigset_t;
#define SIGRTMAX 31
#define NSIG 32
-#define SIG_SETMASK 0 /* set mask with sigprocmask() */
-#define SIG_BLOCK 1 /* set of signals to block */
-#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
+#define SIG_SETMASK 0 /* set mask with sigprocmask() */
+#define SIG_BLOCK 1 /* set of signals to block */
+#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
typedef void (*_sig_func_ptr)(int);
struct sigaction
{
- _sig_func_ptr sa_handler;
- sigset_t sa_mask;
- int sa_flags;
+ _sig_func_ptr sa_handler;
+ sigset_t sa_mask;
+ int sa_flags;
};
#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
@@ -163,17 +165,17 @@ typedef unsigned long sigset_t;
#define SIGRTMAX 31
#define NSIG 32
-#define SIG_SETMASK 0 /* set mask with sigprocmask() */
-#define SIG_BLOCK 1 /* set of signals to block */
-#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
+#define SIG_SETMASK 0 /* set mask with sigprocmask() */
+#define SIG_BLOCK 1 /* set of signals to block */
+#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
typedef void (*_sig_func_ptr)(int);
struct sigaction
{
- _sig_func_ptr sa_handler;
- sigset_t sa_mask;
- int sa_flags;
+ _sig_func_ptr sa_handler;
+ sigset_t sa_mask;
+ int sa_flags;
};
#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
diff --git a/include/rtdef.h b/include/rtdef.h
index f2da3ac7bc..2404f7a364 100644
--- a/include/rtdef.h
+++ b/include/rtdef.h
@@ -451,8 +451,10 @@ typedef struct rt_timer *rt_timer_t;
* @addtogroup Signal
*/
#ifdef RT_USING_SIGNALS
+#include <libc/libc_signal.h>
typedef unsigned long rt_sigset_t;
typedef void (*rt_sighandler_t)(int signo);
+typedef siginfo_t rt_siginfo_t;
#define RT_SIG_MAX 32
#endif
@@ -481,7 +483,7 @@ typedef void (*rt_sighandler_t)(int signo);
#define RT_THREAD_STAT_SIGNAL 0x10
#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
/**
diff --git a/include/rtthread.h b/include/rtthread.h
index 61cd82d97e..c92f7f012f 100644
--- a/include/rtthread.h
+++ b/include/rtthread.h
@@ -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_unmask(int signo);
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);
#endif
diff --git a/src/scheduler.c b/src/scheduler.c
index fa9348cd25..1be1816bc2 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -263,7 +263,7 @@ void rt_schedule(void)
rt_hw_interrupt_enable(level);
}
}
- else
+ else
{
/* enable interrupt */
rt_hw_interrupt_enable(level);
@@ -293,7 +293,7 @@ void rt_schedule_insert_thread(struct rt_thread *thread)
temp = rt_hw_interrupt_disable();
/* change stat */
- thread->stat = RT_THREAD_READY;
+ thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
/* insert thread to ready list */
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
diff --git a/src/signal.c b/src/signal.c
index 53d44bdcd4..68b3836a85 100644
--- a/src/signal.c
+++ b/src/signal.c
@@ -80,6 +80,16 @@ static void _signal_entry(void *parameter)
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)
{
rt_ubase_t level;
@@ -88,7 +98,7 @@ static void _signal_deliver(rt_thread_t tid)
if (!(tid->sig_pending & tid->sig_mask)) return;
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 */
rt_thread_resume(tid);
@@ -106,14 +116,17 @@ static void _signal_deliver(rt_thread_t tid)
{
/* add signal state */
tid->stat |= RT_THREAD_STAT_SIGNAL;
+
rt_hw_interrupt_enable(level);
/* do signal action in self thread context */
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;
+
/* point to the signal handle entry */
tid->sig_ret = tid->sp;
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)
{
rt_base_t level;
@@ -199,38 +311,45 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
struct siginfo_node *si_node;
level = rt_hw_interrupt_disable();
- while (tid->sig_pending & tid->sig_mask)
+ if (tid->sig_pending & tid->sig_mask)
{
- int signo, error;
- rt_sighandler_t handler;
+ /* if thread is not waiting for signal */
+ if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT))
+ {
+ while (tid->sig_pending & tid->sig_mask)
+ {
+ int signo, error;
+ rt_sighandler_t handler;
- si_node = (struct siginfo_node *)tid->si_list;
- if (!si_node) break;
+ si_node = (struct siginfo_node *)tid->si_list;
+ if (!si_node) break;
- /* remove this sig info node from list */
- if (si_node->list.next == RT_NULL)
- tid->si_list = RT_NULL;
- else
- tid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
+ /* remove this sig info node from list */
+ if (si_node->list.next == RT_NULL)
+ tid->si_list = RT_NULL;
+ else
+ tid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
- signo = si_node->si.si_signo;
- handler = tid->sig_vectors[signo];
- rt_hw_interrupt_enable(level);
+ signo = si_node->si.si_signo;
+ handler = tid->sig_vectors[signo];
+ rt_hw_interrupt_enable(level);
- dbg_log(DBG_LOG, "handle signal: %d, handler 0x%08x\n", signo, handler);
- if (handler) handler(signo);
+ dbg_log(DBG_LOG, "handle signal: %d, handler 0x%08x\n", signo, handler);
+ if (handler) handler(signo);
- level = rt_hw_interrupt_disable();
- tid->sig_pending &= ~sig_mask(signo);
- error = si_node->si.si_errno;
+ level = rt_hw_interrupt_disable();
+ tid->sig_pending &= ~sig_mask(signo);
+ error = si_node->si.si_errno;
- rt_mp_free(si_node); /* release this siginfo node */
- /* set errno in thread tcb */
- tid->error = error;
- }
+ rt_mp_free(si_node); /* release this siginfo node */
+ /* set errno in thread tcb */
+ tid->error = error;
+ }
- /* whether clean signal status */
- if (clean_state == RT_TRUE) tid->stat &= ~RT_THREAD_STAT_SIGNAL;
+ /* whether clean signal status */
+ if (clean_state == RT_TRUE) tid->stat &= ~RT_THREAD_STAT_SIGNAL;
+ }
+ }
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;
rt_hw_interrupt_enable(level);
- /* update sig infor */
+ /* update sig info */
rt_enter_critical();
for (; (node) != RT_NULL; node = node->next)
{
@@ -358,7 +477,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
}
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 */
@@ -380,4 +499,3 @@ int rt_system_signal_init(void)
}
#endif
-
diff --git a/src/thread.c b/src/thread.c
index 3a3e55302e..ea0ba0bfc9 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -638,7 +638,7 @@ rt_err_t rt_thread_suspend(rt_thread_t thread)
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));
return -RT_ERROR;
@@ -648,7 +648,7 @@ rt_err_t rt_thread_suspend(rt_thread_t thread)
temp = rt_hw_interrupt_disable();
/* change thread stat */
- thread->stat = RT_THREAD_SUSPEND;
+ thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
rt_schedule_remove_thread(thread);
/* stop thread timer anyway */
diff --git a/src/timer.c b/src/timer.c
index c56a453a3c..d6cf486931 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -396,7 +396,7 @@ rt_err_t rt_timer_start(rt_timer_t timer)
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
/* 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 */
rt_thread_resume(&timer_thread);