Commit e995d512 authored by Jens Axboe's avatar Jens Axboe

io-wq: briefly spin for new work after finishing work

To avoid going to sleep only to get woken shortly thereafter, spin
briefly for new work upon completion of work.
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 506d95ff
...@@ -491,26 +491,46 @@ static void io_worker_handle_work(struct io_worker *worker) ...@@ -491,26 +491,46 @@ static void io_worker_handle_work(struct io_worker *worker)
} while (1); } while (1);
} }
static inline void io_worker_spin_for_work(struct io_wqe *wqe)
{
int i = 0;
while (++i < 1000) {
if (io_wqe_run_queue(wqe))
break;
if (need_resched())
break;
cpu_relax();
}
}
static int io_wqe_worker(void *data) static int io_wqe_worker(void *data)
{ {
struct io_worker *worker = data; struct io_worker *worker = data;
struct io_wqe *wqe = worker->wqe; struct io_wqe *wqe = worker->wqe;
struct io_wq *wq = wqe->wq; struct io_wq *wq = wqe->wq;
bool did_work;
io_worker_start(wqe, worker); io_worker_start(wqe, worker);
did_work = false;
while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) { while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
loop:
if (did_work)
io_worker_spin_for_work(wqe);
spin_lock_irq(&wqe->lock); spin_lock_irq(&wqe->lock);
if (io_wqe_run_queue(wqe)) { if (io_wqe_run_queue(wqe)) {
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
io_worker_handle_work(worker); io_worker_handle_work(worker);
continue; did_work = true;
goto loop;
} }
did_work = false;
/* drops the lock on success, retry */ /* drops the lock on success, retry */
if (__io_worker_idle(wqe, worker)) { if (__io_worker_idle(wqe, worker)) {
__release(&wqe->lock); __release(&wqe->lock);
continue; goto loop;
} }
spin_unlock_irq(&wqe->lock); spin_unlock_irq(&wqe->lock);
if (signal_pending(current)) if (signal_pending(current))
......
...@@ -35,7 +35,8 @@ static inline void wq_list_add_tail(struct io_wq_work_node *node, ...@@ -35,7 +35,8 @@ static inline void wq_list_add_tail(struct io_wq_work_node *node,
struct io_wq_work_list *list) struct io_wq_work_list *list)
{ {
if (!list->first) { if (!list->first) {
list->first = list->last = node; list->last = node;
WRITE_ONCE(list->first, node);
} else { } else {
list->last->next = node; list->last->next = node;
list->last = node; list->last = node;
...@@ -47,7 +48,7 @@ static inline void wq_node_del(struct io_wq_work_list *list, ...@@ -47,7 +48,7 @@ static inline void wq_node_del(struct io_wq_work_list *list,
struct io_wq_work_node *prev) struct io_wq_work_node *prev)
{ {
if (node == list->first) if (node == list->first)
list->first = node->next; WRITE_ONCE(list->first, node->next);
if (node == list->last) if (node == list->last)
list->last = prev; list->last = prev;
if (prev) if (prev)
...@@ -58,7 +59,7 @@ static inline void wq_node_del(struct io_wq_work_list *list, ...@@ -58,7 +59,7 @@ static inline void wq_node_del(struct io_wq_work_list *list,
#define wq_list_for_each(pos, prv, head) \ #define wq_list_for_each(pos, prv, head) \
for (pos = (head)->first, prv = NULL; pos; prv = pos, pos = (pos)->next) for (pos = (head)->first, prv = NULL; pos; prv = pos, pos = (pos)->next)
#define wq_list_empty(list) ((list)->first == NULL) #define wq_list_empty(list) (READ_ONCE((list)->first) == NULL)
#define INIT_WQ_LIST(list) do { \ #define INIT_WQ_LIST(list) do { \
(list)->first = NULL; \ (list)->first = NULL; \
(list)->last = NULL; \ (list)->last = NULL; \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment