Re: 2.4.0test1-ac14: smp deadlock

From: Philipp Rumpf (prumpf@puffin.external.hp.com)
Date: Mon Jun 12 2000 - 06:41:55 EST


On Mon, Jun 12, 2000 at 09:52:23AM +0100, David Woodhouse wrote:
> andrewm@uow.edu.au said:
> > Unfortunately schedule_timeout() doesn't actually call del_timer_sync.
> >
>
> Er,... it did in -ac14. It looked 'obviously correct' to me. So I sent the
> patch to Alan with with a question mark indicating that I wanted him to
> comment rather than just apply it. In hindsight, perhaps I should have made
> that more explicit.
>
> Why _doesn't_ it work, though?

>From reading del_timer_sync, you're only allowed to use it if you use
timer_exit in your timer, like this:

--- linux/kernel/sched.c Sun Jun 11 17:02:22 2000
+++ linux-prumpf/kernel/sched.c Sun Jun 11 18:43:20 2000
@@ -337,15 +337,23 @@
         spin_unlock_irqrestore(&runqueue_lock, flags);
 }
 
+struct foo_struct {
+ struct task_struct *process;
+ struct timer_list *timer;
+};
+
 static void process_timeout(unsigned long __data)
 {
- struct task_struct * p = (struct task_struct *) __data;
+ struct foo_struct *p = (struct foo_struct *) __data;
+
+ wake_up_process(p->process);
 
- wake_up_process(p);
+ timer_exit(p->timer);
 }
 
 signed long schedule_timeout(signed long timeout)
 {
+ struct foo_struct foo;
         struct timer_list timer;
         unsigned long expire;
 
@@ -383,8 +391,11 @@
 
         init_timer(&timer);
         timer.expires = expire;
- timer.data = (unsigned long) current;
+ timer.data = (unsigned long) &foo;
         timer.function = process_timeout;
+
+ foo.process = current;
+ foo.timer = &timer;
 
         add_timer(&timer);
         schedule();

Of course, if you go through the complexity of doing this, you could just
use a finished flag in the struct and use del_timer by hand:

--- linux/kernel/sched.c Sun Jun 11 17:02:22 2000
+++ linux-prumpf/kernel/sched.c Sun Jun 11 18:45:48 2000
@@ -337,15 +337,23 @@
         spin_unlock_irqrestore(&runqueue_lock, flags);
 }
 
+struct foo_struct {
+ struct task_struct *process;
+ int finished;
+};
+
 static void process_timeout(unsigned long __data)
 {
- struct task_struct * p = (struct task_struct *) __data;
+ struct foo_struct *p = (struct foo_struct *) __data;
+
+ wake_up_process(p->process);
 
- wake_up_process(p);
+ p->finished = 0;
 }
 
 signed long schedule_timeout(signed long timeout)
 {
+ struct foo_struct foo;
         struct timer_list timer;
         unsigned long expire;
 
@@ -383,12 +391,16 @@
 
         init_timer(&timer);
         timer.expires = expire;
- timer.data = (unsigned long) current;
+ timer.data = (unsigned long) &foo;
         timer.function = process_timeout;
 
+ foo.process = current;
+ foo.finished = 0;
+
         add_timer(&timer);
         schedule();
- del_timer_sync(&timer);
+ if(!del_timer(&timer))
+ while(!(foo.finished));
 
         timeout = expire - jiffies;
 
but that's basically unrolling del_timer_sync by hand.

        Philipp Rumpf

-
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/



This archive was generated by hypermail 2b29 : Thu Jun 15 2000 - 21:00:25 EST