Module: xenomai-forge
Branch: master
Commit: 618228db04cc6842845d88602777b202a1a28a6d
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=618228db04cc6842845d88602777b202a1a28a6d

Author: Philippe Gerum <r...@xenomai.org>
Date:   Tue Sep 10 17:31:17 2013 +0200

cobalt/posix/sem: fix timeout handling in sem_timedwait()

Do not check validity of the timeout argument if the semaphore can be
locked immediately.

---

 kernel/cobalt/posix/sem.c |   78 ++++++++++++++++++++++++---------------------
 1 files changed, 42 insertions(+), 36 deletions(-)

diff --git a/kernel/cobalt/posix/sem.c b/kernel/cobalt/posix/sem.c
index f3a5d1c..076f2d2 100644
--- a/kernel/cobalt/posix/sem.c
+++ b/kernel/cobalt/posix/sem.c
@@ -540,32 +540,58 @@ static int sem_trywait(struct cobalt_sem *sem)
 }
 
 static inline int
-sem_timedwait_internal(struct cobalt_sem *sem, int timed, xnticks_t to)
+sem_timedwait_internal(struct cobalt_sem *sem, int timed,
+                      const struct timespec __user *u_ts)
 {
+       struct timespec ts;
        xntmode_t tmode;
        int ret, info;
+       spl_t s;
+
+       xnlock_get_irqsave(&nklock, s);
 
        ret = sem_trywait_internal(sem);
-       if (ret != -EAGAIN)
+       if (ret != -EAGAIN) {
+               xnlock_put_irqrestore(&nklock, s);
                return ret;
-
-       sem->nwaiters++;
+       }
 
        if (timed) {
+               xnlock_put_irqrestore(&nklock, s);
+
+               if (u_ts == NULL ||
+                   __xn_safe_copy_from_user(&ts, u_ts, sizeof(ts)))
+                       return -EFAULT;
+
+               if (ts.tv_nsec >= ONE_BILLION)
+                       return -EINVAL;
+
+               xnlock_get_irqsave(&nklock, s);
+
+               if (sem->value > 0) {
+                       ret = 0;
+                       --sem->value;
+                       goto out;
+               }
+               sem->nwaiters++;
                tmode = sem->flags & SEM_RAWCLOCK ? XN_ABSOLUTE : XN_REALTIME;
-               info = xnsynch_sleep_on(&sem->synchbase, to, tmode);
-       } else
+               info = xnsynch_sleep_on(&sem->synchbase, ts2ns(&ts) + 1, tmode);
+       } else {
+               sem->nwaiters++;
                info = xnsynch_sleep_on(&sem->synchbase, XN_INFINITE, 
XN_RELATIVE);
+       }
 
+       ret = 0;
        if (info & XNRMID)
-               return -EINVAL;
-
-       if (info & (XNBREAK|XNTIMEO)) {
+               ret = -EINVAL;
+       else if (info & (XNBREAK|XNTIMEO)) {
                sem->nwaiters--;
-               return (info & XNBREAK) ? -EINTR : -ETIMEDOUT;
+               ret = (info & XNBREAK) ? -EINTR : -ETIMEDOUT;
        }
+out:
+       xnlock_put_irqrestore(&nklock, s);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -603,14 +629,7 @@ sem_timedwait_internal(struct cobalt_sem *sem, int timed, 
xnticks_t to)
  */
 static int sem_wait(struct cobalt_sem *sem)
 {
-       spl_t s;
-       int err;
-
-       xnlock_get_irqsave(&nklock, s);
-       err = sem_timedwait_internal(sem, 0, XN_INFINITE);
-       xnlock_put_irqrestore(&nklock, s);
-
-       return err;
+       return sem_timedwait_internal(sem, 0, NULL);
 }
 
 /**
@@ -647,19 +666,10 @@ static int sem_wait(struct cobalt_sem *sem)
  * Specification.</a>
  *
  */
-static int sem_timedwait(struct cobalt_sem *sem, const struct timespec 
*abs_timeout)
+static int sem_timedwait(struct cobalt_sem *sem,
+                        const struct timespec __user *abs_timeout)
 {
-       spl_t s;
-       int err;
-
-       if (abs_timeout->tv_nsec > ONE_BILLION)
-               return -EINVAL;
-
-       xnlock_get_irqsave(&nklock, s);
-       err = sem_timedwait_internal(sem, 1, ts2ns(abs_timeout) + 1);
-       xnlock_put_irqrestore(&nklock, s);
-
-       return err;
+       return sem_timedwait_internal(sem, 1, abs_timeout);
 }
 
 int sem_post_inner(struct cobalt_sem *sem, struct cobalt_kqueues *ownq, int 
bcast)
@@ -818,15 +828,11 @@ int cobalt_sem_wait(struct __shadow_sem __user *u_sem)
 int cobalt_sem_timedwait(struct __shadow_sem __user *u_sem,
                         struct timespec __user *u_ts)
 {
-       struct timespec ts;
        struct cobalt_sem *sm;
 
        __xn_get_user(sm, &u_sem->sem);
 
-       if (__xn_safe_copy_from_user(&ts, u_ts, sizeof(ts)))
-               return -EFAULT;
-
-       return sem_timedwait(sm, &ts);
+       return sem_timedwait(sm, u_ts);
 }
 
 int cobalt_sem_trywait(struct __shadow_sem __user *u_sem)


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to