Re: [patch] jiffies wraparound [Re: 2.1.125 Show stopper list: Draft]

Andrea Arcangeli (andrea@e-mind.com)
Sun, 18 Oct 1998 21:58:50 +0200 (CEST)


On Sun, 18 Oct 1998, MOLNAR Ingo wrote:

>with the special values '0' and '-1' devoted to 'no timeout' and

As you see I just dropped from the beginning the 0 case. In the 0 case we
must use schedule() and not schedule_timeout() ;-).

Now I have dropped now also the -1 (forever) case. There' s now a nice
#define (MAX_SCHEDULE_TIMEOUT) that is just the right value (~0UL >> 1).
Using -1 is less pretty than using a #define and cause us to waste time
converting and checking for the -1 case...

Here my latest schedule_timeout() update against 2.1.125 (I like it so btw
;-):

Index: linux/kernel/sched.c
diff -u linux/kernel/sched.c:1.1.1.1 linux/kernel/sched.c:1.1.1.1.14.7
--- linux/kernel/sched.c:1.1.1.1 Fri Oct 2 19:22:39 1998
+++ linux/kernel/sched.c Sun Oct 18 21:47:49 1998
@@ -90,7 +90,7 @@

extern void mem_use(void);

-unsigned long volatile jiffies=0;
+unsigned long volatile jiffies=JIFFIES_OFFSET;

/*
* Init task must be ok at boot for the ix86 as we will check its signals
@@ -248,7 +248,6 @@
{
struct task_struct * p = (struct task_struct *) __data;

- p->timeout = 0;
wake_up_process(p);
}

@@ -341,7 +340,7 @@

#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))

-static unsigned long timer_jiffies = 0;
+static unsigned long timer_jiffies = JIFFIES_OFFSET;

static inline void insert_timer(struct timer_list *timer,
struct timer_list **vec, int idx)
@@ -372,12 +371,12 @@
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
insert_timer(timer, tv4.vec, i);
- } else if (expires < timer_jiffies) {
+ } else if ((signed long) idx < 0) {
/* can happen if you add a timer with expires == jiffies,
* or you set a timer to go off in the past
*/
insert_timer(timer, tv1.vec, tv1.index);
- } else if (idx < 0xffffffffUL) {
+ } else if (idx <= 0xffffffffUL) {
int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
insert_timer(timer, tv5.vec, i);
} else {
@@ -445,6 +444,50 @@

#endif

+signed long schedule_timeout(signed long timeout)
+{
+ struct timer_list timer;
+ unsigned long expire;
+
+ /*
+ * PARANOID.
+ */
+ if (current->state != TASK_INTERRUPTIBLE)
+ {
+ printk(KERN_ERR "schedule_timeout: task not interrutible "
+ " from %p\n", __builtin_return_address(0));
+ goto normal_schedule;
+ }
+ if (!timeout || timeout < 0)
+ {
+ printk(KERN_ERR "schedule_timeout: wrong timeout value %lx"
+ "from %p\n", timeout, __builtin_return_address(0));
+ goto normal_schedule;
+ }
+
+ /*
+ * Here we start for real.
+ */
+ expire = (unsigned long) timeout + jiffies;
+
+ init_timer(&timer);
+ timer.expires = expire;
+ timer.data = (unsigned long) current;
+ timer.function = process_timeout;
+
+ add_timer(&timer);
+ schedule();
+ del_timer(&timer);
+
+ timeout = (signed long) (expire - jiffies);
+
+ return timeout < 0 ? 0 : timeout;
+
+ normal_schedule:
+ schedule();
+ return 0;
+}
+
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
@@ -458,7 +501,6 @@
asmlinkage void schedule(void)
{
struct task_struct * prev, * next;
- unsigned long timeout;
int this_cpu;

prev = current;
@@ -481,16 +523,11 @@
prev->counter = prev->priority;
move_last_runqueue(prev);
}
- timeout = 0;
+
switch (prev->state) {
case TASK_INTERRUPTIBLE:
if (signal_pending(prev))
- goto makerunnable;
- timeout = prev->timeout;
- if (timeout && (timeout <= jiffies)) {
- prev->timeout = 0;
- timeout = 0;
- makerunnable:
+ {
prev->state = TASK_RUNNING;
break;
}
@@ -550,21 +587,9 @@
#endif

if (prev != next) {
- struct timer_list timer;
-
kstat.context_swtch++;
- if (timeout) {
- init_timer(&timer);
- timer.expires = timeout;
- timer.data = (unsigned long) prev;
- timer.function = process_timeout;
- add_timer(&timer);
- }
get_mmu_context(next);
switch_to(prev,next);
-
- if (timeout)
- del_timer(&timer);
}

spin_unlock(&scheduler_lock);
@@ -803,7 +828,7 @@
break;
if (!(mask & timer_active))
continue;
- if (tp->expires > jiffies)
+ if (time_after(tp->expires, jiffies))
continue;
timer_active &= ~mask;
tp->fn();
@@ -1563,16 +1588,14 @@
return 0;
}

- expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies;
+ expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);

- current->timeout = expire;
current->state = TASK_INTERRUPTIBLE;
- schedule();
+ expire = schedule_timeout(expire);

- if (expire > jiffies) {
+ if (expire) {
if (rmtp) {
- jiffies_to_timespec(expire - jiffies -
- (expire > jiffies + 1), &t);
+ jiffies_to_timespec(expire, &t);
if (copy_to_user(rmtp, &t, sizeof(struct timespec)))
return -EFAULT;
}
Index: linux/include/linux/sched.h
diff -u linux/include/linux/sched.h:1.1.1.1.2.1 linux/include/linux/sched.h:1.1.1.1.2.1.2.7
--- linux/include/linux/sched.h:1.1.1.1.2.1 Mon Oct 5 18:21:46 1998
+++ linux/include/linux/sched.h Sun Oct 18 20:50:16 1998
@@ -23,6 +23,8 @@
#include <linux/capability.h>
#include <linux/securebits.h>

+#define JIFFIES_OFFSET (-120*HZ)
+
/*
* cloning flags:
*/
@@ -119,6 +121,8 @@
extern void show_state(void);
extern void trap_init(void);

+#define MAX_SCHEDULE_TIMEOUT (~0UL >> 1)
+extern signed long schedule_timeout(signed long timeout);
asmlinkage void schedule(void);


@@ -258,7 +262,7 @@
struct task_struct **tarray_ptr;

struct wait_queue *wait_chldexit; /* for wait4() */
- unsigned long timeout, policy, rt_priority;
+ unsigned long policy, rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
@@ -348,7 +352,7 @@
/* pidhash */ NULL, NULL, \
/* tarray */ &task[0], \
/* chld wait */ NULL, \
-/* timeout */ 0,SCHED_OTHER,0,0,0,0,0,0,0, \
+/* timeout */ SCHED_OTHER,0,0,0,0,0,0,0, \
/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \
/* utime */ {0,0,0,0},0, \
/* per CPU times */ {0, }, {0, }, \
Index: linux/kernel/signal.c
diff -u linux/kernel/signal.c:1.1.1.1 linux/kernel/signal.c:1.1.1.1.12.4
--- linux/kernel/signal.c:1.1.1.1 Fri Oct 2 19:22:39 1998
+++ linux/kernel/signal.c Sun Oct 18 21:50:32 1998
@@ -712,6 +712,7 @@
sigset_t these;
struct timespec ts;
siginfo_t info;
+ long timeout = 0;

/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
@@ -738,22 +739,18 @@
if (!sig) {
/* None ready -- temporarily unblock those we're interested
in so that we'll be awakened when they arrive. */
- unsigned long expire;
sigset_t oldblocked = current->blocked;
sigandsets(&current->blocked, &current->blocked, &these);
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);

- expire = ~0UL;
- if (uts) {
- expire = (timespec_to_jiffies(&ts)
- + (ts.tv_sec || ts.tv_nsec));
- expire += jiffies;
- }
- current->timeout = expire;
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ if (uts)
+ timeout = (timespec_to_jiffies(&ts)
+ + (ts.tv_sec || ts.tv_nsec));

current->state = TASK_INTERRUPTIBLE;
- schedule();
+ timeout = schedule_timeout(timeout);

spin_lock_irq(&current->sigmask_lock);
sig = dequeue_signal(&these, &info);
@@ -770,10 +767,8 @@
}
} else {
ret = -EAGAIN;
- if (current->timeout != 0) {
- current->timeout = 0;
+ if (timeout)
ret = -EINTR;
- }
}

return ret;

Andrea Arcangeli

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/