Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/external/cddl/osnet This implementation of Solaris taskq API...
details: https://anonhg.NetBSD.org/src/rev/6981445deaa9
branches: trunk
changeset: 451126:6981445deaa9
user: hannken <hannken%NetBSD.org@localhost>
date: Tue May 07 08:49:59 2019 +0000
description:
This implementation of Solaris taskq API is incomplete and doesn't track
Solaris upstream. FreeBSD already replaced it with a glue to their
taskqueue API.
Replace it with a glue component that queues Solaris taskq requests to
threadpool jobs.
diffstat:
external/cddl/osnet/dist/uts/common/fs/zfs/spa.c | 2 +-
external/cddl/osnet/dist/uts/common/fs/zfs/zio.c | 8 +-
external/cddl/osnet/dist/uts/common/sys/taskq.h | 12 +-
external/cddl/osnet/sys/kern/taskq.c | 1743 ++-------------------
external/cddl/osnet/sys/sys/zfs_context.h | 9 +-
5 files changed, 255 insertions(+), 1519 deletions(-)
diffs (truncated from 1932 to 300 lines):
diff -r ca7f4684b11b -r 6981445deaa9 external/cddl/osnet/dist/uts/common/fs/zfs/spa.c
--- a/external/cddl/osnet/dist/uts/common/fs/zfs/spa.c Tue May 07 08:14:59 2019 +0000
+++ b/external/cddl/osnet/dist/uts/common/fs/zfs/spa.c Tue May 07 08:49:59 2019 +0000
@@ -924,7 +924,7 @@
* then a difference between them is insignificant.
*/
if (t == ZIO_TYPE_WRITE && q == ZIO_TASKQ_ISSUE)
-#ifdef illumos
+#if defined(illumos) || defined(__NetBSD__)
pri--;
#else
pri += 4;
diff -r ca7f4684b11b -r 6981445deaa9 external/cddl/osnet/dist/uts/common/fs/zfs/zio.c
--- a/external/cddl/osnet/dist/uts/common/fs/zfs/zio.c Tue May 07 08:14:59 2019 +0000
+++ b/external/cddl/osnet/dist/uts/common/fs/zfs/zio.c Tue May 07 08:49:59 2019 +0000
@@ -1537,8 +1537,10 @@
* to a single taskq at a time. It would be a grievous error
* to dispatch the zio to another taskq at the same time.
*/
-#if defined(illumos) || defined(__NetBSD__) || !defined(_KERNEL)
+#if defined(illumos) || !defined(_KERNEL)
ASSERT(zio->io_tqent.tqent_next == NULL);
+#elif defined(__NetBSD__)
+ ASSERT(zio->io_tqent.tqent_queued == 0);
#else
ASSERT(zio->io_tqent.tqent_task.ta_pending == 0);
#endif
@@ -3842,8 +3844,10 @@
* Reexecution is potentially a huge amount of work.
* Hand it off to the otherwise-unused claim taskq.
*/
-#if defined(illumos) || defined(__NetBSD__) || !defined(_KERNEL)
+#if defined(illumos) || !defined(_KERNEL)
ASSERT(zio->io_tqent.tqent_next == NULL);
+#elif defined(__NetBSD__)
+ ASSERT(zio->io_tqent.tqent_queued == 0);
#else
ASSERT(zio->io_tqent.tqent_task.ta_pending == 0);
#endif
diff -r ca7f4684b11b -r 6981445deaa9 external/cddl/osnet/dist/uts/common/sys/taskq.h
--- a/external/cddl/osnet/dist/uts/common/sys/taskq.h Tue May 07 08:14:59 2019 +0000
+++ b/external/cddl/osnet/dist/uts/common/sys/taskq.h Tue May 07 08:49:59 2019 +0000
@@ -54,6 +54,16 @@
typedef uintptr_t taskqid_t;
typedef void (task_func_t)(void *);
+#ifdef __NetBSD__
+typedef struct taskq_ent {
+ SIMPLEQ_ENTRY(taskq_ent) tqent_list; /* Task queue. */
+ task_func_t *tqent_func; /* Function to run. */
+ void *tqent_arg; /* Argument to function above. */
+ unsigned tqent_dynamic:1; /* Must kmem_free() if true. */
+ unsigned tqent_queued:1; /* Queued and waiting to run if true. */
+} taskq_ent_t;
+#endif
+
struct proc;
/*
@@ -89,7 +99,7 @@
taskq_t *taskq_create_sysdc(const char *, int, int, int,
struct proc *, uint_t, uint_t);
taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__NetBSD__)
void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
taskq_ent_t *);
#endif
diff -r ca7f4684b11b -r 6981445deaa9 external/cddl/osnet/sys/kern/taskq.c
--- a/external/cddl/osnet/sys/kern/taskq.c Tue May 07 08:14:59 2019 +0000
+++ b/external/cddl/osnet/sys/kern/taskq.c Tue May 07 08:49:59 2019 +0000
@@ -1,1594 +1,323 @@
-/* $NetBSD: taskq.c,v 1.8 2019/01/12 10:42:40 hannken Exp $ */
+/* $NetBSD: taskq.c,v 1.9 2019/05/07 08:49:59 hannken Exp $ */
-/*
- * CDDL HEADER START
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
*
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Juergen Hannken-Illjes.
*
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
-/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
- */
+#include <sys/types.h>
+#include <sys/mutex.h>
+#include <sys/kcondvar.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/threadpool.h>
+
+#include <sys/taskq.h>
+
+struct taskq_executor {
+ struct threadpool_job te_job; /* Threadpool job serving the queue. */
+ taskq_t *te_self; /* Backpointer to the queue. */
+ unsigned te_running:1; /* True if the job is running. */
+};
+
+struct taskq {
+ int tq_nthreads; /* # of threads serving queue. */
+ pri_t tq_pri; /* Scheduling priority. */
+ uint_t tq_flags; /* Saved flags from taskq_create. */
+ int tq_active; /* # of tasks (queued or running). */
+ int tq_running; /* # of jobs currently running. */
+ int tq_waiting; /* # of jobs currently idle. */
+ unsigned tq_destroyed:1; /* True if queue gets destroyed. */
+ kmutex_t tq_lock; /* Queue and job lock. */
+ kcondvar_t tq_cv; /* Queue condvar. */
+ struct taskq_executor *tq_executor; /* Array of jobs. */
+ struct threadpool *tq_threadpool; /* Pool backing the jobs. */
+ SIMPLEQ_HEAD(, taskq_ent) tq_list; /* Queue of tasks waiting. */
+};
+
+taskq_t *system_taskq; /* General purpose task queue. */
+
+static specificdata_key_t taskq_lwp_key; /* Null or taskq this thread runs. */
/*
- * Kernel task queues: general-purpose asynchronous task scheduling.
- *
- * A common problem in kernel programming is the need to schedule tasks
- * to be performed later, by another thread. There are several reasons
- * you may want or need to do this:
- *
- * (1) The task isn't time-critical, but your current code path is.
- *
- * (2) The task may require grabbing locks that you already hold.
- *
- * (3) The task may need to block (e.g. to wait for memory), but you
- * cannot block in your current context.
- *
- * (4) Your code path can't complete because of some condition, but you can't
- * sleep or fail, so you queue the task for later execution when condition
- * disappears.
- *
- * (5) You just want a simple way to launch multiple tasks in parallel.
- *
- * Task queues provide such a facility. In its simplest form (used when
- * performance is not a critical consideration) a task queue consists of a
- * single list of tasks, together with one or more threads to service the
- * list. There are some cases when this simple queue is not sufficient:
- *
- * (1) The task queues are very hot and there is a need to avoid data and lock
- * contention over global resources.
- *
- * (2) Some tasks may depend on other tasks to complete, so they can't be put in
- * the same list managed by the same thread.
- *
- * (3) Some tasks may block for a long time, and this should not block other
- * tasks in the queue.
- *
- * To provide useful service in such cases we define a "dynamic task queue"
- * which has an individual thread for each of the tasks. These threads are
- * dynamically created as they are needed and destroyed when they are not in
- * use. The API for managing task pools is the same as for managing task queues
- * with the exception of a taskq creation flag TASKQ_DYNAMIC which tells that
- * dynamic task pool behavior is desired.
- *
- * Dynamic task queues may also place tasks in the normal queue (called "backing
- * queue") when task pool runs out of resources. Users of task queues may
- * disallow such queued scheduling by specifying TQ_NOQUEUE in the dispatch
- * flags.
- *
- * The backing task queue is also used for scheduling internal tasks needed for
- * dynamic task queue maintenance.
- *
- * INTERFACES ==================================================================
- *
- * taskq_t *taskq_create(name, nthreads, pri, minalloc, maxalloc, flags);
- *
- * Create a taskq with specified properties.
- * Possible 'flags':
- *
- * TASKQ_DYNAMIC: Create task pool for task management. If this flag is
- * specified, 'nthreads' specifies the maximum number of threads in
- * the task queue. Task execution order for dynamic task queues is
- * not predictable.
- *
- * If this flag is not specified (default case) a
- * single-list task queue is created with 'nthreads' threads
- * servicing it. Entries in this queue are managed by
- * taskq_ent_alloc() and taskq_ent_free() which try to keep the
- * task population between 'minalloc' and 'maxalloc', but the
- * latter limit is only advisory for TQ_SLEEP dispatches and the
- * former limit is only advisory for TQ_NOALLOC dispatches. If
- * TASKQ_PREPOPULATE is set in 'flags', the taskq will be
- * prepopulated with 'minalloc' task structures.
- *
- * Since non-DYNAMIC taskqs are queues, tasks are guaranteed to be
- * executed in the order they are scheduled if nthreads == 1.
- * If nthreads > 1, task execution order is not predictable.
- *
- * TASKQ_PREPOPULATE: Prepopulate task queue with threads.
- * Also prepopulate the task queue with 'minalloc' task structures.
- *
- * TASKQ_THREADS_CPU_PCT: This flag specifies that 'nthreads' should be
- * interpreted as a percentage of the # of online CPUs on the
- * system. The taskq subsystem will automatically adjust the
- * number of threads in the taskq in response to CPU online
- * and offline events, to keep the ratio. nthreads must be in
- * the range [0,100].
- *
- * The calculation used is:
- *
- * MAX((ncpus_online * percentage)/100, 1)
- *
- * This flag is not supported for DYNAMIC task queues.
- * This flag is not compatible with TASKQ_CPR_SAFE.
- *
- * TASKQ_CPR_SAFE: This flag specifies that users of the task queue will
- * use their own protocol for handling CPR issues. This flag is not
- * supported for DYNAMIC task queues. This flag is not compatible
- * with TASKQ_THREADS_CPU_PCT.
- *
- * The 'pri' field specifies the default priority for the threads that
- * service all scheduled tasks.
- *
- * taskq_t *taskq_create_instance(name, instance, nthreads, pri, minalloc,
- * maxalloc, flags);
- *
- * Like taskq_create(), but takes an instance number (or -1 to indicate
- * no instance).
- *
- * taskq_t *taskq_create_proc(name, nthreads, pri, minalloc, maxalloc, proc,
- * flags);
- *
- * Like taskq_create(), but creates the taskq threads in the specified
- * system process. If proc != &p0, this must be called from a thread
- * in that process.
- *
- * taskq_t *taskq_create_sysdc(name, nthreads, minalloc, maxalloc, proc,
- * dc, flags);
- *
- * Like taskq_create_proc(), but the taskq threads will use the
- * System Duty Cycle (SDC) scheduling class with a duty cycle of dc.
- *
- * void taskq_destroy(tap):
- *
- * Waits for any scheduled tasks to complete, then destroys the taskq.
- * Caller should guarantee that no new tasks are scheduled in the closing
- * taskq.
- *
- * taskqid_t taskq_dispatch(tq, func, arg, flags):
- *
- * Dispatches the task "func(arg)" to taskq. The 'flags' indicates whether
- * the caller is willing to block for memory. The function returns an
- * opaque value which is zero iff dispatch fails. If flags is TQ_NOSLEEP
- * or TQ_NOALLOC and the task can't be dispatched, taskq_dispatch() fails
- * and returns (taskqid_t)0.
- *
- * ASSUMES: func != NULL.
- *
- * Possible flags:
- * TQ_NOSLEEP: Do not wait for resources; may fail.
- *
Home |
Main Index |
Thread Index |
Old Index