Page MenuHomeFreeBSD

D20669.id58723.diff
No OneTemporary

D20669.id58723.diff

Index: kern/kern_synch.c
===================================================================
--- kern/kern_synch.c
+++ kern/kern_synch.c
@@ -368,6 +368,19 @@
kick_proc0();
}
+void
+wakeup_any(void *ident)
+{
+ int wakeup_swapper;
+
+ sleepq_lock(ident);
+ wakeup_swapper = sleepq_signal(ident, SLEEPQ_SLEEP | SLEEPQ_UNFAIR,
+ 0, 0);
+ sleepq_release(ident);
+ if (wakeup_swapper)
+ kick_proc0();
+}
+
static void
kdb_switch(void)
{
Index: kern/subr_sleepqueue.c
===================================================================
--- kern/subr_sleepqueue.c
+++ kern/subr_sleepqueue.c
@@ -123,7 +123,7 @@
* c - sleep queue chain lock
*/
struct sleepqueue {
- TAILQ_HEAD(, thread) sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */
+ struct threadqueue sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */
u_int sq_blockedcnt[NR_SLEEPQS]; /* (c) N. of blocked threads. */
LIST_ENTRY(sleepqueue) sq_hash; /* (c) Chain and free list. */
LIST_HEAD(, sleepqueue) sq_free; /* (c) Free queues. */
@@ -889,12 +889,14 @@
}
/*
- * Find the highest priority thread sleeping on a wait channel and resume it.
+ * Find thread sleeping on a wait channel and resume it.
*/
int
sleepq_signal(void *wchan, int flags, int pri, int queue)
{
+ struct sleepqueue_chain *sc;
struct sleepqueue *sq;
+ struct threadqueue *head;
struct thread *td, *besttd;
int wakeup_swapper;
@@ -907,16 +909,33 @@
KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE),
("%s: mismatch between sleep/wakeup and cv_*", __func__));
- /*
- * Find the highest priority thread on the queue. If there is a
- * tie, use the thread that first appears in the queue as it has
- * been sleeping the longest since threads are always added to
- * the tail of sleep queues.
- */
- besttd = TAILQ_FIRST(&sq->sq_blocked[queue]);
- TAILQ_FOREACH(td, &sq->sq_blocked[queue], td_slpq) {
- if (td->td_priority < besttd->td_priority)
+ head = &sq->sq_blocked[queue];
+ if (flags & SLEEPQ_UNFAIR) {
+ /*
+ * Find the most recently sleeping thread, but try to
+ * skip threads still in process of context switch to
+ * avoid spinning on the thread lock.
+ */
+ sc = SC_LOOKUP(wchan);
+ besttd = TAILQ_LAST_FAST(head, thread, td_slpq);
+ while (besttd->td_lock != &sc->sc_lock) {
+ td = TAILQ_PREV_FAST(besttd, head, thread, td_slpq);
+ if (td == NULL)
+ break;
besttd = td;
+ }
+ } else {
+ /*
+ * Find the highest priority thread on the queue. If there
+ * is a tie, use the thread that first appears in the queue
+ * as it has been sleeping the longest since threads are
+ * always added to the tail of sleep queues.
+ */
+ besttd = td = TAILQ_FIRST(head);
+ while ((td = TAILQ_NEXT(td, td_slpq)) != NULL) {
+ if (td->td_priority < besttd->td_priority)
+ besttd = td;
+ }
}
MPASS(besttd != NULL);
thread_lock(besttd);
Index: kern/subr_taskqueue.c
===================================================================
--- kern/subr_taskqueue.c
+++ kern/subr_taskqueue.c
@@ -804,7 +804,7 @@
tqp = context;
tq = *tqp;
- wakeup_one(tq);
+ wakeup_any(tq);
}
TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, NULL,
Index: sys/queue.h
===================================================================
--- sys/queue.h
+++ sys/queue.h
@@ -829,6 +829,10 @@
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_PREV_FAST(elm, head, type, field) \
+ ((elm)->field.tqe_prev == &(head)->tqh_first ? NULL : \
+ __containerof((elm)->field.tqe_prev, QUEUE_TYPEOF(type), field.tqe_next))
+
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
Index: sys/sleepqueue.h
===================================================================
--- sys/sleepqueue.h
+++ sys/sleepqueue.h
@@ -84,6 +84,7 @@
#define SLEEPQ_SX 0x03 /* Used by an sx lock. */
#define SLEEPQ_LK 0x04 /* Used by a lockmgr. */
#define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */
+#define SLEEPQ_UNFAIR 0x200 /* Unfair wakeup order. */
void init_sleepqueues(void);
int sleepq_abort(struct thread *td, int intrval);
Index: sys/systm.h
===================================================================
--- sys/systm.h
+++ sys/systm.h
@@ -489,6 +489,7 @@
_sleep((chan), NULL, (pri), (wmesg), (bt), (pr), (flags))
void wakeup(void * chan);
void wakeup_one(void * chan);
+void wakeup_any(void * chan);
/*
* Common `struct cdev *' stuff are declared here to avoid #include poisoning

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 29, 10:20 AM (7 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32343048
Default Alt Text
D20669.id58723.diff (4 KB)

Event Timeline