#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 "pwqr.h"
+#define PWQR_UNPARK_DELAY (HZ / 10)
#define PWQR_HASH_BITS 5
#define PWQR_HASH_SIZE (1 << PWQR_HASH_BITS)
struct pwqr_sb {
struct kref kref;
struct rcu_head rcu;
+ struct timer_list timer;
wait_queue_head_t wqh;
pid_t tgid;
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;
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)
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;
{
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)
} else {
/*
* This codepath deserves an explanation: when the thread is
- * quarantined, for is, really, it's already "parked". Though
+ * quarantined, for us, really, it's already "parked". Though
* userland doesn't know about, so wake as many threads as
* userlands would have liked to, and let the wakeup tell
* userland those should be parked.