New rules:
        ->_base &  1    : is timer pending
        ->_base & ~1    : timer's base

If ->_base == NULL, this timer is not running on any cpu.
Cleared only in del_timer_sync().

Note that now we don't need del_singleshot_timer_sync().

Here is the code of del_timer_sync:

int del_timer_sync(struct timer_list *timer)
{
        int ret = 0;

        for (;;) {
                unsigned long flags;
                tvec_base_t *_base, *base;

                _base = timer->_base;
                if (!_base)
                        return ret;

                base = __timer_base(_base);
                spin_lock_irqsave(&base->lock, flags);

                if (timer->_base != _base)
                        goto unlock;

                if (base->running_timer == timer)
                        goto unlock;

                if (__timer_pending(_base)) {
                        list_del(&timer->entry);
                        ret = 1;
                }
                smp_wmb();
                timer->_base = NULL;
unlock:
                spin_unlock_irqrestore(&base->lock, flags);
        }
}

Signed-off-by: Oleg Nesterov <[EMAIL PROTECTED]>

--- 2.6.11/include/linux/timer.h~2_PEND 2005-03-15 17:49:19.000000000 +0300
+++ 2.6.11/include/linux/timer.h        2005-03-15 18:09:06.000000000 +0300
@@ -21,9 +21,11 @@ struct timer_list {
        struct tvec_t_base_s *_base;
 };
 
+#define        __TIMER_PENDING 1
+
 static inline int __timer_pending(struct tvec_t_base_s *base)
 {
-       return base != NULL;
+       return ((unsigned long)base & __TIMER_PENDING) != 0;
 }
 
 #define TIMER_MAGIC    0x4b87ad6e
--- 2.6.11/kernel/timer.c~2_PEND        2005-03-15 17:55:00.000000000 +0300
+++ 2.6.11/kernel/timer.c       2005-03-15 19:52:48.000000000 +0300
@@ -86,16 +86,26 @@ static inline void set_running_timer(tve
 
 static inline tvec_base_t *__get_base(struct timer_list *timer)
 {
-       return timer->_base;
+       tvec_base_t *base = timer->_base;
+
+       if (__timer_pending(base))
+               return (void*)base - __TIMER_PENDING;
+       else
+               return NULL;
 }
 
 static inline void __set_base(struct timer_list *timer,
                                tvec_base_t *base, int pending)
 {
        if (pending)
-               timer->_base = base;
+               timer->_base = (void*)base + __TIMER_PENDING;
        else
-               timer->_base = NULL;
+               timer->_base = base;
+}
+
+static inline tvec_base_t *__timer_base(tvec_base_t *base)
+{
+       return (tvec_base_t*)((unsigned long)base & ~__TIMER_PENDING);
 }
 
 /* Fake initialization */
@@ -356,29 +366,39 @@ EXPORT_SYMBOL(del_timer);
  */
 int del_timer_sync(struct timer_list *timer)
 {
-       tvec_base_t *base;
-       int i, ret = 0;
+       int ret;
 
        check_timer(timer);
 
-del_again:
-       ret += del_timer(timer);
+       ret = 0;
+       for (;;) {
+               unsigned long flags;
+               tvec_base_t *_base, *base;
+
+               _base = timer->_base;
+               if (!_base)
+                       return ret;
 
-       for_each_online_cpu(i) {
-               base = &per_cpu(tvec_bases, i);
-               if (base->running_timer == timer) {
-                       while (base->running_timer == timer) {
-                               cpu_relax();
-                               preempt_check_resched();
-                       }
-                       break;
+               base = __timer_base(_base);
+               spin_lock_irqsave(&base->lock, flags);
+
+               if (timer->_base != _base)
+                       goto unlock;
+
+               if (base->running_timer == timer)
+                       goto unlock;
+
+               if (__timer_pending(_base)) {
+                       list_del(&timer->entry);
+                       ret = 1;
                }
+               /* Need to make sure that anybody who sees a NULL base
+                * also sees the list ops */
+               smp_wmb();
+               timer->_base = NULL;
+unlock:
+               spin_unlock_irqrestore(&base->lock, flags);
        }
-       smp_rmb();
-       if (timer_pending(timer))
-               goto del_again;
-
-       return ret;
 }
 EXPORT_SYMBOL(del_timer_sync);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to