The Linux Foundation

 
LsbRuntimeTest3

From The Linux Foundation

Contents

LSB 3: Runtime Test Results and Analysis

Linux Kernel 2.6.12

This issue is not fully analyzed, but it appears the 2.6.12 kernel fails two new tests, for the preservation of alarms and interval timers across exec. Since there are six exec forms that each test the same sequence, we get twelve fails:

/tset/LSB.os/procprim/exec_L/T.execl_L 7 FAIL
/tset/LSB.os/procprim/exec_L/T.execle_L 7 FAIL
/tset/LSB.os/procprim/exec_L/T.execlp_L 7 FAIL
/tset/LSB.os/procprim/exec_L/T.execv_L 7 FAIL
/tset/LSB.os/procprim/exec_L/T.execve_L 7 FAIL
/tset/LSB.os/procprim/exec_L/T.execvp_L 7 FAIL
/tset/POSIX.os/procprim/exec/T.execl 30 FAIL
/tset/POSIX.os/procprim/exec/T.execle 30 FAIL
/tset/POSIX.os/procprim/exec/T.execlp 30 FAIL
/tset/POSIX.os/procprim/exec/T.execv 30 FAIL
/tset/POSIX.os/procprim/exec/T.execve 30 FAIL
/tset/POSIX.os/procprim/exec/T.execvp 30 FAIL

The journal snips for one of each of these issues are:

10|903 /tset/LSB.os/procprim/exec_L/T.execl_L 11:52:05|TC Start, scenario ref 909-0
...
200|903 7 11:52:16|TP Start
520|903 7 00016088 2 1|For ITIMER_REAL: it_value.tv_sec reset incorrectly by exec:
520|903 7 00016088 2 2|expected value 0; observed value 0
220|903 7 1 11:52:16|FAIL

Note the "expected value 0" is a lie, and the subject of bug 1053, but that's only for the diagnostic output, not for the test itself.

10|512 /tset/POSIX.os/procprim/exec/T.execl 10:03:35|TC Start, scenario ref 515-0
...
200|512 30 10:03:47|TP Start
520|512 30 00011620 5 1|Following execl(...), time to alarm was cleared
520|512 30 00011620 5 2|Following execl(...), alarm not set correctly
520|512 30 00011620 5 3|Expected value 250; Observed value 0
220|512 30 1 10:03:47|FAIL


New info on 2.6.12 issue

The following appears to be the simplest fix: http://lkml.org/lkml/2005/8/4/281

Followup on 2.6.12 kernel issue

18 Aug 2005 - Stew Benedict

Mats mentioned that upstream has fixed this, I downloaded and built 2.6.13rc6 and it indeed passes the 12 T.exec* tests. I came up with the following patch against our 2.6.12-9mdk kernel, which also passes now:

19 Aug 2005 - Stew Benedict I didn't test the SMP build, updated patch covers this now too. If someone has something less intrusuive, please post it.

--- linux-2.6.12-9mdk/include/linux/timer.h.LSB	2005-08-17 20:31:56.000000000 -0400
+++ linux-2.6.12-9mdk/include/linux/timer.h	2005-08-19 07:46:57.000000000 -0400
@@ -6,45 +6,33 @@
: #include <linux/spinlock.h>
: #include <linux/stddef.h>
: 
-struct tvec_t_base_s;
+struct timer_base_s;
: 
: struct timer_list {
: 	struct list_head entry;
: 	unsigned long expires;
: 
-	spinlock_t lock;
: 	unsigned long magic;
: 
: 	void (*function)(unsigned long);
: 	unsigned long data;
: 
-	struct tvec_t_base_s *base;
+	struct timer_base_s *base;
: };
: 
: #define TIMER_MAGIC	0x4b87ad6e
: 
+extern struct timer_base_s __init_timer_base;
+
: #define TIMER_INITIALIZER(_function, _expires, _data) {		\
: 		.function = (_function),			\
: 		.expires = (_expires),				\
: 		.data = (_data),				\
-		.base = NULL,					\
+		.base = &__init_timer_base,			\
: 		.magic = TIMER_MAGIC,				\
-		.lock = SPIN_LOCK_UNLOCKED,			\
: 	}
: 
-/***
- * init_timer - initialize a timer.
- * @timer: the timer to be initialized
- *
- * init_timer() must be done to a timer prior calling *any* of the
- * other timer functions.
- */
-static inline void init_timer(struct timer_list * timer)
-{
-	timer->base = NULL;
-	timer->magic = TIMER_MAGIC;
-	spin_lock_init(&timer->lock);
-}
+void fastcall init_timer(struct timer_list * timer);
: 
: /***
* timer_pending - is a timer pending?
@@ -58,7 +46,7 @@
*/
: static inline int timer_pending(const struct timer_list * timer)
: {
-	return timer->base != NULL;
+	return timer->entry.next != NULL;
: }
: 
: extern void add_timer_on(struct timer_list *timer, int cpu);
@@ -88,13 +76,15 @@
: }
: 
: #ifdef CONFIG_SMP
+  extern int try_to_del_timer_sync(struct timer_list *timer);
: extern int del_timer_sync(struct timer_list *timer);
-  extern int del_singleshot_timer_sync(struct timer_list *timer);
: #else
-# define del_timer_sync(t) del_timer(t)
-# define del_singleshot_timer_sync(t) del_timer(t)
+# define try_to_del_timer_sync(t)      del_timer(t)
+# define del_timer_sync(t)             del_timer(t)
: #endif
: 
+#define del_singleshot_timer_sync(t) del_timer_sync(t)
+
: extern void init_timers(void);
: extern void run_local_timers(void);
: extern void it_real_fn(unsigned long);
--- linux-2.6.12-9mdk/kernel/exit.c.LSB	2005-08-17 19:35:59.000000000 -0400
+++ linux-2.6.12-9mdk/kernel/exit.c	2005-08-17 19:37:27.000000000 -0400
@@ -825,8 +825,10 @@
: 	acct_update_integrals(tsk);
: 	update_mem_hiwater(tsk);
: 	group_dead = atomic_dec_and_test(&tsk->signal->live);
-	if (group_dead)
+	if (group_dead) {
+		del_timer_sync(&tsk->signal->real_timer);
: 		acct_process(code);
+	}
: 	exit_mm(tsk);
: 
: 	exit_sem(tsk);
--- linux-2.6.12-9mdk/kernel/itimer.c.LSB	2005-08-17 19:37:34.000000000 -0400
+++ linux-2.6.12-9mdk/kernel/itimer.c	2005-08-17 20:01:19.000000000 -0400
@@ -112,55 +112,54 @@
: 	return error;
: }
: 
-/*
- * Called with P->sighand->siglock held and P->signal->real_timer inactive.
- * If interval is nonzero, arm the timer for interval ticks from now.
- */
-static inline void it_real_arm(struct task_struct *p, unsigned long interval)
-{
-	p->signal->it_real_value = interval; /* XXX unnecessary field?? */
-	if (interval == 0)
-		return;
-	if (interval > (unsigned long) LONG_MAX)
-		interval = LONG_MAX;
-	/* the "+ 1" below makes sure that the timer doesn't go off before
-	 * the interval requested. This could happen if
-	 * time requested % (usecs per jiffy) is more than the usecs left
-	 * in the current jiffy */
-	p->signal->real_timer.expires = jiffies + interval + 1;
-	add_timer(&p->signal->real_timer);
-}
: 
: void it_real_fn(unsigned long __data)
: {
: 	struct task_struct * p = (struct task_struct *) __data;
-
+	unsigned long inc = p->signal->it_real_incr;
+	
: 	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
: 
: 	/*
* Now restart the timer if necessary.  We don't need any locking
* here because do_setitimer makes sure we have finished running
* before it touches anything.
-	 */
-	it_real_arm(p, p->signal->it_real_incr);
+	 * Note, we KNOW we are (or should be) at a jiffie edge here so
+	 * we don't need the +1 stuff.  Also, we want to use the prior
+	 * expire value so as to not "slip" a jiffie if we are late.
+	 * Deal with requesting a time prior to "now" here rather than
+	 * in add_timer.
+        */
+	if (!inc)
+		return;
+	while (time_before_eq(p->signal->real_timer.expires, jiffies))
+		p->signal->real_timer.expires += inc;
+	add_timer(&p->signal->real_timer);
: }
: 
: int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
: {
: 	struct task_struct *tsk = current;
- 	unsigned long val, interval;
+ 	unsigned long val, interval, expires;
: 	cputime_t cval, cinterval, nval, ninterval;
: 
: 	switch (which) {
: 	case ITIMER_REAL:
+again:
: 		spin_lock_irq(&tsk->sighand->siglock);
: 		interval = tsk->signal->it_real_incr;
: 		val = it_real_value(tsk->signal);
-		if (val)
-			del_timer_sync(&tsk->signal->real_timer);
+		/* We are sharing ->siglock with it_real_fn() */
+		if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
+			spin_unlock_irq(&tsk->sighand->siglock);
+			goto again;
+		}
: 		tsk->signal->it_real_incr =
: 			timeval_to_jiffies(&value->it_interval);
-		it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
+		expires = timeval_to_jiffies(&value->it_value);
+		if (expires)
+			mod_timer(&tsk->signal->real_timer,
+				  jiffies + 1 + expires);
: 		spin_unlock_irq(&tsk->sighand->siglock);
: 		if (ovalue) {
: 			jiffies_to_timeval(val, &ovalue->it_value);
--- linux-2.6.12-9mdk/kernel/posix-timers.c.LSB	2005-08-17 19:42:57.000000000 -0400
+++ linux-2.6.12-9mdk/kernel/posix-timers.c	2005-08-17 19:49:48.000000000 -0400
@@ -89,23 +89,6 @@
: static DEFINE_SPINLOCK(idr_lock);
: 
: /*
- * Just because the timer is not in the timer list does NOT mean it is
- * inactive.  It could be in the "fire" routine getting a new expire time.
- */
-#define TIMER_INACTIVE 1
-
-#ifdef CONFIG_SMP
-# define timer_active(tmr) \
-		((tmr)->it.real.timer.entry.prev != (void *)TIMER_INACTIVE)
-# define set_timer_inactive(tmr) \
-		do { \
-			(tmr)->it.real.timer.entry.prev = (void *)TIMER_INACTIVE; \
-		} while (0)
-#else
-# define timer_active(tmr) BARFY	// error to use outside of SMP
-# define set_timer_inactive(tmr) do { } while (0)
-#endif
-/*
* we assume that the new SIGEV_THREAD_ID shares no bits with the other
* SIGEV values.  Here we put out an error if this assumption fails.
*/
@@ -226,7 +209,6 @@
: 	init_timer(&new_timer->it.real.timer);
: 	new_timer->it.real.timer.data = (unsigned long) new_timer;
: 	new_timer->it.real.timer.function = posix_timer_fn;
-	set_timer_inactive(new_timer);
: 	return 0;
: }
: 
@@ -480,7 +462,6 @@
: 	int do_notify = 1;
: 
: 	spin_lock_irqsave(&timr->it_lock, flags);
- 	set_timer_inactive(timr);
: 	if (!list_empty(&timr->it.real.abs_timer_entry)) {
: 		spin_lock(&abs_list.lock);
: 		do {
@@ -915,21 +896,10 @@
: 			jiffies_64_f = get_jiffies_64();
: 		}
: 		/*
-		 * Take away now to get delta
-		 */
-		oc.tv_sec -= now.tv_sec;
-		oc.tv_nsec -= now.tv_nsec;
-		/*
-		 * Normalize...
+		 * Take away now to get delta and normalize
*/
-		while ((oc.tv_nsec - NSEC_PER_SEC) >= 0) {
-			oc.tv_nsec -= NSEC_PER_SEC;
-			oc.tv_sec++;
-		}
-		while ((oc.tv_nsec) < 0) {
-			oc.tv_nsec += NSEC_PER_SEC;
-			oc.tv_sec--;
-		}
+		 set_normalized_timespec(&oc, oc.tv_sec - now.tv_sec,
+				         oc.tv_nsec - now.tv_nsec);
: 	}else{
: 		jiffies_64_f = get_jiffies_64();
: 	}
@@ -983,8 +953,8 @@
* careful here.  If smp we could be in the "fire" routine which will
* be spinning as we hold the lock.  But this is ONLY an SMP issue.
*/
+	if (try_to_del_timer_sync(&timr->it.real.timer) < 0) {
: #ifdef CONFIG_SMP
-	if (timer_active(timr) && !del_timer(&timr->it.real.timer))
: 		/*
* It can only be active if on an other cpu.  Since
* we have cleared the interval stuff above, it should
@@ -994,11 +964,9 @@
* a "retry" exit status.
*/
: 		return TIMER_RETRY;
-
-	set_timer_inactive(timr);
-#else
-	del_timer(&timr->it.real.timer);
: #endif
+	}
+
: 	remove_from_abslist(timr);
: 
: 	timr->it_requeue_pending = (timr->it_requeue_pending + 2) & 
@@ -1083,8 +1051,9 @@
: static inline int common_timer_del(struct k_itimer *timer)
: {
: 	timer->it.real.incr = 0;
+
+	if (try_to_del_timer_sync(&timer->it.real.timer) < 0) {
: #ifdef CONFIG_SMP
-	if (timer_active(timer) && !del_timer(&timer->it.real.timer))
: 		/*
* It can only be active if on an other cpu.  Since
* we have cleared the interval stuff above, it should
@@ -1094,9 +1063,9 @@
* a "retry" exit status.
*/
: 		return TIMER_RETRY;
-#else
-	del_timer(&timer->it.real.timer);
: #endif
+	}
+
: 	remove_from_abslist(timer);
: 
: 	return 0;
@@ -1197,7 +1166,6 @@
: 		tmr = list_entry(sig->posix_timers.next, struct k_itimer, list);
: 		itimer_delete(tmr);
: 	}
-	del_timer_sync(&sig->real_timer);
: }
: 
: /*
--- linux-2.6.12-9mdk/kernel/timer.c.LSB	2005-08-17 19:55:14.000000000 -0400
+++ linux-2.6.12-9mdk/kernel/timer.c	2005-08-19 09:46:51.000000000 -0400
@@ -62,6 +62,11 @@
: #define TVN_MASK (TVN_SIZE - 1)
: #define TVR_MASK (TVR_SIZE - 1)
: 
+struct timer_base_s {
+	spinlock_t lock;
+	struct timer_list *running_timer;
+};
+
: typedef struct tvec_s {
: 	struct list_head vec[TVN_SIZE];
: } tvec_t;
@@ -71,9 +76,8 @@
: } tvec_root_t;
: 
: struct tvec_t_base_s {
-	spinlock_t lock;
+	struct timer_base_s t_base;
: 	unsigned long timer_jiffies;
-	struct timer_list *running_timer;
: 	tvec_root_t tv1;
: 	tvec_t tv2;
: 	tvec_t tv3;
@@ -82,19 +86,16 @@
: } ____cacheline_aligned_in_smp;
: 
: typedef struct tvec_t_base_s tvec_base_t;
+static DEFINE_PER_CPU(tvec_base_t, tvec_bases);
: 
: static inline void set_running_timer(tvec_base_t *base,
: 					struct timer_list *timer)
: {
: #ifdef CONFIG_SMP
-	base->running_timer = timer;
+	base->t_base.running_timer = timer;
: #endif
: }
: 
-/* Fake initialization */
-static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED };
-static DEFINE_PER_CPU(int, timer_inited) = 0; 
-
: static void check_timer_failed(struct timer_list *timer)
: {
: 	static int whine_count;
@@ -109,7 +110,6 @@
: 	/*
* Now fix it up
*/
-	spin_lock_init(&timer->lock);
: 	timer->magic = TIMER_MAGIC;
: }
: 
@@ -162,66 +162,114 @@
: 	list_add_tail(&timer->entry, vec);
: }
: 
+typedef struct timer_base_s timer_base_t;
+/*
+ * Used by TIMER_INITIALIZER, we can't use per_cpu(tvec_bases)
+ * at compile time, and we need timer->base to lock the timer.
+ */
+timer_base_t __init_timer_base
+        ____cacheline_aligned_in_smp = { .lock = SPIN_LOCK_UNLOCKED };
+EXPORT_SYMBOL(__init_timer_base);
+
+/***
+ * init_timer - initialize a timer.
+ * @timer: the timer to be initialized
+ *
+ * init_timer() must be done to a timer prior calling *any* of the
+ * other timer functions.
+ */
+void fastcall init_timer(struct timer_list *timer)
+{
+        timer->entry.next = NULL;
+        timer->base = &per_cpu(tvec_bases, smp_processor_id()).t_base;
+        timer->magic = TIMER_MAGIC;
+}
+EXPORT_SYMBOL(init_timer);
+
+static inline void detach_timer(struct timer_list *timer,
+                                        int clear_pending)
+{
+        struct list_head *entry = &timer->entry;
+
+        __list_del(entry->prev, entry->next);
+        if (clear_pending)
+                entry->next = NULL;
+        entry->prev = LIST_POISON2;
+}
+
+/*
+ * We are using hashed locking: holding per_cpu(tvec_bases).t_base.lock
+ * means that all timers which are tied to this base via timer->base are
+ * locked, and the base itself is locked too.
+ *
+ * So __run_timers/migrate_timers can safely modify all timers which could
+ * be found on ->tvX lists.
+ *
+ * When the timer's base is locked, and the timer removed from list, it is
+ * possible to set timer->base = NULL and drop the lock: the timer remains
+ * locked.
+ */
+static timer_base_t *lock_timer_base(struct timer_list *timer,
+                                        unsigned long *flags)
+{
+        timer_base_t *base;
+
+        for (;;) {
+                base = timer->base;
+                if (likely(base != NULL)) {
+                        spin_lock_irqsave(&base->lock, *flags);
+                        if (likely(base == timer->base))
+                                return base;
+                        /* The timer has migrated to another CPU */
+                        spin_unlock_irqrestore(&base->lock, *flags);
+                }
+                cpu_relax();
+        }
+}
+
: int __mod_timer(struct timer_list *timer, unsigned long expires)
: {
-	tvec_base_t *old_base, *new_base;
+	timer_base_t *base;
+	tvec_base_t *new_base;
: 	unsigned long flags;
: 	int ret = 0;
: 
: 	BUG_ON(!timer->function);
-
: 	check_timer(timer);
: 
-	spin_lock_irqsave(&timer->lock, flags);
+	base = lock_timer_base(timer, &flags);
+	
+	if (timer_pending(timer)) {
+		detach_timer(timer, 0);
+		ret = 1;
+		}
+
: 	new_base = &__get_cpu_var(tvec_bases);
-repeat:
-	old_base = timer->base;
: 
-	/*
-	 * Prevent deadlocks via ordering by old_base < new_base.
-	 */
-	if (old_base && (new_base != old_base)) {
-		if (old_base < new_base) {
-			spin_lock(&new_base->lock);
-			spin_lock(&old_base->lock);
-		} else {
-			spin_lock(&old_base->lock);
-			spin_lock(&new_base->lock);
-		}
+	if (base != &new_base->t_base) {
: 		/*
-		 * The timer base might have been cancelled while we were
-		 * trying to take the lock(s):
+		 * We are trying to schedule the timer on the local CPU.
+		 * However we can't change timer's base while it is running,
+		 * otherwise del_timer_sync() can't detect that the timer's
+		 * handler yet has not finished. This also guarantees that
+		 * the timer is serialized wrt itself.
*/
-		if (timer->base != old_base) {
-			spin_unlock(&new_base->lock);
-			spin_unlock(&old_base->lock);
-			goto repeat;
-		}
-	} else {
-		spin_lock(&new_base->lock);
-		if (timer->base != old_base) {
-			spin_unlock(&new_base->lock);
-			goto repeat;
+		if (unlikely(base->running_timer == timer)) {
+			/* The timer remains on a former base */
+			new_base = container_of(base, tvec_base_t, t_base);
+		} else {
+			/* See the comment in lock_timer_base() */
+			timer->base = NULL;
+			spin_unlock(&base->lock);
+			spin_lock(&new_base->t_base.lock);
+			timer->base = &new_base->t_base;
: 		}
: 	}
: 
-	/*
-	 * Delete the previous timeout (if there was any), and install
-	 * the new one:
-	 */
-	if (old_base) {
-		list_del(&timer->entry);
-		ret = 1;
-	}
: 	timer->expires = expires;
: 	internal_add_timer(new_base, timer);
-	timer->base = new_base;
-
-	if (old_base && (new_base != old_base))
-		spin_unlock(&old_base->lock);
-	spin_unlock(&new_base->lock);
-	spin_unlock_irqrestore(&timer->lock, flags);
-
+	spin_unlock_irqrestore(&new_base->t_base.lock, flags);
+	
: 	return ret;
: }
: 
@@ -243,10 +291,10 @@
: 
: 	check_timer(timer);
: 
-	spin_lock_irqsave(&base->lock, flags);
+	spin_lock_irqsave(&base->t_base.lock, flags);
+	timer->base = &base->t_base;
: 	internal_add_timer(base, timer);
-	timer->base = base;
-	spin_unlock_irqrestore(&base->lock, flags);
+	spin_unlock_irqrestore(&base->t_base.lock, flags);
: }
: 
: 
@@ -301,109 +349,84 @@
*/
: int del_timer(struct timer_list *timer)
: {
+	timer_base_t *base;
: 	unsigned long flags;
-	tvec_base_t *base;
-
+	int ret = 0;
+	
: 	check_timer(timer);
: 
-repeat:
- 	base = timer->base;
-	if (!base)
-		return 0;
-	spin_lock_irqsave(&base->lock, flags);
-	if (base != timer->base) {
+	if (timer_pending(timer)) {
+		base = lock_timer_base(timer, &flags);
+		if (timer_pending(timer)) {
+			detach_timer(timer, 1);
+			ret = 1;
+		}
: 		spin_unlock_irqrestore(&base->lock, flags);
-		goto repeat;
: 	}
-	list_del(&timer->entry);
-	/* Need to make sure that anybody who sees a NULL base also sees the list ops */
-	smp_wmb();
-	timer->base = NULL;
-	spin_unlock_irqrestore(&base->lock, flags);
: 
-	return 1;
+	return ret;
: }
: 
: EXPORT_SYMBOL(del_timer);
: 
: #ifdef CONFIG_SMP
-/***
- * del_timer_sync - deactivate a timer and wait for the handler to finish.
- * @timer: the timer to be deactivated
- *
- * This function only differs from del_timer() on SMP: besides deactivating
- * the timer it also makes sure the handler has finished executing on other
- * CPUs.
- *
- * Synchronization rules: callers must prevent restarting of the timer,
- * otherwise this function is meaningless. It must not be called from
- * interrupt contexts. The caller must not hold locks which would prevent
- * completion of the timer's handler.  Upon exit the timer is not queued and
- * the handler is not running on any CPU.
- *
- * The function returns whether it has deactivated a pending timer or not.
+/*
+ * This function tries to deactivate a timer. Upon successful (ret >= 0)
+ * exit the timer is not queued and the handler is not running on any CPU.
*
- * del_timer_sync() is slow and complicated because it copes with timer
- * handlers which re-arm the timer (periodic timers).  If the timer handler
- * is known to not do this (a single shot timer) then use
- * del_singleshot_timer_sync() instead.
+ * It must not be called from interrupt contexts.
*/
-int del_timer_sync(struct timer_list *timer)
+int try_to_del_timer_sync(struct timer_list *timer)
: {
-	tvec_base_t *base;
-	int i, ret = 0;
-
-	check_timer(timer);
+	timer_base_t *base;
+	unsigned long flags;
+	int ret = -1;
: 
-del_again:
-	ret += del_timer(timer);
+	base = lock_timer_base(timer, &flags);
: 
-	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;
-		}
+	if (base->running_timer == timer)
+		goto out;
+	
+	ret = 0;
+	if (timer_pending(timer)) {
+		detach_timer(timer, 1);
+		ret = 1;
: 	}
-	smp_rmb();
-	if (timer_pending(timer))
-		goto del_again;
-
+out:
+	spin_unlock_irqrestore(&base->lock, flags);
+	 
: 	return ret;
: }
-EXPORT_SYMBOL(del_timer_sync);
: 
: /***
- * del_singleshot_timer_sync - deactivate a non-recursive timer
+ * del_timer_sync - deactivate a timer and wait for the handler to finish.
* @timer: the timer to be deactivated
*
- * This function is an optimization of del_timer_sync for the case where the
- * caller can guarantee the timer does not reschedule itself in its timer
- * function.
+ * This function only differs from del_timer() on SMP: besides deactivating
+ * the timer it also makes sure the handler has finished executing on other
+ * CPUs.
*
* Synchronization rules: callers must prevent restarting of the timer,
* otherwise this function is meaningless. It must not be called from
- * interrupt contexts. The caller must not hold locks which wold prevent
- * completion of the timer's handler.  Upon exit the timer is not queued and
- * the handler is not running on any CPU.
+ * interrupt contexts. The caller must not hold locks which would prevent
+ * completion of the timer's handler. The timer's handler must not call
+ * add_timer_on(). Upon exit the timer is not queued and the handler is
+ * not running on any CPU.
*
* The function returns whether it has deactivated a pending timer or not.
*/
-int del_singleshot_timer_sync(struct timer_list *timer)
+int del_timer_sync(struct timer_list *timer)
: {
-	int ret = del_timer(timer);
-
-	if (!ret) {
-		ret = del_timer_sync(timer);
-		BUG_ON(ret);
-	}
+        check_timer(timer);
: 
-	return ret;
+        for (;;) {
+                int ret = try_to_del_timer_sync(timer);
+                if (ret >= 0)
+                        return ret;
+        }
: }
-EXPORT_SYMBOL(del_singleshot_timer_sync);
+
+EXPORT_SYMBOL(del_timer_sync);
: #endif
: 
: static int cascade(tvec_base_t *base, tvec_t *tv, int index)
@@ -421,7 +444,7 @@
: 		struct timer_list *tmp;
: 
: 		tmp = list_entry(curr, struct timer_list, entry);
-		BUG_ON(tmp->base != base);
+		BUG_ON(tmp->base != &base->t_base);
: 		curr = curr->next;
: 		internal_add_timer(base, tmp);
: 	}
@@ -443,7 +466,7 @@
: {
: 	struct timer_list *timer;
: 
-	spin_lock_irq(&base->lock);
+	spin_lock_irq(&base->t_base.lock);
: 	while (time_after_eq(jiffies, base->timer_jiffies)) {
: 		struct list_head work_list = LIST_HEAD_INIT(work_list);
: 		struct list_head *head = &work_list;
@@ -459,8 +482,7 @@
: 			cascade(base, &base->tv5, INDEX(3));
: 		++base->timer_jiffies; 
: 		list_splice_init(base->tv1.vec + index, &work_list);
-repeat:
-		if (!list_empty(head)) {
+		while (!list_empty(head)) {
: 			void (*fn)(unsigned long);
: 			unsigned long data;
: 
@@ -468,25 +490,22 @@
: 			fn = timer->function;
: 			data = timer->data;
: 
-			list_del(&timer->entry);
: 			set_running_timer(base, timer);
-			smp_wmb();
-			timer->base = NULL;
-			spin_unlock_irq(&base->lock);
+			detach_timer(timer, 1);
+			spin_unlock_irq(&base->t_base.lock);
: 			{
-				u32 preempt_count = preempt_count();
+				int preempt_count = preempt_count();
: 				fn(data);
: 				if (preempt_count != preempt_count()) {
: 					printk("huh, entered %p with %08x, exited with %08x?\n", fn, preempt_count, preempt_count());
: 					BUG();
: 				}
: 			}
-			spin_lock_irq(&base->lock);
-			goto repeat;
+			spin_lock_irq(&base->t_base.lock);
: 		}
: 	}
: 	set_running_timer(base, NULL);
-	spin_unlock_irq(&base->lock);
+	spin_unlock_irq(&base->t_base.lock);
: }
: 
: #ifdef CONFIG_NO_IDLE_HZ
@@ -505,7 +524,7 @@
: 	int i, j;
: 
: 	base = &__get_cpu_var(tvec_bases);
-	spin_lock(&base->lock);
+	spin_lock(&base->t_base.lock);
: 	expires = base->timer_jiffies + (LONG_MAX >> 1);
: 	list = 0;
: 
@@ -553,7 +572,7 @@
: 				expires = nte->expires;
: 		}
: 	}
-	spin_unlock(&base->lock);
+	spin_unlock(&base->t_base.lock);
: 	return expires;
: }
: #endif
@@ -1307,11 +1326,8 @@
: 	int j;
: 	tvec_base_t *base;
: 	
-	if (per_cpu(timer_inited, cpu))
-		return;
-       
: 	base = &per_cpu(tvec_bases, cpu);
-	spin_lock_init(&base->lock);
+	spin_lock_init(&base->t_base.lock);
: 	for (j = 0; j < TVN_SIZE; j++) {
: 		INIT_LIST_HEAD(base->tv5.vec + j);
: 		INIT_LIST_HEAD(base->tv4.vec + j);
@@ -1322,26 +1338,19 @@
: 		INIT_LIST_HEAD(base->tv1.vec + j);
: 
: 	base->timer_jiffies = jiffies;
-	per_cpu(timer_inited, cpu) = 1;
: }
: 
: #ifdef CONFIG_HOTPLUG_CPU
-static int migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
+static void migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
: {
: 	struct timer_list *timer;
: 
: 	while (!list_empty(head)) {
: 		timer = list_entry(head->next, struct timer_list, entry);
-		/* We're locking backwards from __mod_timer order here,
-		   beware deadlock. */
-		if (!spin_trylock(&timer->lock))
-			return 0;
-		list_del(&timer->entry);
+		detach_timer(timer, 0);
+		timer->base = &new_base->t_base;
: 		internal_add_timer(new_base, timer);
-		timer->base = new_base;
-		spin_unlock(&timer->lock);
: 	}
-	return 1;
: }
: 
: static void __devinit migrate_timers(int cpu)
@@ -1396,7 +1405,6 @@
: {
: 	long cpu = (long)hcpu;
: 	switch(action) {
-	case CPU_UP_PREPARE_EARLY:
: 	case CPU_UP_PREPARE:
: 		init_timers_cpu(cpu);
: 		break;

Summary for Fedora Core 4 w/2.6.12-1.1398_FC4 kernel (x86_64)

29 July 2005 - mats

Output for the twelve exec fails noted above for 2.6.12 kernels is omitted, but the counts are not.

/tset/LI18NUX2K.L1/utils/cpio-fh/T.cpio-fh 5 FAIL
/tset/LI18NUX2K.L1/utils/cpio-fh/T.cpio-fh 6 FAIL
/tset/LI18NUX2K.L1/utils/cpio-fh/T.cpio-fh 7 FAIL
/tset/POSIX.os/procprim/sigconcept/T.sigconcept 41 UNRESOLVED

Test system: FC4/x86_64
Test was run: 20050729 07:36:54
Test Suite Version: 3.0.0-4
Test Suite Architecture: (x86_64)
Total Tests Passed: 9843
Total Tests Failed (including waived): 16
Total Tests Failed (excluding waived): 16

Test Result Breakdown:
PASS: 5300
WARNING: 19
NOTIMP: 0
UNAPPROVE: 0
UNSUPPORTED: 131
TEST_ERROR: 0
FIP: 10
NOTINUSE: 4328
UNRESOLVED: 1
UNINITIATED: 0
UNTESTED: 55
FAIL: 15
UNKNOWN: 0
UNREPORTED: 0

Summary for 3.0.0-2 on LSB SI

10 June 2005 - heffler

The following problems occurred when executing the runtime test on all architectures:

/tset/LI18NUX2K.L1/utils/cpio-fh/T.cpio-fh 5 FAIL
/tset/LI18NUX2K.L1/utils/cpio-fh/T.cpio.fh 6 FAIL
/tset/LI18NUX2K.L1/utils/cpio-fh/T.cpio.fh 7 FAIL
/tset/LI18NUX2K.L1/utils/diff/T.diff 2 FAIL
/tset/LI18NUX2K.L1/utils/unexpand/T.unexpand 1 FAIL

The following problem only occurred on IA32 and PPC64:

/tset/POSIX.os/procprim/sigconcept/T.sigconcept 41 UNRESOLVED

The following problem only occurred on IA64:

/tset/ANSI.os/streamio/freopen/T.freopen 16 FAIL

The next two problem were only seen on PPC32 and are most likely caused by bugs in the context routines in glibc-2.3.5. The source in CVS for glibc has been updated and an attempt at a patch for the lsbsi will be made.

/tset/LSB.os/jump/makecontext/T.makecontext 1 UNRESOLVED
/tset/LSB.os/jump/makecontext/T.makecontext 3 UNRESOLVED

The next problem was only seen on PPC32 and S390. The test hangs and must be killed with CTRL-C in order to continue the runtime test suite.

/tset/LSB.os/mprotect/mprotect_P/T.mprotect_P 8 UNREPORTED

The next problem was only seen on S390X:

/tset/ANSI.os/streamio/fopen/T.fopen 5 FAIL

The next problem was only seen on X86_64:

/tset/POSIX.os/procprim/sleep/T.sleep 1 FAIL

Summary for 3.0.0-2 on Fedora Core 3 x86_64

3 June 2005 - mats

/tset/LSB.os/ioprim/writev_L/T.writev_L 29 FAIL
/tset/LSB.pam/testcases/pam_authenticate/pam_authenticate 6 FAIL
/tset/LSB.pam/testcases/pam_close_session/pam_close_session 2 FAIL
/tset/LSB.pam/testcases/pam_open_session/pam_open_session 3 FAIL
/tset/POSIX.os/procprim/sigconcept/T.sigconcept 41 UNRESOLVED


Test system: x86_64/FC3
Test was run: 20050603 07:11:53 
Total Tests Passed: 9854
Total Tests Failed (including waived): 5
Total Tests Failed (excluding waived): 5

Test Result Breakdown:
PASS: 5309
WARNING: 19
NOTIMP: 0
UNAPPROVE: 0
UNSUPPORTED: 133
TEST_ERROR: 0
FIP: 10
NOTINUSE: 4328
UNRESOLVED: 1
UNINITIATED: 0
UNTESTED: 55
FAIL: 4
UNKNOWN: 0
UNREPORTED: 0

Initially I had a test count mismatch, that turned out to be an out-of-date version of tjreport.

The writev problem is known, described elsewhere on this page. The PAM problems *seem* to be things fixed by later version of upstream. The only unusual one is the UNRES on sigconcept. Here is the journal snip:

10|531 /tset/POSIX.os/procprim/sigconcept/T.sigconcept 10:20:25|TC Start, scenario ref 534-0
...
400|531 41 1 10:42:29|IC Start
200|531 41 10:42:29|TP Start
520|531 41 00014023 2 1|child process terminated incorrectly
520|531 41 00014023 2 2|expected action: process terminated - signal 9
520|531 41 00014023 2 3|observed action: process still active
520|531 41 00014547 1 1|unexpected signal 15 (SIGTERM) received
520|531 41 00014023 4 1|child process terminated incorrectly
520|531 41 00014023 4 2|expected action: process terminated - signal 9
520|531 41 00014023 4 3|observed action: process still active
520|531 41 00014551 1 1|unexpected signal 15 (SIGTERM) received
520|531 41 00014023 5 1|path tracing error: path counter 3, expected 5
220|531 41 2 10:42:57|UNRESOLVED
410|531 41 1 10:42:57|IC End

Summary for 2.9.0-3 on SuSE Linux 9.2 on x86

18 April 2005 - AJJ


/tset/LSB.pam/testcases/pam_acct_mgmt/pam_acct_mgmt 4 FAIL
/tset/LSB.pam/testcases/pam_acct_mgmt/pam_acct_mgmt 5 FAIL
(cause as yet unknown for the above two problems)

Test system: UNKNOWN
Test was run: 20050418 08:35:51
Test Suite Version: 2.9.0-3
Test Suite Architecture: (i386)
Total Tests Passed: 10105
Total Tests Failed (including waived): 2
Total Tests Failed (excluding waived): 2

Test Result Breakdown:
PASS: 5445
WARNING: 16
NOTIMP: 0
UNAPPROVE: 0
UNSUPPORTED: 125
TEST_ERROR: 0
FIP: 8
NOTINUSE: 4452
UNRESOLVED: 0
UNINITIATED: 0
UNTESTED: 59
FAIL: 2
UNKNOWN: 0
UNREPORTED: 0

Results:
Total tests:            10107   PASS = 10105    FAIL = 2

Pass Breakdown:
Number of successes:    5445    Number of warnings:     16
Number unsupported:     125     Number not in use:      4452
Number of untested:     59      Number of FIP:          8
Unapproved assertions:  0       Number not implemented: 0

Failure Breakdown:
Number of failures:     2       Number unresolved:      0
Number uninitiated:     0       Number unreported:      0
Mats: pam_acct_mgmt above seem to be related to getting the vsx1 account set up right, with a valid password. See bug 965 for more on this one.


2.9.0-3 General comments:

It looks as if 2.9.0-3 clears a number of issues with 2.9.0-2 (the build of PTHR.os, the dynamic linker version, the timing tests etc). Known problems on some platforms are with the syslog tests (which need to be removed/disabled later. We also need to move to using a central version of TET.

2.9.0-2 General comments:

The PTHR.os tests are not being built and so are not being executed. The test counts are off, cvs has a fix for the ANSI.os test counts We need to ensure that the dynamic linker is the LSB 3.0 one, see bug 825

From Thorsten 13 April 2005

I run it on SLES9 SP2 last night and, after making sure that all
shell scripts are executeable, I got only two Fails (which were a
problem of a wrong setup done by me).

If I forget to disable NIS, I always get a fail in:

: /tset/POSIX.os/sysdb/getpwuid/T.getpwuid 2      Failed

becaue UID 25000 is in use in our network. Maybe we should try to find
a unused ID during configure phase of run_tests?

The other fail is:

: /tset/LSB.os/devclass/grantpt_L/T.grantpt_L 1   Failed
: 
: Test Information:
: incorrect mode on /dev/pts/3: expected 0620 got 020600

I have no idea if this is a new problem with the test suite or with
the new kernel, I have to run the old testsuite first to verify it.

The integration of the LSB-PAM suite seems to work great, all tests
passes.

Everybody having problem with the PAM testsuite should try to update
Linux-PAM to version 0.79.

Mandriva LE2005 (cooker x86_64) 2.9.0-2 runtime-test: (after chmod +x scripts/li18nux2000-level1/runtime-config.sh)

/tset/LSB.os/devclass/grantpt_L/T.grantpt_L 1 FAIL                              
: 
: Test Information:                                                       
: incorrect mode on /dev/pts/0: expected 0620 got 020600                  
: 
: (I believe it's udev related, showed up about the middle of             
: cooker with 2.0 tests too)                                              

: Thorsten feels it's not udev related.
: seems it's regression in mount - I'm committing this patch:

--- util-linux-2.12q/mount/mount.c.devpts-mode  2005-06-01 22:31:58.727618339 +0200
+++ util-linux-2.12q/mount/mount.c      2005-06-01 22:32:33.490286230 +0200
@@ -476,7 +476,7 @@
: static char *fs_using_iocharset[] = { "iso9660", "udf", "vfat", "msdos", "ntfs", "jfs", "smbfs", "befs", "cifs", NULL };
: static char *fs_using_codepage[] = { "iso9660", "vfat", "msdos", "smbfs", NULL };
: static char *fs_using_umask[] = { "iso9660", "udf", "vfat", "msdos", "ntfs", "hfs", "hfsplus", "hpfs", NULL };
-   static char *fs_using_mode[] = { "iso9660", "ncpfs", "affs", NULL };
+   static char *fs_using_mode[] = { "iso9660", "ncpfs", "affs", "devpts", NULL };
: static char *fs_using_nls[] = { "ntfs", NULL };
: static char *fs_using_utf8[] = { "iso9660", "ntfs", "vfat", NULL };
: 
/tset/LSB.os/ioprim/writev_L/T.writev_L 29 FAIL                                 
: 
: Test Information:                                                       
: iov[0].iov_base = 0x530890, iov[0].iov_len = 4096                       
: iov[1].iov_base = 0x530890, iov[1].iov_len = -1                         
: writev(7, iov, 2) did not behave as expected:                           
: ERRNO VALUES: expected: 22 (EINVAL), observed: 14 (EFAULT)              

: Thorsten posted that this is a known kernel bug - fixed upstream.
: Discussion, patch here: http://bugme.osdl.org/show_bug.cgi?id=4326
: :: Mats: is there any way to tell when this went into mainstream? The bug just says "fixed in code".
: 
/tset/LSB.os/procprim/fork/T.fork 10 FAIL                              
: Test Information:                                                       
: mq_open() failed for "/vsrt_mqueue", errno = 22 (EINVAL)                

: Mats mentions this is a test-suite issue.
: :: Mats: had to do with how it was built - picking up some non-LSB calls. Is this cleared now?
: 
Test system: SE2005 (cooker x86_64)                                             
Test was run: 20050412 22:02:46                                                 
Test Suite Version: 2.9.0-2                                                     
Test Suite Architecture: (x86_64)                                               
Total Tests Passed: 9752                                                        
Total Tests Failed (including waived): 3                                        
Total Tests Failed (excluding waived): 3                 

Mandriva SE2005 (cooker x86) 2.9.0-2 runtime-test (after chmod +x scripts/li18nux2000-level1/runtime-config.sh)

/tset/LSB.os/devclass/grantpt_L/T.grantpt_L 1 FAIL                              
/tset/LSB.os/ioprim/writev_L/T.writev_L 29 FAIL                                 
: 
: Test Information:                                                       
: iov[0].iov_base = 0x8071b00, iov[0].iov_len = 4096                      
: iov[1].iov_base = 0x8071b00, iov[1].iov_len = -1                        
: writev(7, iov, 2) did not behave as expected:                           
: ERRNO VALUES: expected: 22 (EINVAL), observed: 14 (EFAULT)

/tset/LSB.os/procprim/fork/T.fork 10 FAIL                                       
/tset/POSIX.os/procenv/times/T.times 4 FAIL                                     
: 
: Test Information:                                                       
: observed current time: 0, observed past time: 0                         
: (after 4000 sys_call() calls                                            
: 
/tset/POSIX.os/procenv/times/T.times 6 UNINITIATED                              
: 
: Test Information:                                                       
: depends on success of test 4                                            
: 
/tset/POSIX.os/procprim/fork/T.fork 5 UNRESOLVED                       
: 
: Test Information:                                                       
: deletion reason: tms_utime and tms_stime are not                        
: both non-zero before fork()                                             
: utime: 1; stime: 0                                              
: 
: 
I've been seeing the above 3 with LSB2.0 on the faster machine that I just      
replaced with this current one. They don't show on an older machine             
(<1GHz).                                                                

Test system: LE2005 (cooker)                                                    
Test was run: 20050412 16:52:18                                                 
Test Suite Version: 2.9.0-2                                                     
Test Suite Architecture: (i386)                                                 
Total Tests Passed: 9749                                                        
Total Tests Failed (including waived): 6                                        
Total Tests Failed (excluding waived): 6                     

[[[LsbRuntimeTest3]]/Comments User Comments] [[Include(LsbRuntimeTest3/Comments)]]


[Article] [Discussion] [View source] [History]