fix a few more bugs detected by the simple tester.
[~madcoder/pwqr.git] / kernel / pwqr.c
index e5a232e..c705dfa 100644 (file)
@@ -115,6 +115,7 @@ struct pwqr_sb {
        unsigned                overcommit_wakes;
 
        int                     state;
+       unsigned                has_pollin;
 };
 
 struct pwqr_task {
@@ -192,7 +193,9 @@ static void pwqr_sb_timer_cb(unsigned long arg)
                        wake_up_locked(&sb->wqh);
        }
        if (sb->running > sb->concurrency) {
+               printk(KERN_DEBUG "wake up poll");
                wake_up_poll(&sb->wqh_poll, POLLIN);
+               sb->has_pollin = 1;
        }
        pwqr_sb_unlock_irqrestore(sb, flags);
 }
@@ -207,6 +210,7 @@ static struct pwqr_sb *pwqr_sb_create(void)
 
        kref_init(&sb->kref);
        init_waitqueue_head(&sb->wqh);
+       init_waitqueue_head(&sb->wqh_poll);
        sb->concurrency    = num_online_cpus();
        init_timer(&sb->timer);
        sb->timer.function = pwqr_sb_timer_cb;
@@ -320,6 +324,7 @@ static void pwqr_task_detach(struct pwqr_task *pwqt, struct pwqr_sb *sb)
        } else {
                __pwqr_sb_update_state(sb, 0);
        }
+       pwqt->notifier.ops = &pwqr_preempt_noop_ops;
        pwqr_sb_unlock_irqrestore(sb, flags);
        pwqr_sb_put(sb);
        pwqt->sb = NULL;
@@ -347,7 +352,6 @@ static void pwqr_task_release(struct pwqr_task *pwqt, bool from_notifier)
        hlist_del(&pwqt->link);
        spin_unlock(&b->lock);
 #endif
-       pwqt->notifier.ops = &pwqr_preempt_noop_ops;
 
        if (from_notifier) {
                /* When called from sched_{out,in}, it's not allowed to
@@ -370,7 +374,7 @@ static void pwqr_task_noop_sched_in(struct preempt_notifier *notifier, int cpu)
 }
 
 static void pwqr_task_noop_sched_out(struct preempt_notifier *notifier,
-                                   struct task_struct *next)
+                                    struct task_struct *next)
 {
 }
 
@@ -382,7 +386,6 @@ static void pwqr_task_blocked_sched_in(struct preempt_notifier *notifier, int cp
 
        if (unlikely(sb->state < 0)) {
                pwqr_task_detach(pwqt, sb);
-               pwqr_task_release(pwqt, true);
                return;
        }
 
@@ -401,7 +404,8 @@ static void pwqr_task_sched_out(struct preempt_notifier *notifier,
 
        if (unlikely(p->state & TASK_DEAD) || unlikely(sb->state < 0)) {
                pwqr_task_detach(pwqt, sb);
-               pwqr_task_release(pwqt, true);
+               if (p->state & TASK_DEAD)
+                       pwqr_task_release(pwqt, true);
                return;
        }
        if (p->state == 0 || (p->state & (__TASK_STOPPED | __TASK_TRACED)))
@@ -465,7 +469,7 @@ static unsigned int pwqr_poll(struct file *filp, poll_table *wait)
        poll_wait(filp, &sb->wqh_poll, wait);
 
        pwqr_sb_lock_irqsave(sb, flags);
-       if (sb->running > sb->concurrency)
+       if (sb->has_pollin)
                events |= POLLIN;
        if (sb->state < 0)
                events |= POLLHUP;
@@ -501,8 +505,10 @@ static inline ssize_t pwqr_sb_read(struct pwqr_sb *sb, int no_wait, u32 *cnt)
                remove_wait_queue(&sb->wqh_poll, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (likely(rc == 0))
+       if (likely(rc == 0)) {
                *cnt = sb->running - sb->concurrency;
+               sb->has_pollin = 0;
+       }
        spin_unlock_irq(&sb->wqh.lock);
 
        return rc;