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)
|