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

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


On Sun, 18 Oct 1998, Andrea Arcangeli wrote:

>On Sun, 18 Oct 1998, MOLNAR Ingo wrote:
>
>>with the special values '0' and '-1' devoted to 'no timeout' and
>>'forever'. And since the timeout is delta, there are no wraparound issues.
>
>OK, I' ll try.

This what I produced so far, now I am going to try to update the rest of
the kernel I use in my kernel-configuration and then I' ll try to boot
;-).

Index: kernel/sched.c
===================================================================
RCS file: /var/cvs/linux/kernel/sched.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 sched.c
--- sched.c 1998/10/02 17:22:39 1.1.1.1
+++ sched.c 1998/10/18 16:09:57
@@ -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,65 @@

#endif

+#define MAX_TIMEOUT (jiffies + (~0UL >> 1))
+
+void schedule_timeout(unsigned long * timeout)
+{
+ unsigned long __timeout = *timeout;
+ struct timer_list timer;
+
+ /*
+ * 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 > (~0UL >> 1))
+ {
+ 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.
+ */
+ if (__timeout == ~0UL)
+ __timeout = MAX_TIMEOUT;
+ else
+ __timeout += jiffies;
+
+ init_timer(&timer);
+ timer.expires = __timeout;
+ timer.data = (unsigned long) current;
+ timer.function = process_timeout;
+
+ add_timer(&timer);
+ schedule();
+ del_timer(&timer);
+
+ __timeout -= jiffies;
+
+ /*
+ * This will allow us to be lazy in the caller.
+ */
+ if ((signed long) __timeout < 0)
+ __timeout = 0;
+
+ *timeout = __timeout;
+
+ return;
+
+ normal_schedule:
+ schedule();
+}
+
+#undef MAX_TIMEOUT
+
/*
* '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 +516,6 @@
asmlinkage void schedule(void)
{
struct task_struct * prev, * next;
- unsigned long timeout;
int this_cpu;

prev = current;
@@ -481,16 +538,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 +602,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 +843,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 +1603,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();
+ 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: include/linux/sched.h
===================================================================
RCS file: /var/cvs/linux/include/linux/sched.h,v
retrieving revision 1.1.1.1.2.1
diff -u -r1.1.1.1.2.1 sched.h
--- sched.h 1998/10/05 16:21:46 1.1.1.1.2.1
+++ sched.h 1998/10/18 16:14:08
@@ -23,6 +23,8 @@
#include <linux/capability.h>
#include <linux/securebits.h>

+#define JIFFIES_OFFSET (-120*HZ)
+
/*
* cloning flags:
*/
@@ -258,7 +260,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 +350,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, }, \

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/