patch-2.1.127 linux/kernel/sched.c
Next file: linux/kernel/signal.c
Previous file: linux/kernel/ksyms.c
Back to the patch index
Back to the overall index
- Lines: 274
- Date:
Fri Nov 6 17:15:02 1998
- Orig file:
v2.1.126/linux/kernel/sched.c
- Orig date:
Sat Sep 5 16:46:42 1998
diff -u --recursive --new-file v2.1.126/linux/kernel/sched.c linux/kernel/sched.c
@@ -230,7 +230,7 @@
* "current->state = TASK_RUNNING" to mark yourself runnable
* without the overhead of this.
*/
-inline void wake_up_process(struct task_struct * p)
+void wake_up_process(struct task_struct * p)
{
unsigned long flags;
@@ -248,7 +248,6 @@
{
struct task_struct * p = (struct task_struct *) __data;
- p->timeout = 0;
wake_up_process(p);
}
@@ -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,74 @@
#endif
+signed long schedule_timeout(signed long timeout)
+{
+ struct timer_list timer;
+ unsigned long expire;
+
+ /*
+ * PARANOID.
+ */
+ if (current->state == TASK_UNINTERRUPTIBLE)
+ {
+ printk(KERN_WARNING "schedule_timeout: task not interrutible "
+ "from %p\n", __builtin_return_address(0));
+ /*
+ * We don' t want to interrupt a not interruptible task
+ * risking to cause corruption. Better a a deadlock ;-).
+ */
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ }
+
+ /*
+ * Here we start for real.
+ */
+ switch (timeout)
+ {
+ case MAX_SCHEDULE_TIMEOUT:
+ /*
+ * These two special cases are useful to be comfortable
+ * in the caller. Nothing more. We could take
+ * MAX_SCHEDULE_TIMEOUT from one of the negative value
+ * but I' d like to return a valid offset (>=0) to allow
+ * the caller to do everything it want with the retval.
+ */
+ schedule();
+ goto out;
+ default:
+ /*
+ * Another bit of PARANOID. Note that the retval will be
+ * 0 since no piece of kernel is supposed to do a check
+ * for a negative retval of schedule_timeout() (since it
+ * should never happens anyway). You just have the printk()
+ * that will tell you if something is gone wrong and where.
+ */
+ if (timeout < 0)
+ {
+ printk(KERN_ERR "schedule_timeout: wrong timeout "
+ "value %lx from %p\n", timeout,
+ __builtin_return_address(0));
+ goto out;
+ }
+ }
+
+ expire = 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 = expire - jiffies;
+
+ out:
+ return timeout < 0 ? 0 : 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 +525,6 @@
asmlinkage void schedule(void)
{
struct task_struct * prev, * next;
- unsigned long timeout;
int this_cpu;
prev = current;
@@ -481,16 +547,10 @@
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:
+ if (signal_pending(prev)) {
prev->state = TASK_RUNNING;
break;
}
@@ -550,21 +610,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);
@@ -702,7 +750,6 @@
schedule();
tsk->state = task_state;
}
-
tsk->state = TASK_RUNNING;
remove_wait_queue(&sem->wait, &wait);
return ret;
@@ -718,32 +765,54 @@
return __do_down(sem,TASK_INTERRUPTIBLE);
}
-
-static void FASTCALL(__sleep_on(struct wait_queue **p, int state));
-static void __sleep_on(struct wait_queue **p, int state)
-{
- unsigned long flags;
+#define SLEEP_ON_VAR \
+ unsigned long flags; \
struct wait_queue wait;
- current->state = state;
- wait.task = current;
- write_lock_irqsave(&waitqueue_lock, flags);
- __add_wait_queue(p, &wait);
+#define SLEEP_ON_HEAD \
+ wait.task = current; \
+ write_lock_irqsave(&waitqueue_lock, flags); \
+ __add_wait_queue(p, &wait); \
write_unlock(&waitqueue_lock);
- schedule();
- write_lock_irq(&waitqueue_lock);
- __remove_wait_queue(p, &wait);
+
+#define SLEEP_ON_TAIL \
+ write_lock_irq(&waitqueue_lock); \
+ __remove_wait_queue(p, &wait); \
write_unlock_irqrestore(&waitqueue_lock, flags);
-}
void interruptible_sleep_on(struct wait_queue **p)
{
- __sleep_on(p,TASK_INTERRUPTIBLE);
+ SLEEP_ON_VAR
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ SLEEP_ON_HEAD
+ schedule();
+ SLEEP_ON_TAIL
+}
+
+long interruptible_sleep_on_timeout(struct wait_queue **p, long timeout)
+{
+ SLEEP_ON_VAR
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ SLEEP_ON_HEAD
+ timeout = schedule_timeout(timeout);
+ SLEEP_ON_TAIL
+
+ return timeout;
}
void sleep_on(struct wait_queue **p)
{
- __sleep_on(p,TASK_UNINTERRUPTIBLE);
+ SLEEP_ON_VAR
+
+ current->state = TASK_UNINTERRUPTIBLE;
+
+ SLEEP_ON_HEAD
+ schedule();
+ SLEEP_ON_TAIL
}
void scheduling_functions_end_here(void) { }
@@ -803,7 +872,7 @@
break;
if (!(mask & timer_active))
continue;
- if (tp->expires > jiffies)
+ if (time_after(tp->expires, jiffies))
continue;
timer_active &= ~mask;
tp->fn();
@@ -1488,7 +1557,8 @@
{
spin_lock(&scheduler_lock);
spin_lock_irq(&runqueue_lock);
- current->policy |= SCHED_YIELD;
+ if (current->policy == SCHED_OTHER)
+ current->policy |= SCHED_YIELD;
current->need_resched = 1;
move_last_runqueue(current);
spin_unlock_irq(&runqueue_lock);
@@ -1563,16 +1633,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;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov