do not forbid other processes to use the pwqr fd.
[~madcoder/pwqr.git] / kernel / pwqr.c
index 7ce0700..a6ff8e5 100644 (file)
 
 #include "pwqr.h"
 
-#define PWQR_UNPARK_DELAY      (HZ / 10)
 #define PWQR_HASH_BITS         5
 #define PWQR_HASH_SIZE         (1 << PWQR_HASH_BITS)
 
+#define PWQR_UC_DELAY          (HZ / 10)
+#define PWQR_OC_DELAY          (HZ / 20)
+
+#define PWQR_STATE_NONE                0
+#define PWQR_STATE_UC          1
+#define PWQR_STATE_OC          2
+#define PWQR_STATE_DEAD                (-1)
+
 struct pwqr_task_bucket {
        spinlock_t              lock;
        struct hlist_head       tasks;
@@ -53,7 +60,6 @@ struct pwqr_sb {
        struct rcu_head         rcu;
        struct timer_list       timer;
        wait_queue_head_t       wqh;
-       pid_t                   tgid;
 
        unsigned                concurrency;
        unsigned                registered;
@@ -63,7 +69,7 @@ struct pwqr_sb {
        unsigned                parked;
        unsigned                overcommit_wakes;
 
-       unsigned                dead;
+       int                     state;
 };
 
 struct pwqr_task {
@@ -93,22 +99,27 @@ static struct preempt_ops   pwqr_preempt_noop_ops;
 #define pwqr_sb_unlock_irqrestore(sb, flags) \
        spin_unlock_irqrestore(&(sb)->wqh.lock, flags)
 
+static inline void pwqr_arm_timer(struct pwqr_sb *sb, int how, int delay)
+{
+       if (timer_pending(&sb->timer) && sb->state == how)
+               return;
+       mod_timer(&sb->timer, jiffies + delay);
+       sb->state = how;
+}
+
 static inline void __pwqr_sb_update_state(struct pwqr_sb *sb, int running_delta)
 {
        sb->running += running_delta;
-       if (sb->running > sb->concurrency) {
-               /* TODO see ../Documentation/pwqr.adoc */
-       } else if (sb->running == sb->concurrency) {
-               /* do nothing */
-       } else if (sb->waiting == 0 && sb->parked) {
-               if (!timer_pending(&sb->timer)) {
-                       mod_timer(&sb->timer, jiffies + PWQR_UNPARK_DELAY);
-               }
-               return;
-       }
 
-       if (timer_pending(&sb->timer))
-               del_timer(&sb->timer);
+       if (sb->running < sb->concurrency && sb->waiting == 0 && sb->parked) {
+               pwqr_arm_timer(sb, PWQR_STATE_UC, PWQR_UC_DELAY);
+       } else if (sb->running > sb->concurrency) {
+               pwqr_arm_timer(sb, PWQR_STATE_OC, PWQR_OC_DELAY);
+       } else {
+               sb->state = PWQR_STATE_NONE;
+               if (!timer_pending(&sb->timer))
+                       del_timer(&sb->timer);
+       }
 }
 
 static void pwqr_sb_timer_cb(unsigned long arg)
@@ -117,10 +128,13 @@ static void pwqr_sb_timer_cb(unsigned long arg)
        unsigned long flags;
 
        pwqr_sb_lock_irqsave(sb, flags);
-       if (sb->waiting == 0 && sb->parked && sb->running < sb->concurrency) {
+       if (sb->running < sb->concurrency && sb->waiting == 0 && sb->parked) {
                if (sb->overcommit_wakes == 0)
                        wake_up_locked(&sb->wqh);
        }
+       if (sb->running > sb->concurrency) {
+               /* See ../Documentation/pwqr.adoc */
+       }
        pwqr_sb_unlock_irqrestore(sb, flags);
 }
 
@@ -134,8 +148,7 @@ static struct pwqr_sb *pwqr_sb_create(void)
 
        kref_init(&sb->kref);
        init_waitqueue_head(&sb->wqh);
-       sb->tgid        = current->tgid;
-       sb->concurrency = num_online_cpus();
+       sb->concurrency    = num_online_cpus();
        init_timer(&sb->timer);
        sb->timer.function = pwqr_sb_timer_cb;
        sb->timer.data     = (unsigned long)sb;
@@ -281,7 +294,7 @@ static void pwqr_task_blocked_sched_in(struct preempt_notifier *notifier, int cp
        struct pwqr_sb   *sb   = pwqt->sb;
        unsigned long flags;
 
-       if (unlikely(sb->dead)) {
+       if (unlikely(sb->state < 0)) {
                pwqr_task_detach(pwqt, sb);
                pwqr_task_release(pwqt, true);
                return;
@@ -296,11 +309,11 @@ static void pwqr_task_blocked_sched_in(struct preempt_notifier *notifier, int cp
 static void pwqr_task_sched_out(struct preempt_notifier *notifier,
                               struct task_struct *next)
 {
-       struct pwqr_task    *pwqt = container_of(notifier, struct pwqr_task, notifier);
-       struct pwqr_sb      *sb   = pwqt->sb;
+       struct pwqr_task   *pwqt = container_of(notifier, struct pwqr_task, notifier);
+       struct pwqr_sb     *sb   = pwqt->sb;
        struct task_struct *p    = pwqt->task;
 
-       if (unlikely(p->state & TASK_DEAD) || unlikely(sb->dead)) {
+       if (unlikely(p->state & TASK_DEAD) || unlikely(sb->state < 0)) {
                pwqr_task_detach(pwqt, sb);
                pwqr_task_release(pwqt, true);
                return;
@@ -350,7 +363,7 @@ static int pwqr_release(struct inode *inode, struct file *filp)
        unsigned long flags;
 
        pwqr_sb_lock_irqsave(sb, flags);
-       sb->dead = true;
+       sb->state = PWQR_STATE_DEAD;
        pwqr_sb_unlock_irqrestore(sb, flags);
        wake_up_all(&sb->wqh);
        pwqr_sb_put(sb);
@@ -359,7 +372,7 @@ static int pwqr_release(struct inode *inode, struct file *filp)
 
 static long
 do_pwqr_wait(struct pwqr_sb *sb, struct pwqr_task *pwqt,
-           int is_wait, struct pwqr_ioc_wait __user *arg)
+            int is_wait, struct pwqr_ioc_wait __user *arg)
 {
        unsigned long flags;
        struct pwqr_ioc_wait wait;
@@ -400,7 +413,7 @@ do_pwqr_wait(struct pwqr_sb *sb, struct pwqr_task *pwqt,
        }
 
        /* @ see <wait_event_interruptible_exclusive_locked_irq> */
-       if (likely(!sb->dead)) {
+       if (likely(sb->state >= 0)) {
                DEFINE_WAIT(__wait);
 
                __wait.flags |= WQ_FLAG_EXCLUSIVE;
@@ -429,7 +442,7 @@ do_pwqr_wait(struct pwqr_sb *sb, struct pwqr_task *pwqt,
                                break;
                        if (sb->running + sb->waiting < sb->concurrency)
                                break;
-               } while (likely(!sb->dead));
+               } while (likely(sb->state >= 0));
 
                __remove_wait_queue(&sb->wqh, &__wait);
                __set_current_state(TASK_RUNNING);
@@ -447,7 +460,7 @@ do_pwqr_wait(struct pwqr_sb *sb, struct pwqr_task *pwqt,
        }
 
 out_unlock:
-       if (unlikely(sb->dead))
+       if (unlikely(sb->state < 0))
                rc = -EBADFD;
        pwqr_sb_unlock_irqrestore(sb, flags);
 out:
@@ -543,14 +556,11 @@ static long do_pwqr_wake(struct pwqr_sb *sb, int oc, int count)
 
 static long pwqr_ioctl(struct file *filp, unsigned command, unsigned long arg)
 {
-       struct pwqr_sb      *sb   = filp->private_data;
+       struct pwqr_sb     *sb   = filp->private_data;
        struct task_struct *task = current;
-       struct pwqr_task    *pwqt;
+       struct pwqr_task   *pwqt;
        int rc = 0;
 
-       if (sb->tgid != current->tgid)
-               return -EBADFD;
-
        switch (command) {
        case PWQR_GET_CONC:
                return sb->concurrency;
@@ -593,7 +603,7 @@ static long pwqr_ioctl(struct file *filp, unsigned command, unsigned long arg)
                break;
        }
 
-       if (unlikely(sb->dead)) {
+       if (unlikely(sb->state < 0)) {
                pwqr_task_detach(pwqt, pwqt->sb);
                return -EBADFD;
        }