From c7cabb18799090c303666bab78827bc64ca2594e Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 15 Jan 2012 08:51:17 +0100 Subject: [PATCH] Prepare code to plug the overcommit notification. Let the pwqr_sb have a state (instead of yes/no "dead" flag) being among: - DEAD - NONE (normal) - UC (undercommit) - OC (overcommit). In the last two modes a timer is fired. In the UC case, if the timer fires, we unpark a thread (if any, and if no overcommit unpark is pending) as before. In the OC case for now we do nothing. Signed-off-by: Pierre Habouzit --- kernel/pwqr.c | 67 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/kernel/pwqr.c b/kernel/pwqr.c index 7ce0700..8592a00 100644 --- a/kernel/pwqr.c +++ b/kernel/pwqr.c @@ -39,10 +39,17 @@ #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; @@ -63,7 +70,7 @@ struct pwqr_sb { unsigned parked; unsigned overcommit_wakes; - unsigned dead; + int state; }; struct pwqr_task { @@ -93,22 +100,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 +129,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); } @@ -281,7 +296,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 +311,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 +365,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); @@ -400,7 +415,7 @@ do_pwqr_wait(struct pwqr_sb *sb, struct pwqr_task *pwqt, } /* @ see */ - if (likely(!sb->dead)) { + if (likely(sb->state >= 0)) { DEFINE_WAIT(__wait); __wait.flags |= WQ_FLAG_EXCLUSIVE; @@ -429,7 +444,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 +462,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,9 +558,9 @@ 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) @@ -593,7 +608,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; } -- 2.20.1