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 <pierre.habouzit@intersec.com>
-#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)
+#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;
struct pwqr_task_bucket {
spinlock_t lock;
struct hlist_head tasks;
unsigned parked;
unsigned overcommit_wakes;
unsigned parked;
unsigned overcommit_wakes;
#define pwqr_sb_unlock_irqrestore(sb, flags) \
spin_unlock_irqrestore(&(sb)->wqh.lock, flags)
#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;
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)
}
static void pwqr_sb_timer_cb(unsigned long arg)
unsigned long flags;
pwqr_sb_lock_irqsave(sb, flags);
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->overcommit_wakes == 0)
wake_up_locked(&sb->wqh);
}
+ if (sb->running > sb->concurrency) {
+ /* See ../Documentation/pwqr.adoc */
+ }
pwqr_sb_unlock_irqrestore(sb, flags);
}
pwqr_sb_unlock_irqrestore(sb, flags);
}
struct pwqr_sb *sb = pwqt->sb;
unsigned long flags;
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;
pwqr_task_detach(pwqt, sb);
pwqr_task_release(pwqt, true);
return;
static void pwqr_task_sched_out(struct preempt_notifier *notifier,
struct task_struct *next)
{
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;
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;
pwqr_task_detach(pwqt, sb);
pwqr_task_release(pwqt, true);
return;
unsigned long flags;
pwqr_sb_lock_irqsave(sb, flags);
unsigned long flags;
pwqr_sb_lock_irqsave(sb, flags);
+ sb->state = PWQR_STATE_DEAD;
pwqr_sb_unlock_irqrestore(sb, flags);
wake_up_all(&sb->wqh);
pwqr_sb_put(sb);
pwqr_sb_unlock_irqrestore(sb, flags);
wake_up_all(&sb->wqh);
pwqr_sb_put(sb);
}
/* @ see <wait_event_interruptible_exclusive_locked_irq> */
}
/* @ see <wait_event_interruptible_exclusive_locked_irq> */
- if (likely(!sb->dead)) {
+ if (likely(sb->state >= 0)) {
DEFINE_WAIT(__wait);
__wait.flags |= WQ_FLAG_EXCLUSIVE;
DEFINE_WAIT(__wait);
__wait.flags |= WQ_FLAG_EXCLUSIVE;
break;
if (sb->running + sb->waiting < sb->concurrency)
break;
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);
__remove_wait_queue(&sb->wqh, &__wait);
__set_current_state(TASK_RUNNING);
- if (unlikely(sb->dead))
+ if (unlikely(sb->state < 0))
rc = -EBADFD;
pwqr_sb_unlock_irqrestore(sb, flags);
out:
rc = -EBADFD;
pwqr_sb_unlock_irqrestore(sb, flags);
out:
static long pwqr_ioctl(struct file *filp, unsigned command, unsigned long arg)
{
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 task_struct *task = current;
- struct pwqr_task *pwqt;
+ struct pwqr_task *pwqt;
int rc = 0;
if (sb->tgid != current->tgid)
int rc = 0;
if (sb->tgid != current->tgid)
- if (unlikely(sb->dead)) {
+ if (unlikely(sb->state < 0)) {
pwqr_task_detach(pwqt, pwqt->sb);
return -EBADFD;
}
pwqr_task_detach(pwqt, pwqt->sb);
return -EBADFD;
}