Implement the reluctancy to unpark threads.
[~madcoder/pwqr.git] / kernel / pwqr.c
index 4d4c4cd..e4e3f58 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/timer.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 
@@ -38,6 +39,7 @@
 
 #include "pwqr.h"
 
 
 #include "pwqr.h"
 
+#define PWQR_UNPARK_DELAY      (HZ / 10)
 #define PWQR_HASH_BITS         5
 #define PWQR_HASH_SIZE         (1 << PWQR_HASH_BITS)
 
 #define PWQR_HASH_BITS         5
 #define PWQR_HASH_SIZE         (1 << PWQR_HASH_BITS)
 
@@ -49,6 +51,7 @@ struct pwqr_task_bucket {
 struct pwqr_sb {
        struct kref             kref;
        struct rcu_head         rcu;
 struct pwqr_sb {
        struct kref             kref;
        struct rcu_head         rcu;
+       struct timer_list       timer;
        wait_queue_head_t       wqh;
        pid_t                   tgid;
 
        wait_queue_head_t       wqh;
        pid_t                   tgid;
 
@@ -97,10 +100,9 @@ static inline void __pwqr_sb_update_state(struct pwqr_sb *sb, int running_delta)
 
        sb->running += running_delta;
        overcommit = sb->running + sb->waiting - sb->concurrency;
 
        sb->running += running_delta;
        overcommit = sb->running + sb->waiting - sb->concurrency;
-       if (overcommit == 0)
-               return;
-
-       if (overcommit > 0) {
+       if (overcommit == 0) {
+               /* do nothing */
+       } else if (overcommit > 0) {
                if (overcommit > sb->waiting) {
                        sb->quarantined += sb->waiting;
                        sb->waiting      = 0;
                if (overcommit > sb->waiting) {
                        sb->quarantined += sb->waiting;
                        sb->waiting      = 0;
@@ -118,9 +120,29 @@ static inline void __pwqr_sb_update_state(struct pwqr_sb *sb, int running_delta)
                        sb->waiting     += sb->quarantined;
                        sb->quarantined  = 0;
                } else if (sb->waiting == 0 && sb->parked) {
                        sb->waiting     += sb->quarantined;
                        sb->quarantined  = 0;
                } else if (sb->waiting == 0 && sb->parked) {
-                       wake_up_locked(&sb->wqh);
+                       if (!timer_pending(&sb->timer)) {
+                               mod_timer(&sb->timer, jiffies +
+                                         PWQR_UNPARK_DELAY);
+                       }
+                       return;
                }
        }
                }
        }
+
+       if (timer_pending(&sb->timer))
+               del_timer(&sb->timer);
+}
+
+static void pwqr_sb_timer_cb(unsigned long arg)
+{
+       struct pwqr_sb *sb = (struct pwqr_sb *)arg;
+       unsigned long flags;
+
+       pwqr_sb_lock_irqsave(sb, flags);
+       if (sb->waiting == 0 && sb->parked && sb->running < sb->concurrency) {
+               if (sb->overcommit_wakes == 0)
+                       wake_up_locked(&sb->wqh);
+       }
+       pwqr_sb_unlock_irqrestore(sb, flags);
 }
 
 static struct pwqr_sb *pwqr_sb_create(void)
 }
 
 static struct pwqr_sb *pwqr_sb_create(void)
@@ -135,6 +157,9 @@ static struct pwqr_sb *pwqr_sb_create(void)
        init_waitqueue_head(&sb->wqh);
        sb->tgid        = current->tgid;
        sb->concurrency = num_online_cpus();
        init_waitqueue_head(&sb->wqh);
        sb->tgid        = current->tgid;
        sb->concurrency = num_online_cpus();
+       init_timer(&sb->timer);
+       sb->timer.function = pwqr_sb_timer_cb;
+       sb->timer.data     = (unsigned long)sb;
 
        __module_get(THIS_MODULE);
        return sb;
 
        __module_get(THIS_MODULE);
        return sb;
@@ -156,6 +181,7 @@ static void pwqr_sb_release(struct kref *kref)
 {
        struct pwqr_sb *sb = container_of(kref, struct pwqr_sb, kref);
 
 {
        struct pwqr_sb *sb = container_of(kref, struct pwqr_sb, kref);
 
+       del_timer_sync(&sb->timer);
        call_rcu(&sb->rcu, pwqr_sb_finalize);
 }
 static inline void pwqr_sb_put(struct pwqr_sb *sb)
        call_rcu(&sb->rcu, pwqr_sb_finalize);
 }
 static inline void pwqr_sb_put(struct pwqr_sb *sb)