9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  28  * Copyright (c) 2017 by Delphix. All rights reserved.
  29  */
  30 
  31 /*
  32  * Kernel task queues: general-purpose asynchronous task scheduling.
  33  *
  34  * A common problem in kernel programming is the need to schedule tasks
  35  * to be performed later, by another thread. There are several reasons
  36  * you may want or need to do this:
  37  *
  38  * (1) The task isn't time-critical, but your current code path is.
  39  *
  40  * (2) The task may require grabbing locks that you already hold.
  41  *
  42  * (3) The task may need to block (e.g. to wait for memory), but you
  43  *     cannot block in your current context.
  44  *
  45  * (4) Your code path can't complete because of some condition, but you can't
  46  *     sleep or fail, so you queue the task for later execution when condition
  47  *     disappears.
  48  *
 
 
1302         ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
1303 
1304         /*
1305          * Mark it as a prealloc'd task.  This is important
1306          * to ensure that we don't free it later.
1307          */
1308         tqe->tqent_un.tqent_flags |= TQENT_FLAG_PREALLOC;
1309         /*
1310          * Enqueue the task to the underlying queue.
1311          */
1312         mutex_enter(&tq->tq_lock);
1313 
1314         if (flags & TQ_FRONT) {
1315                 TQ_ENQUEUE_FRONT(tq, tqe, func, arg);
1316         } else {
1317                 TQ_ENQUEUE(tq, tqe, func, arg);
1318         }
1319         mutex_exit(&tq->tq_lock);
1320 }
1321 
1322 /*
1323  * Wait for all pending tasks to complete.
1324  * Calling taskq_wait from a task will cause deadlock.
1325  */
1326 void
1327 taskq_wait(taskq_t *tq)
1328 {
1329         ASSERT(tq != curthread->t_taskq);
1330 
1331         mutex_enter(&tq->tq_lock);
1332         while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
1333                 cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
1334         mutex_exit(&tq->tq_lock);
1335 
1336         if (tq->tq_flags & TASKQ_DYNAMIC) {
1337                 taskq_bucket_t *b = tq->tq_buckets;
1338                 int bid = 0;
1339                 for (; (b != NULL) && (bid < tq->tq_nbuckets); b++, bid++) {
1340                         mutex_enter(&b->tqbucket_lock);
1341                         while (b->tqbucket_nalloc > 0)
 
 | 
 
 
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  28  * Copyright (c) 2017 by Delphix. All rights reserved.
  29  * Copyright (c) 2017, Joyent, Inc.
  30  */
  31 
  32 /*
  33  * Kernel task queues: general-purpose asynchronous task scheduling.
  34  *
  35  * A common problem in kernel programming is the need to schedule tasks
  36  * to be performed later, by another thread. There are several reasons
  37  * you may want or need to do this:
  38  *
  39  * (1) The task isn't time-critical, but your current code path is.
  40  *
  41  * (2) The task may require grabbing locks that you already hold.
  42  *
  43  * (3) The task may need to block (e.g. to wait for memory), but you
  44  *     cannot block in your current context.
  45  *
  46  * (4) Your code path can't complete because of some condition, but you can't
  47  *     sleep or fail, so you queue the task for later execution when condition
  48  *     disappears.
  49  *
 
 
1303         ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
1304 
1305         /*
1306          * Mark it as a prealloc'd task.  This is important
1307          * to ensure that we don't free it later.
1308          */
1309         tqe->tqent_un.tqent_flags |= TQENT_FLAG_PREALLOC;
1310         /*
1311          * Enqueue the task to the underlying queue.
1312          */
1313         mutex_enter(&tq->tq_lock);
1314 
1315         if (flags & TQ_FRONT) {
1316                 TQ_ENQUEUE_FRONT(tq, tqe, func, arg);
1317         } else {
1318                 TQ_ENQUEUE(tq, tqe, func, arg);
1319         }
1320         mutex_exit(&tq->tq_lock);
1321 }
1322 
1323 /*
1324  * Allow our caller to ask if there are tasks pending on the queue.
1325  */
1326 boolean_t
1327 taskq_empty(taskq_t *tq)
1328 {
1329         boolean_t rv;
1330 
1331         ASSERT3P(tq, !=, curthread->t_taskq);
1332         mutex_enter(&tq->tq_lock);
1333         rv = (tq->tq_task.tqent_next == &tq->tq_task) && (tq->tq_active == 0);
1334         mutex_exit(&tq->tq_lock);
1335 
1336         return (rv);
1337 }
1338 
1339 /*
1340  * Wait for all pending tasks to complete.
1341  * Calling taskq_wait from a task will cause deadlock.
1342  */
1343 void
1344 taskq_wait(taskq_t *tq)
1345 {
1346         ASSERT(tq != curthread->t_taskq);
1347 
1348         mutex_enter(&tq->tq_lock);
1349         while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
1350                 cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
1351         mutex_exit(&tq->tq_lock);
1352 
1353         if (tq->tq_flags & TASKQ_DYNAMIC) {
1354                 taskq_bucket_t *b = tq->tq_buckets;
1355                 int bid = 0;
1356                 for (; (b != NULL) && (bid < tq->tq_nbuckets); b++, bid++) {
1357                         mutex_enter(&b->tqbucket_lock);
1358                         while (b->tqbucket_nalloc > 0)
 
 |