1*2ee1bbb5Smvs /* $OpenBSD: kern_task.c,v 1.36 2025/01/13 03:21:10 mvs Exp $ */ 2e72c42a1Sdlg 3e72c42a1Sdlg /* 4e72c42a1Sdlg * Copyright (c) 2013 David Gwynne <dlg@openbsd.org> 5e72c42a1Sdlg * 6e72c42a1Sdlg * Permission to use, copy, modify, and distribute this software for any 7e72c42a1Sdlg * purpose with or without fee is hereby granted, provided that the above 8e72c42a1Sdlg * copyright notice and this permission notice appear in all copies. 9e72c42a1Sdlg * 10e72c42a1Sdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11e72c42a1Sdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12e72c42a1Sdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13e72c42a1Sdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14e72c42a1Sdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15e72c42a1Sdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16e72c42a1Sdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17e72c42a1Sdlg */ 18e72c42a1Sdlg 19e72c42a1Sdlg #include <sys/param.h> 20e72c42a1Sdlg #include <sys/systm.h> 21e72c42a1Sdlg #include <sys/malloc.h> 22e72c42a1Sdlg #include <sys/mutex.h> 23e72c42a1Sdlg #include <sys/kthread.h> 24e72c42a1Sdlg #include <sys/task.h> 256f1a6781Sdlg #include <sys/proc.h> 2660aa962eSdlg #include <sys/witness.h> 2760aa962eSdlg 288430bc4bSanton #include "kcov.h" 298430bc4bSanton #if NKCOV > 0 308430bc4bSanton #include <sys/kcov.h> 318430bc4bSanton #endif 328430bc4bSanton 3360aa962eSdlg #ifdef WITNESS 3460aa962eSdlg 3560aa962eSdlg static struct lock_type taskq_lock_type = { 3660aa962eSdlg .lt_name = "taskq" 3760aa962eSdlg }; 3860aa962eSdlg 3960aa962eSdlg #define TASKQ_LOCK_FLAGS LO_WITNESS | LO_INITIALIZED | LO_SLEEPABLE | \ 4060aa962eSdlg (LO_CLASS_RWLOCK << LO_CLASSSHIFT) 4160aa962eSdlg 4260aa962eSdlg #endif /* WITNESS */ 43e72c42a1Sdlg 44ba614123Sdlg struct taskq_thread { 45ba614123Sdlg SLIST_ENTRY(taskq_thread) 46ba614123Sdlg tt_entry; 47ba614123Sdlg struct proc *tt_thread; 48ba614123Sdlg }; 49ba614123Sdlg SLIST_HEAD(taskq_threads, taskq_thread); 50ba614123Sdlg 51e72c42a1Sdlg struct taskq { 52e72c42a1Sdlg enum { 53e72c42a1Sdlg TQ_S_CREATED, 54e72c42a1Sdlg TQ_S_RUNNING, 55e72c42a1Sdlg TQ_S_DESTROYED 56e72c42a1Sdlg } tq_state; 573c9f708dSdlg unsigned int tq_running; 583c9f708dSdlg unsigned int tq_nthreads; 5979ea9c08Sdlg unsigned int tq_flags; 60e72c42a1Sdlg const char *tq_name; 61e72c42a1Sdlg 62e72c42a1Sdlg struct mutex tq_mtx; 63d3bdd90fSdlg struct task_list tq_worklist; 64ba614123Sdlg 65ba614123Sdlg struct taskq_threads tq_threads; 66ba614123Sdlg unsigned int tq_barriers; 67ba614123Sdlg unsigned int tq_bgen; 68ba614123Sdlg unsigned int tq_bthreads; 69ba614123Sdlg 7060aa962eSdlg #ifdef WITNESS 7160aa962eSdlg struct lock_object tq_lock_object; 7260aa962eSdlg #endif 73e72c42a1Sdlg }; 74e72c42a1Sdlg 7560aa962eSdlg static const char taskq_sys_name[] = "systq"; 7660aa962eSdlg 77e72c42a1Sdlg struct taskq taskq_sys = { 78ba614123Sdlg .tq_state = TQ_S_CREATED, 79ba614123Sdlg .tq_running = 0, 80ba614123Sdlg .tq_nthreads = 1, 81ba614123Sdlg .tq_flags = 0, 82ba614123Sdlg .tq_name = taskq_sys_name, 83ba614123Sdlg .tq_mtx = MUTEX_INITIALIZER_FLAGS(IPL_HIGH, 84ba614123Sdlg taskq_sys_name, 0), 85ba614123Sdlg .tq_worklist = TAILQ_HEAD_INITIALIZER(taskq_sys.tq_worklist), 86ba614123Sdlg 87ba614123Sdlg .tq_threads = SLIST_HEAD_INITIALIZER(taskq_sys.tq_threads), 88ba614123Sdlg .tq_barriers = 0, 89ba614123Sdlg .tq_bgen = 0, 90ba614123Sdlg .tq_bthreads = 0, 91ba614123Sdlg 9260aa962eSdlg #ifdef WITNESS 93ba614123Sdlg .tq_lock_object = { 9460aa962eSdlg .lo_name = taskq_sys_name, 9560aa962eSdlg .lo_flags = TASKQ_LOCK_FLAGS, 9660aa962eSdlg }, 9760aa962eSdlg #endif 98e72c42a1Sdlg }; 99e72c42a1Sdlg 10060aa962eSdlg static const char taskq_sys_mp_name[] = "systqmp"; 10160aa962eSdlg 10253eebcffSblambert struct taskq taskq_sys_mp = { 103ba614123Sdlg .tq_state = TQ_S_CREATED, 104ba614123Sdlg .tq_running = 0, 105ba614123Sdlg .tq_nthreads = 1, 106ba614123Sdlg .tq_flags = TASKQ_MPSAFE, 107ba614123Sdlg .tq_name = taskq_sys_mp_name, 108ba614123Sdlg .tq_mtx = MUTEX_INITIALIZER_FLAGS(IPL_HIGH, 109ba614123Sdlg taskq_sys_mp_name, 0), 110ba614123Sdlg .tq_worklist = TAILQ_HEAD_INITIALIZER(taskq_sys_mp.tq_worklist), 111ba614123Sdlg 112ba614123Sdlg .tq_threads = SLIST_HEAD_INITIALIZER(taskq_sys_mp.tq_threads), 113ba614123Sdlg .tq_barriers = 0, 114ba614123Sdlg .tq_bgen = 0, 115ba614123Sdlg .tq_bthreads = 0, 116ba614123Sdlg 11760aa962eSdlg #ifdef WITNESS 118ba614123Sdlg .tq_lock_object = { 11960aa962eSdlg .lo_name = taskq_sys_mp_name, 12060aa962eSdlg .lo_flags = TASKQ_LOCK_FLAGS, 12160aa962eSdlg }, 12260aa962eSdlg #endif 12353eebcffSblambert }; 12453eebcffSblambert 1251c81877cSdlg struct taskq *const systq = &taskq_sys; 12653eebcffSblambert struct taskq *const systqmp = &taskq_sys_mp; 1271c81877cSdlg 128e72c42a1Sdlg void taskq_init(void); /* called in init_main.c */ 129e72c42a1Sdlg void taskq_create_thread(void *); 1306f1a6781Sdlg void taskq_barrier_task(void *); 131f07ea34cSdlg int taskq_next_work(struct taskq *, struct task *); 132e72c42a1Sdlg void taskq_thread(void *); 133e72c42a1Sdlg 134e72c42a1Sdlg void 135e72c42a1Sdlg taskq_init(void) 136e72c42a1Sdlg { 13760aa962eSdlg WITNESS_INIT(&systq->tq_lock_object, &taskq_lock_type); 1381c81877cSdlg kthread_create_deferred(taskq_create_thread, systq); 13960aa962eSdlg WITNESS_INIT(&systqmp->tq_lock_object, &taskq_lock_type); 14053eebcffSblambert kthread_create_deferred(taskq_create_thread, systqmp); 141e72c42a1Sdlg } 142e72c42a1Sdlg 143e72c42a1Sdlg struct taskq * 14479ea9c08Sdlg taskq_create(const char *name, unsigned int nthreads, int ipl, 14579ea9c08Sdlg unsigned int flags) 146e72c42a1Sdlg { 147e72c42a1Sdlg struct taskq *tq; 148e72c42a1Sdlg 1490bfe7560Sdlg tq = malloc(sizeof(*tq), M_DEVBUF, M_WAITOK); 150e72c42a1Sdlg if (tq == NULL) 151e72c42a1Sdlg return (NULL); 152e72c42a1Sdlg 153e72c42a1Sdlg tq->tq_state = TQ_S_CREATED; 154e72c42a1Sdlg tq->tq_running = 0; 155e72c42a1Sdlg tq->tq_nthreads = nthreads; 156e72c42a1Sdlg tq->tq_name = name; 15779ea9c08Sdlg tq->tq_flags = flags; 1584e29e7adSkettenis 159bd1acdabSvisa mtx_init_flags(&tq->tq_mtx, ipl, name, 0); 160e72c42a1Sdlg TAILQ_INIT(&tq->tq_worklist); 161e72c42a1Sdlg 162ba614123Sdlg SLIST_INIT(&tq->tq_threads); 163ba614123Sdlg tq->tq_barriers = 0; 164ba614123Sdlg tq->tq_bgen = 0; 165ba614123Sdlg tq->tq_bthreads = 0; 166ba614123Sdlg 16760aa962eSdlg #ifdef WITNESS 16860aa962eSdlg memset(&tq->tq_lock_object, 0, sizeof(tq->tq_lock_object)); 16960aa962eSdlg tq->tq_lock_object.lo_name = name; 17060aa962eSdlg tq->tq_lock_object.lo_flags = TASKQ_LOCK_FLAGS; 17160aa962eSdlg witness_init(&tq->tq_lock_object, &taskq_lock_type); 17260aa962eSdlg #endif 17360aa962eSdlg 174e72c42a1Sdlg /* try to create a thread to guarantee that tasks will be serviced */ 175e72c42a1Sdlg kthread_create_deferred(taskq_create_thread, tq); 176e72c42a1Sdlg 177e72c42a1Sdlg return (tq); 178e72c42a1Sdlg } 179e72c42a1Sdlg 180e72c42a1Sdlg void 181e72c42a1Sdlg taskq_destroy(struct taskq *tq) 182e72c42a1Sdlg { 183e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 184e72c42a1Sdlg switch (tq->tq_state) { 185e72c42a1Sdlg case TQ_S_CREATED: 186e72c42a1Sdlg /* tq is still referenced by taskq_create_thread */ 187e72c42a1Sdlg tq->tq_state = TQ_S_DESTROYED; 188e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 189e72c42a1Sdlg return; 190e72c42a1Sdlg 191e72c42a1Sdlg case TQ_S_RUNNING: 192e72c42a1Sdlg tq->tq_state = TQ_S_DESTROYED; 193e72c42a1Sdlg break; 194e72c42a1Sdlg 195e72c42a1Sdlg default: 196e72c42a1Sdlg panic("unexpected %s tq state %u", tq->tq_name, tq->tq_state); 197e72c42a1Sdlg } 198e72c42a1Sdlg 199e72c42a1Sdlg while (tq->tq_running > 0) { 200e72c42a1Sdlg wakeup(tq); 201babb761dSmpi msleep_nsec(&tq->tq_running, &tq->tq_mtx, PWAIT, "tqdestroy", 202babb761dSmpi INFSLP); 203e72c42a1Sdlg } 204e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 205e72c42a1Sdlg 206fc62de09Stedu free(tq, M_DEVBUF, sizeof(*tq)); 207e72c42a1Sdlg } 208e72c42a1Sdlg 209e72c42a1Sdlg void 210e72c42a1Sdlg taskq_create_thread(void *arg) 211e72c42a1Sdlg { 212e72c42a1Sdlg struct taskq *tq = arg; 213e72c42a1Sdlg int rv; 214e72c42a1Sdlg 215e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 216e72c42a1Sdlg 217e72c42a1Sdlg switch (tq->tq_state) { 218e72c42a1Sdlg case TQ_S_DESTROYED: 219e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 220fc62de09Stedu free(tq, M_DEVBUF, sizeof(*tq)); 221e72c42a1Sdlg return; 222e72c42a1Sdlg 223e72c42a1Sdlg case TQ_S_CREATED: 224e72c42a1Sdlg tq->tq_state = TQ_S_RUNNING; 225e72c42a1Sdlg break; 226e72c42a1Sdlg 227e72c42a1Sdlg default: 228e72c42a1Sdlg panic("unexpected %s tq state %d", tq->tq_name, tq->tq_state); 229e72c42a1Sdlg } 230e72c42a1Sdlg 231e72c42a1Sdlg do { 232e72c42a1Sdlg tq->tq_running++; 233e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 234e72c42a1Sdlg 2352d257949Sderaadt rv = kthread_create(taskq_thread, tq, NULL, tq->tq_name); 236e72c42a1Sdlg 237e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 238e72c42a1Sdlg if (rv != 0) { 239e72c42a1Sdlg printf("unable to create thread for \"%s\" taskq\n", 240e72c42a1Sdlg tq->tq_name); 241e72c42a1Sdlg 242e72c42a1Sdlg tq->tq_running--; 243e72c42a1Sdlg /* could have been destroyed during kthread_create */ 244e72c42a1Sdlg if (tq->tq_state == TQ_S_DESTROYED && 245e72c42a1Sdlg tq->tq_running == 0) 246e72c42a1Sdlg wakeup_one(&tq->tq_running); 247e72c42a1Sdlg break; 248e72c42a1Sdlg } 249e72c42a1Sdlg } while (tq->tq_running < tq->tq_nthreads); 250e72c42a1Sdlg 251e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 252e72c42a1Sdlg } 253e72c42a1Sdlg 254e72c42a1Sdlg void 2556f1a6781Sdlg taskq_barrier_task(void *p) 2566f1a6781Sdlg { 257ba614123Sdlg struct taskq *tq = p; 258ba614123Sdlg unsigned int gen; 259ba614123Sdlg 260ba614123Sdlg mtx_enter(&tq->tq_mtx); 261ba614123Sdlg tq->tq_bthreads++; 262ba614123Sdlg wakeup(&tq->tq_bthreads); 263ba614123Sdlg 264ba614123Sdlg gen = tq->tq_bgen; 265ba614123Sdlg do { 266ba614123Sdlg msleep_nsec(&tq->tq_bgen, &tq->tq_mtx, 267ba614123Sdlg PWAIT, "tqbarend", INFSLP); 268ba614123Sdlg } while (gen == tq->tq_bgen); 269ba614123Sdlg mtx_leave(&tq->tq_mtx); 270ba614123Sdlg } 271ba614123Sdlg 272ba614123Sdlg static void 273ba614123Sdlg taskq_do_barrier(struct taskq *tq) 274ba614123Sdlg { 275ba614123Sdlg struct task t = TASK_INITIALIZER(taskq_barrier_task, tq); 276ba614123Sdlg struct proc *thread = curproc; 277ba614123Sdlg struct taskq_thread *tt; 278ba614123Sdlg 279ba614123Sdlg mtx_enter(&tq->tq_mtx); 280ba614123Sdlg tq->tq_barriers++; 281ba614123Sdlg 282ba614123Sdlg /* is the barrier being run from a task inside the taskq? */ 283ba614123Sdlg SLIST_FOREACH(tt, &tq->tq_threads, tt_entry) { 284ba614123Sdlg if (tt->tt_thread == thread) { 285ba614123Sdlg tq->tq_bthreads++; 286ba614123Sdlg wakeup(&tq->tq_bthreads); 287ba614123Sdlg break; 288ba614123Sdlg } 289ba614123Sdlg } 290ba614123Sdlg 291ba614123Sdlg while (tq->tq_bthreads < tq->tq_nthreads) { 292ba614123Sdlg /* shove the task into the queue for a worker to pick up */ 293ba614123Sdlg SET(t.t_flags, TASK_ONQUEUE); 2941330a2b3Sdlg TAILQ_INSERT_TAIL(&tq->tq_worklist, &t, t_entry); 295ba614123Sdlg wakeup_one(tq); 296ba614123Sdlg 297ba614123Sdlg msleep_nsec(&tq->tq_bthreads, &tq->tq_mtx, 298ba614123Sdlg PWAIT, "tqbar", INFSLP); 299ba614123Sdlg 300ba614123Sdlg /* 301c3947ab6Sdlg * another thread running a barrier might have 302ba614123Sdlg * done this work for us. 303ba614123Sdlg */ 304ba614123Sdlg if (ISSET(t.t_flags, TASK_ONQUEUE)) 305ba614123Sdlg TAILQ_REMOVE(&tq->tq_worklist, &t, t_entry); 306ba614123Sdlg } 307ba614123Sdlg 308ba614123Sdlg if (--tq->tq_barriers == 0) { 309ba614123Sdlg /* we're the last one out */ 310ba614123Sdlg tq->tq_bgen++; 311ba614123Sdlg wakeup(&tq->tq_bgen); 312ba614123Sdlg tq->tq_bthreads = 0; 313ba614123Sdlg } else { 314ba614123Sdlg unsigned int gen = tq->tq_bgen; 315ba614123Sdlg do { 316ba614123Sdlg msleep_nsec(&tq->tq_bgen, &tq->tq_mtx, 317ba614123Sdlg PWAIT, "tqbarwait", INFSLP); 318ba614123Sdlg } while (gen == tq->tq_bgen); 319ba614123Sdlg } 320ba614123Sdlg mtx_leave(&tq->tq_mtx); 321ba614123Sdlg } 322ba614123Sdlg 323ba614123Sdlg void 324ba614123Sdlg taskq_barrier(struct taskq *tq) 325ba614123Sdlg { 326ba614123Sdlg WITNESS_CHECKORDER(&tq->tq_lock_object, LOP_NEWORDER, NULL); 327ba614123Sdlg 328ba614123Sdlg taskq_do_barrier(tq); 329ba614123Sdlg } 330ba614123Sdlg 331ba614123Sdlg void 332ba614123Sdlg taskq_del_barrier(struct taskq *tq, struct task *t) 333ba614123Sdlg { 334ba614123Sdlg WITNESS_CHECKORDER(&tq->tq_lock_object, LOP_NEWORDER, NULL); 335ba614123Sdlg 336*2ee1bbb5Smvs task_del(tq, t); 337ba614123Sdlg taskq_do_barrier(tq); 3386f1a6781Sdlg } 3396f1a6781Sdlg 3406f1a6781Sdlg void 341e4195480Sdlg task_set(struct task *t, void (*fn)(void *), void *arg) 342e72c42a1Sdlg { 343e72c42a1Sdlg t->t_func = fn; 344e4195480Sdlg t->t_arg = arg; 345e72c42a1Sdlg t->t_flags = 0; 346e72c42a1Sdlg } 347e72c42a1Sdlg 348e72c42a1Sdlg int 349e72c42a1Sdlg task_add(struct taskq *tq, struct task *w) 350e72c42a1Sdlg { 351e72c42a1Sdlg int rv = 0; 352e72c42a1Sdlg 353a75b147bSmvs if (ISSET(w->t_flags, TASK_ONQUEUE)) 354a75b147bSmvs return (0); 355a75b147bSmvs 356e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 357e72c42a1Sdlg if (!ISSET(w->t_flags, TASK_ONQUEUE)) { 358e72c42a1Sdlg rv = 1; 359e72c42a1Sdlg SET(w->t_flags, TASK_ONQUEUE); 360e72c42a1Sdlg TAILQ_INSERT_TAIL(&tq->tq_worklist, w, t_entry); 3618430bc4bSanton #if NKCOV > 0 362da19784aSanton if (!kcov_cold) 3638430bc4bSanton w->t_process = curproc->p_p; 3648430bc4bSanton #endif 365e72c42a1Sdlg } 366e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 367e72c42a1Sdlg 368e72c42a1Sdlg if (rv) 369e72c42a1Sdlg wakeup_one(tq); 370e72c42a1Sdlg 371e72c42a1Sdlg return (rv); 372e72c42a1Sdlg } 373e72c42a1Sdlg 374e72c42a1Sdlg int 375e72c42a1Sdlg task_del(struct taskq *tq, struct task *w) 376e72c42a1Sdlg { 377e72c42a1Sdlg int rv = 0; 378e72c42a1Sdlg 379a75b147bSmvs if (!ISSET(w->t_flags, TASK_ONQUEUE)) 380a75b147bSmvs return (0); 381a75b147bSmvs 382e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 383e72c42a1Sdlg if (ISSET(w->t_flags, TASK_ONQUEUE)) { 384e72c42a1Sdlg rv = 1; 385e72c42a1Sdlg CLR(w->t_flags, TASK_ONQUEUE); 386e72c42a1Sdlg TAILQ_REMOVE(&tq->tq_worklist, w, t_entry); 387e72c42a1Sdlg } 388e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 389e72c42a1Sdlg 390e72c42a1Sdlg return (rv); 391e72c42a1Sdlg } 392e72c42a1Sdlg 393e72c42a1Sdlg int 394f07ea34cSdlg taskq_next_work(struct taskq *tq, struct task *work) 395e72c42a1Sdlg { 396e72c42a1Sdlg struct task *next; 397e72c42a1Sdlg 398e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 399e72c42a1Sdlg while ((next = TAILQ_FIRST(&tq->tq_worklist)) == NULL) { 400e72c42a1Sdlg if (tq->tq_state != TQ_S_RUNNING) { 401e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 402e72c42a1Sdlg return (0); 403e72c42a1Sdlg } 404e72c42a1Sdlg 405babb761dSmpi msleep_nsec(tq, &tq->tq_mtx, PWAIT, "bored", INFSLP); 406e72c42a1Sdlg } 407e72c42a1Sdlg 408e72c42a1Sdlg TAILQ_REMOVE(&tq->tq_worklist, next, t_entry); 409e72c42a1Sdlg CLR(next->t_flags, TASK_ONQUEUE); 410e72c42a1Sdlg 411e72c42a1Sdlg *work = *next; /* copy to caller to avoid races */ 412e72c42a1Sdlg 413e72c42a1Sdlg next = TAILQ_FIRST(&tq->tq_worklist); 414e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 415e72c42a1Sdlg 41608dae4e5Sdlg if (next != NULL && tq->tq_nthreads > 1) 417e72c42a1Sdlg wakeup_one(tq); 418e72c42a1Sdlg 419e72c42a1Sdlg return (1); 420e72c42a1Sdlg } 421e72c42a1Sdlg 422e72c42a1Sdlg void 423e72c42a1Sdlg taskq_thread(void *xtq) 424e72c42a1Sdlg { 425ba614123Sdlg struct taskq_thread self = { .tt_thread = curproc }; 426e72c42a1Sdlg struct taskq *tq = xtq; 427e72c42a1Sdlg struct task work; 428e72c42a1Sdlg int last; 429e72c42a1Sdlg 43079ea9c08Sdlg if (ISSET(tq->tq_flags, TASKQ_MPSAFE)) 4314e29e7adSkettenis KERNEL_UNLOCK(); 4324e29e7adSkettenis 433ba614123Sdlg mtx_enter(&tq->tq_mtx); 434ba614123Sdlg SLIST_INSERT_HEAD(&tq->tq_threads, &self, tt_entry); 435ba614123Sdlg mtx_leave(&tq->tq_mtx); 436ba614123Sdlg 43760aa962eSdlg WITNESS_CHECKORDER(&tq->tq_lock_object, LOP_NEWORDER, NULL); 43860aa962eSdlg 439f07ea34cSdlg while (taskq_next_work(tq, &work)) { 44060aa962eSdlg WITNESS_LOCK(&tq->tq_lock_object, 0); 4418430bc4bSanton #if NKCOV > 0 4428430bc4bSanton kcov_remote_enter(KCOV_REMOTE_COMMON, work.t_process); 4438430bc4bSanton #endif 444e4195480Sdlg (*work.t_func)(work.t_arg); 4458430bc4bSanton #if NKCOV > 0 4468430bc4bSanton kcov_remote_leave(KCOV_REMOTE_COMMON, work.t_process); 4478430bc4bSanton #endif 44860aa962eSdlg WITNESS_UNLOCK(&tq->tq_lock_object, 0); 4499b1ed563Smpi sched_pause(yield); 450bb38800eSblambert } 451e72c42a1Sdlg 452e72c42a1Sdlg mtx_enter(&tq->tq_mtx); 453ba614123Sdlg SLIST_REMOVE(&tq->tq_threads, &self, taskq_thread, tt_entry); 454e72c42a1Sdlg last = (--tq->tq_running == 0); 455e72c42a1Sdlg mtx_leave(&tq->tq_mtx); 456e72c42a1Sdlg 4579e51102cSdlg if (ISSET(tq->tq_flags, TASKQ_MPSAFE)) 4589e51102cSdlg KERNEL_LOCK(); 4599e51102cSdlg 460e72c42a1Sdlg if (last) 461e72c42a1Sdlg wakeup_one(&tq->tq_running); 462e72c42a1Sdlg 463e72c42a1Sdlg kthread_exit(0); 464e72c42a1Sdlg } 465