Selaa lähdekoodia

Merge pull request #1241 from BernardXiong/feature_signal

[Kernel] add sigwait implementation
Bernard Xiong 7 vuotta sitten
vanhempi
commit
44def114fb

+ 51 - 36
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;
-
-	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);
+    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);
 
     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;
 }
 

+ 1 - 50
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

+ 20 - 18
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)

+ 3 - 1
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
 
 /**

+ 1 - 0
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

+ 2 - 2
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]),

+ 147 - 29
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
-

+ 2 - 2
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 */

+ 1 - 1
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);