Commit 81dcbaab authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] posix_timers fixes

From: George Anzinger <george@mvista.com>

- Removes C++ comment in favor of C style.

- Removes the special treatment for MIPS SIGEV values.  We only require
  (and error if this fails) that the SIGEV_THREAD_ID value not share bits
  with the other SIGEV values.  Note that mips has yet to define this value
  so when they do...

- Corrects the check for the signal range to be from 1 to SIGRTMAX
  inclusive.

- Adds a check to verify that kmem_cache_alloc() actually returned a timer,
  error if not.

- Fixes a bug in timer_gettime() where the incorrect value was returned if
  a signal was pending on the timer OR the timer was a SIGEV_NONE timer.
parent bd5e36f5
...@@ -2,8 +2,26 @@ ...@@ -2,8 +2,26 @@
* linux/kernel/posix_timers.c * linux/kernel/posix_timers.c
* *
* *
* 2002-10-15 Posix Clocks & timers by George Anzinger * 2002-10-15 Posix Clocks & timers
* Copyright (C) 2002 by MontaVista Software. * by George Anzinger george@mvista.com
*
* Copyright (C) 2002 2003 by MontaVista Software.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* MontaVista Software | 1237 East Arques Avenue | Sunnyvale | CA 94085 | USA
*/ */
/* These are all the functions necessary to implement /* These are all the functions necessary to implement
...@@ -33,7 +51,7 @@ ...@@ -33,7 +51,7 @@
result; }) result; })
#endif #endif
#define CLOCK_REALTIME_RES TICK_NSEC // In nano seconds. #define CLOCK_REALTIME_RES TICK_NSEC /* In nano seconds. */
static inline u64 mpy_l_X_l_ll(unsigned long mpy1,unsigned long mpy2) static inline u64 mpy_l_X_l_ll(unsigned long mpy1,unsigned long mpy2)
{ {
...@@ -82,17 +100,15 @@ static spinlock_t idr_lock = SPIN_LOCK_UNLOCKED; ...@@ -82,17 +100,15 @@ static spinlock_t idr_lock = SPIN_LOCK_UNLOCKED;
# define timer_active(tmr) BARFY // error to use outside of SMP # define timer_active(tmr) BARFY // error to use outside of SMP
# define set_timer_inactive(tmr) do { } while (0) # define set_timer_inactive(tmr) do { } while (0)
#endif #endif
/* /*
* For some reason mips/mips64 define the SIGEV constants plus 128. * we assume that the new SIGEV_THREAD_ID shares no bits with the other
* Here we define a mask to get rid of the common bits. The * SIGEV values. Here we put out an error if this assumption fails.
* optimizer should make this costless to all but mips.
* Note that no common bits (the non-mips case) will give 0xffffffff.
*/ */
#define MIPS_SIGEV ~(SIGEV_NONE & \ #if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \
SIGEV_SIGNAL & \ ~(SIGEV_SIGNAL | SIGEV_NONE | SIGEV_THREAD))
SIGEV_THREAD & \ #error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"
SIGEV_THREAD_ID) #endif
#define REQUEUE_PENDING 1 #define REQUEUE_PENDING 1
/* /*
...@@ -301,7 +317,7 @@ static void timer_notify_task(struct k_itimer *timr) ...@@ -301,7 +317,7 @@ static void timer_notify_task(struct k_itimer *timr)
if (timr->it_incr) if (timr->it_incr)
timr->sigq->info.si_sys_private = ++timr->it_requeue_pending; timr->sigq->info.si_sys_private = ++timr->it_requeue_pending;
if (timr->it_sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV) if (timr->it_sigev_notify & SIGEV_THREAD_ID )
ret = send_sigqueue(timr->it_sigev_signo, timr->sigq, ret = send_sigqueue(timr->it_sigev_signo, timr->sigq,
timr->it_process); timr->it_process);
else else
...@@ -338,14 +354,14 @@ static inline struct task_struct * good_sigevent(sigevent_t * event) ...@@ -338,14 +354,14 @@ static inline struct task_struct * good_sigevent(sigevent_t * event)
{ {
struct task_struct *rtn = current; struct task_struct *rtn = current;
if ((event->sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV) && if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
(!(rtn = find_task_by_pid(event->sigev_notify_thread_id)) || (!(rtn = find_task_by_pid(event->sigev_notify_thread_id)) ||
rtn->tgid != current->tgid)) rtn->tgid != current->tgid ||
(event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
return NULL; return NULL;
if ((event->sigev_notify & ~SIGEV_NONE & MIPS_SIGEV) && if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
event->sigev_signo && ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
((unsigned) (event->sigev_signo > SIGRTMAX)))
return NULL; return NULL;
return rtn; return rtn;
...@@ -365,6 +381,8 @@ static struct k_itimer * alloc_posix_timer(void) ...@@ -365,6 +381,8 @@ static struct k_itimer * alloc_posix_timer(void)
{ {
struct k_itimer *tmr; struct k_itimer *tmr;
tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL); tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL);
if (!tmr)
return tmr;
memset(tmr, 0, sizeof (struct k_itimer)); memset(tmr, 0, sizeof (struct k_itimer));
tmr->it_id = (timer_t)-1; tmr->it_id = (timer_t)-1;
if (unlikely(!(tmr->sigq = sigqueue_alloc()))) { if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
...@@ -586,14 +604,18 @@ do_timer_gettime(struct k_itimer *timr, struct itimerspec *cur_setting) ...@@ -586,14 +604,18 @@ do_timer_gettime(struct k_itimer *timr, struct itimerspec *cur_setting)
posix_get_now(&now); posix_get_now(&now);
if (expires && (timr->it_sigev_notify & SIGEV_NONE) && !timr->it_incr && if (expires &&
((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) &&
!timr->it_incr &&
posix_time_before(&timr->it_timer, &now)) posix_time_before(&timr->it_timer, &now))
timr->it_timer.expires = expires = 0; timr->it_timer.expires = expires = 0;
if (expires) { if (expires) {
if (timr->it_requeue_pending & REQUEUE_PENDING || if (timr->it_requeue_pending & REQUEUE_PENDING ||
(timr->it_sigev_notify & SIGEV_NONE)) (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
while (posix_time_before(&timr->it_timer, &now)) while (posix_time_before(&timr->it_timer, &now))
posix_bump_timer(timr); posix_bump_timer(timr);
expires = timr->it_timer.expires;
}
else else
if (!timer_pending(&timr->it_timer)) if (!timer_pending(&timr->it_timer))
expires = 0; expires = 0;
...@@ -804,7 +826,7 @@ do_timer_settime(struct k_itimer *timr, int flags, ...@@ -804,7 +826,7 @@ do_timer_settime(struct k_itimer *timr, int flags,
* equal to jiffies, so the timer notify function is called directly. * equal to jiffies, so the timer notify function is called directly.
* We do not even queue SIGEV_NONE timers! * We do not even queue SIGEV_NONE timers!
*/ */
if (!(timr->it_sigev_notify & SIGEV_NONE)) { if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)) {
if (timr->it_timer.expires == jiffies) if (timr->it_timer.expires == jiffies)
timer_notify_task(timr); timer_notify_task(timr);
else else
...@@ -967,9 +989,6 @@ static int do_posix_gettime(struct k_clock *clock, struct timespec *tp) ...@@ -967,9 +989,6 @@ static int do_posix_gettime(struct k_clock *clock, struct timespec *tp)
* if we are interrupted since we don't take lock that will stall us or * if we are interrupted since we don't take lock that will stall us or
* any other cpu. Voila, no irq lock is needed. * any other cpu. Voila, no irq lock is needed.
* *
* Note also that the while loop assures that the sub_jiff_offset
* will be less than a jiffie, thus no need to normalize the result.
* Well, not really, if called with ints off :(
*/ */
static u64 do_posix_clock_monotonic_gettime_parts( static u64 do_posix_clock_monotonic_gettime_parts(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment