diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index bfc941ee3326..b132da772694 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -496,25 +497,19 @@ taskqueue_swi_giant_run(void *dummy) taskqueue_run(taskqueue_swi_giant); } -int -taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, - const char *name, ...) +static int +_taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, + cpuset_t *mask, const char *ktname) { - va_list ap; struct thread *td; struct taskqueue *tq; int i, error; - char ktname[MAXCOMLEN + 1]; if (count <= 0) return (EINVAL); tq = *tqp; - va_start(ap, name); - vsnprintf(ktname, sizeof(ktname), name, ap); - va_end(ap); - tq->tq_threads = malloc(sizeof(struct thread *) * count, M_TASKQUEUE, M_NOWAIT | M_ZERO); if (tq->tq_threads == NULL) { @@ -542,6 +537,19 @@ taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, if (tq->tq_threads[i] == NULL) continue; td = tq->tq_threads[i]; + if (mask) { + error = cpuset_setthread(curthread->td_tid, mask); + /* + * Failing to pin is rarely an actual fatal error; + * it'll just affect performance. + */ + if (error) + printf("%s: curthread=%llu: can't pin; " + "error=%d\n", + __func__, + (unsigned long long) td->td_tid, + error); + } thread_lock(td); sched_prio(td, pri); sched_add(td, SRQ_BORING); @@ -551,6 +559,45 @@ taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, return (0); } +int +taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, + const char *name, ...) +{ + char ktname[MAXCOMLEN + 1]; + va_list ap; + + va_start(ap, name); + vsnprintf(ktname, sizeof(ktname), name, ap); + va_end(ap); + + return (_taskqueue_start_threads(tqp, count, pri, NULL, ktname)); +} + +int +taskqueue_start_threads_pinned(struct taskqueue **tqp, int count, int pri, + int cpu_id, const char *name, ...) +{ + char ktname[MAXCOMLEN + 1]; + va_list ap; + cpuset_t mask; + + va_start(ap, name); + vsnprintf(ktname, sizeof(ktname), name, ap); + va_end(ap); + + /* + * In case someone passes in NOCPU, just fall back to the + * default behaviour of "don't pin". + */ + if (cpu_id != NOCPU) { + CPU_ZERO(&mask); + CPU_SET(cpu_id, &mask); + } + + return (_taskqueue_start_threads(tqp, count, pri, + cpu_id == NOCPU ? NULL : &mask, ktname)); +} + static inline void taskqueue_run_callback(struct taskqueue *tq, enum taskqueue_callback_type cb_type) diff --git a/sys/sys/taskqueue.h b/sys/sys/taskqueue.h index 326eb91f59df..bf23ac176114 100644 --- a/sys/sys/taskqueue.h +++ b/sys/sys/taskqueue.h @@ -71,6 +71,10 @@ struct taskqueue *taskqueue_create(const char *name, int mflags, void *context); int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, const char *name, ...) __printflike(4, 5); +int taskqueue_start_threads_pinned(struct taskqueue **tqp, int count, + int pri, int cpu_id, const char *name, + ...) __printflike(5, 6); + int taskqueue_enqueue(struct taskqueue *queue, struct task *task); int taskqueue_enqueue_timeout(struct taskqueue *queue, struct timeout_task *timeout_task, int ticks);