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