hrev56208 adds 1 changeset to branch 'master'
old head: ed20f6660f54b5c48f684ed4ad419daf2571f176
new head: 01631912293e6b193ffe904ca0e39d70761fcb5a
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=01631912293e+%5Eed20f6660f54
----------------------------------------------------------------------------
01631912293e: freebsd_network: Rework taskqueues implementation.
* Use FreeBSD's queue management directly, only retaining thread
creation and synchronization functions from Haiku.
* Use FreeBSD's task structure declarations.
* Use a standard non-FAST taskqueue for taskqueue_thread.
* Rewrite header and adjust consumers as appropriate.
[ Augustin Cavalier <waddlesplash@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev56208
Commit: 01631912293e6b193ffe904ca0e39d70761fcb5a
URL: https://git.haiku-os.org/haiku/commit/?id=01631912293e
Author: Augustin Cavalier <waddlesplash@xxxxxxxxx>
Date: Tue Jun 21 20:17:50 2022 UTC
----------------------------------------------------------------------------
7 files changed, 786 insertions(+), 472 deletions(-)
.../compat/freebsd_iflib/compat/sys/gtaskqueue.h | 4 -
.../compat/freebsd_iflib/compat/sys/taskqueue.h | 23 -
.../compat/freebsd_network/compat/sys/_task.h | 72 ++-
.../freebsd_network/compat/sys/taskqueue.h | 214 ++++++--
.../compat/freebsd_network/fbsd_subr_taskqueue.c | 519 +++++++++++++++++++
src/libs/compat/freebsd_network/taskqueue.c | 420 ++-------------
.../compat/openbsd_network/compat/sys/task.h | 6 +-
----------------------------------------------------------------------------
diff --git a/src/libs/compat/freebsd_iflib/compat/sys/gtaskqueue.h
b/src/libs/compat/freebsd_iflib/compat/sys/gtaskqueue.h
index 7ef73d450b..9db06ebf9d 100644
--- a/src/libs/compat/freebsd_iflib/compat/sys/gtaskqueue.h
+++ b/src/libs/compat/freebsd_iflib/compat/sys/gtaskqueue.h
@@ -85,10 +85,6 @@ void taskqgroup_config_gtask_init(void *ctx, struct
grouptask *gtask,
gtask_fn_t *fn, const char *name);
void taskqgroup_config_gtask_deinit(struct grouptask *gtask);
-#define TASK_ENQUEUED 0x1
-#define TASK_SKIP_WAKEUP 0x2
-#define TASK_NOENQUEUE 0x4
-
#define GTASK_INIT(gtask, flags, priority, func, context) do { \
(gtask)->ta_flags = flags; \
(gtask)->ta_priority = (priority); \
diff --git a/src/libs/compat/freebsd_iflib/compat/sys/taskqueue.h
b/src/libs/compat/freebsd_iflib/compat/sys/taskqueue.h
deleted file mode 100644
index 728e88e152..0000000000
--- a/src/libs/compat/freebsd_iflib/compat/sys/taskqueue.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2018, Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
- */
-#ifndef _FBSD_IFLIB_SYS_TASKQUEUE_H_
-#define _FBSD_IFLIB_SYS_TASKQUEUE_H_
-
-/* include the real sys/taskqueue.h */
-#include_next <sys/taskqueue.h>
-
-typedef void (*taskqueue_callback_fn)(void *context);
-
-
-enum taskqueue_callback_type {
- TASKQUEUE_CALLBACK_TYPE_INIT,
- TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
-};
-#define TASKQUEUE_CALLBACK_TYPE_MIN TASKQUEUE_CALLBACK_TYPE_INIT
-#define TASKQUEUE_CALLBACK_TYPE_MAX TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
-#define TASKQUEUE_NUM_CALLBACKS TASKQUEUE_CALLBACK_TYPE_MAX + 1
-
-
-#endif /* _FBSD_IFLIB_SYS_TASKQUEUE_H_ */
diff --git a/src/libs/compat/freebsd_network/compat/sys/_task.h
b/src/libs/compat/freebsd_network/compat/sys/_task.h
index d50ee8a88f..da8e7724d9 100644
--- a/src/libs/compat/freebsd_network/compat/sys/_task.h
+++ b/src/libs/compat/freebsd_network/compat/sys/_task.h
@@ -1,29 +1,63 @@
-/*
- * Copyright 2007 Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2000 Doug Rabson
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
*/
-#ifndef _FBSD_COMPAT_SYS__TASK_H_
-#define _FBSD_COMPAT_SYS__TASK_H_
-
-/* Haiku's list management */
-#include <util/list.h>
+#ifndef _SYS__TASK_H_
+#define _SYS__TASK_H_
+#include <sys/queue.h>
-typedef void (*task_fn_t)(void *context, int pending);
+/*
+ * Each task includes a function which is called from
+ * taskqueue_run(). The first argument is taken from the 'ta_context'
+ * field of struct task and the second argument is a count of how many
+ * times the task was enqueued before the call to taskqueue_run().
+ *
+ * List of locks
+ * (c) const after init
+ * (q) taskqueue lock
+ */
+typedef void task_fn_t(void *context, int pending);
struct task {
- int ta_pending;
- int ta_priority;
- int ta_flags;
- task_fn_t ta_handler;
- void *ta_argument;
-
- struct list_link ta_link;
+ STAILQ_ENTRY(task) ta_link; /* (q) link for queue */
+ uint16_t ta_pending; /* (q) count times queued */
+ uint8_t ta_priority; /* (c) Priority */
+ uint8_t ta_flags; /* (c) Flags */
+ task_fn_t *ta_func; /* (c) task handler */
+ void *ta_context; /* (c) argument for handler */
};
+#define TASK_ENQUEUED (1<<0)
+#define TASK_NOENQUEUE (1<<1)
+#define TASK_SKIP_WAKEUP (1<<2)
-#define TASK_NEEDSGIANT (1 << 0) /* Haiku extension, OpenBSD compatibility */
-
+#define TASK_NEEDSGIANT (1<<3) /* Haiku extension, OpenBSD
compatibility */
-#endif
+#endif /* !_SYS__TASK_H_ */
diff --git a/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
b/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
index d9adb6ad87..f1009051d0 100644
--- a/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
+++ b/src/libs/compat/freebsd_network/compat/sys/taskqueue.h
@@ -1,15 +1,45 @@
-/*
- * Copyright 2007-2018, Haiku, Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
*/
-#ifndef _FBSD_COMPAT_SYS_TASKQUEUE_H_
-#define _FBSD_COMPAT_SYS_TASKQUEUE_H_
+#ifndef _SYS_TASKQUEUE_H_
+#define _SYS_TASKQUEUE_H_
+
+#ifndef _KERNEL
+#error "no user-servicable parts inside"
+#endif
#include <sys/queue.h>
#include <sys/_task.h>
-#include <sys/callout.h>
+#include <sys/_callout.h>
+struct taskqueue;
+struct taskqgroup;
+struct thread;
struct timeout_task {
struct taskqueue *q;
@@ -18,48 +48,148 @@ struct timeout_task {
int f;
};
-#define TASKQUEUE_NAMELEN 64
+enum taskqueue_callback_type {
+ TASKQUEUE_CALLBACK_TYPE_INIT,
+ TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
+};
+#define TASKQUEUE_CALLBACK_TYPE_MIN TASKQUEUE_CALLBACK_TYPE_INIT
+#define TASKQUEUE_CALLBACK_TYPE_MAX TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
+#define TASKQUEUE_NUM_CALLBACKS TASKQUEUE_CALLBACK_TYPE_MAX + 1
+#define TASKQUEUE_NAMELEN 32
-typedef void (*taskqueue_enqueue_fn)(void *context);
+typedef void (*taskqueue_callback_fn)(void *context);
+/*
+ * A notification callback function which is called from
+ * taskqueue_enqueue(). The context argument is given in the call to
+ * taskqueue_create(). This function would normally be used to allow the
+ * queue to arrange to run itself later (e.g., by scheduling a software
+ * interrupt or waking a kernel thread).
+ */
+typedef void (*taskqueue_enqueue_fn)(void *context);
-struct taskqueue;
struct taskqueue *taskqueue_create(const char *name, int mflags,
- taskqueue_enqueue_fn enqueue, void *context);
-int taskqueue_start_threads(struct taskqueue **tq, int count, int pri,
- const char *name, ...) __printflike(4, 5);
-void taskqueue_free(struct taskqueue *tq);
-void taskqueue_drain(struct taskqueue *tq, struct task *task);
-void taskqueue_drain_timeout(struct taskqueue *queue,
- struct timeout_task *timeout_task);
-void taskqueue_drain_all(struct taskqueue *tq);
-void taskqueue_block(struct taskqueue *queue);
-void taskqueue_unblock(struct taskqueue *queue);
-int taskqueue_enqueue(struct taskqueue *tq, struct task *task);
-int taskqueue_enqueue_timeout(struct taskqueue *queue,
- struct timeout_task *ttask, int _ticks);
-int taskqueue_cancel(struct taskqueue *queue, struct task *task,
- u_int *pendp);
-int taskqueue_cancel_timeout(struct taskqueue *queue,
- struct timeout_task *timeout_task, u_int *pendp);
-
-void taskqueue_thread_enqueue(void *context);
-
-extern struct taskqueue *taskqueue_fast;
-extern struct taskqueue *taskqueue_swi;
-extern struct taskqueue *taskqueue_thread;
-
-int taskqueue_enqueue_fast(struct taskqueue *queue, struct task *task);
-struct taskqueue *taskqueue_create_fast(const char *name, int mflags,
- taskqueue_enqueue_fn enqueue, void *context);
+ taskqueue_enqueue_fn enqueue,
+ void *context);
+int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
+ const char *name, ...) __printflike(4, 5);
+int taskqueue_enqueue(struct taskqueue *queue, struct task *task);
+int taskqueue_enqueue_timeout(struct taskqueue *queue,
+ struct timeout_task *timeout_task, int _ticks);
+int taskqueue_cancel(struct taskqueue *queue, struct task *task,
+ u_int *pendp);
+int taskqueue_cancel_timeout(struct taskqueue *queue,
+ struct timeout_task *timeout_task, u_int *pendp);
+void taskqueue_drain(struct taskqueue *queue, struct task *task);
+void taskqueue_drain_timeout(struct taskqueue *queue,
+ struct timeout_task *timeout_task);
+void taskqueue_drain_all(struct taskqueue *queue);
+void taskqueue_free(struct taskqueue *queue);
+void taskqueue_run(struct taskqueue *queue);
+void taskqueue_block(struct taskqueue *queue);
+void taskqueue_unblock(struct taskqueue *queue);
+int taskqueue_member(struct taskqueue *queue, struct thread *td);
+void taskqueue_set_callback(struct taskqueue *queue,
+ enum taskqueue_callback_type cb_type,
+ taskqueue_callback_fn callback, void *context);
+
+/*
+ * Functions for dedicated thread taskqueues
+ */
+void taskqueue_thread_loop(void *arg);
+void taskqueue_thread_enqueue(void *context);
-void task_init(struct task *, int prio, task_fn_t handler, void *arg);
-#define TASK_INIT(taskp, prio, hand, arg) task_init(taskp, prio, hand, arg)
+/*
+ * Initialise a task structure.
+ */
+void _task_init(struct task *, int prio, task_fn_t handler, void *arg);
+#define TASK_INIT(taskp, prio, hand, arg) _task_init(taskp, prio, hand, arg)
#define NET_TASK_INIT TASK_INIT
-void timeout_task_init(struct taskqueue *queue, struct timeout_task
*timeout_task,
- int priority, task_fn_t func, void *context);
+void _timeout_task_init(struct taskqueue *queue,
+ struct timeout_task *timeout_task, int priority, task_fn_t func,
+ void *context);
#define TIMEOUT_TASK_INIT(queue, timeout_task, priority, func, context)
\
- timeout_task_init(queue, timeout_task, priority, func, context);
+ _timeout_task_init(queue, timeout_task, priority, func, context);
-#endif
+/*
+ * Declare a reference to a taskqueue.
+ */
+#define TASKQUEUE_DECLARE(name) \
+extern struct taskqueue *taskqueue_##name
+
+/*
+ * Define and initialise a global taskqueue that uses sleep mutexes.
+ */
+#define TASKQUEUE_DEFINE(name, enqueue, context, init) \
+ \
+struct taskqueue *taskqueue_##name; \
+ \
+static void \
+taskqueue_define_##name(void *arg) \
+{ \
+ taskqueue_##name = \
+ taskqueue_create(#name, M_WAITOK, (enqueue), (context));
\
+ init; \
+} \
+ \
+SYSINIT(taskqueue_##name, SI_SUB_INIT_IF, SI_ORDER_SECOND, \
+ taskqueue_define_##name, NULL); \
+ \
+struct __hack
+#define TASKQUEUE_DEFINE_THREAD(name) \
+TASKQUEUE_DEFINE(name, taskqueue_thread_enqueue, &taskqueue_##name, \
+ taskqueue_start_threads(&taskqueue_##name, 1, PWAIT, \
+ "%s taskq", #name))
+
+/*
+ * Define and initialise a global taskqueue that uses spin mutexes.
+ */
+#define TASKQUEUE_FAST_DEFINE(name, enqueue, context, init) \
+ \
+struct taskqueue *taskqueue_##name; \
+ \
+static void \
+taskqueue_define_##name(void *arg) \
+{ \
+ taskqueue_##name = \
+ taskqueue_create_fast(#name, M_WAITOK, (enqueue),
\
+ (context));
\
+ init; \
+} \
+ \
+SYSINIT(taskqueue_##name, SI_SUB_INIT_IF, SI_ORDER_SECOND, \
+ taskqueue_define_##name, NULL); \
+ \
+struct __hack
+#define TASKQUEUE_FAST_DEFINE_THREAD(name) \
+TASKQUEUE_FAST_DEFINE(name, taskqueue_thread_enqueue, \
+ &taskqueue_##name, taskqueue_start_threads(&taskqueue_##name \
+ 1, PWAIT, "%s taskq", #name))
+
+/*
+ * These queues are serviced by software interrupt handlers. To enqueue
+ * a task, call taskqueue_enqueue(taskqueue_swi, &task) or
+ * taskqueue_enqueue(taskqueue_swi_giant, &task).
+ */
+TASKQUEUE_DECLARE(swi_giant);
+TASKQUEUE_DECLARE(swi);
+
+/*
+ * This queue is serviced by a kernel thread. To enqueue a task, call
+ * taskqueue_enqueue(taskqueue_thread, &task).
+ */
+TASKQUEUE_DECLARE(thread);
+
+/*
+ * Queue for swi handlers dispatched from fast interrupt handlers.
+ * These are necessarily different from the above because the queue
+ * must be locked with spinlocks since sleep mutex's cannot be used
+ * from a fast interrupt handler context.
+ */
+TASKQUEUE_DECLARE(fast);
+struct taskqueue *taskqueue_create_fast(const char *name, int mflags,
+ taskqueue_enqueue_fn enqueue,
+ void *context);
+
+#endif /* !_SYS_TASKQUEUE_H_ */
diff --git a/src/libs/compat/freebsd_network/fbsd_subr_taskqueue.c
b/src/libs/compat/freebsd_network/fbsd_subr_taskqueue.c
new file mode 100644
index 0000000000..2f237a3c64
--- /dev/null
+++ b/src/libs/compat/freebsd_network/fbsd_subr_taskqueue.c
@@ -0,0 +1,519 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/libkern.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/taskqueue.h>
+#include <machine/stdarg.h>
+
+static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues");
+static void *taskqueue_giant_ih;
+static void *taskqueue_ih;
+
+struct taskqueue_busy {
+ struct task *tb_running;
+ TAILQ_ENTRY(taskqueue_busy) tb_link;
+};
+
+struct task * const TB_DRAIN_WAITER = (struct task *)0x1;
+
+struct taskqueue {
+ STAILQ_HEAD(, task) tq_queue;
+ taskqueue_enqueue_fn tq_enqueue;
+ void *tq_context;
+ char *tq_name;
+ TAILQ_HEAD(, taskqueue_busy) tq_active;
+ struct mtx tq_mutex;
+#ifdef __HAIKU__
+ sem_id tq_sem;
+ thread_id *tq_threads;
+ thread_id tq_thread_storage;
+ int tq_threadcount;
+#else
+ struct thread **tq_threads;
+#endif
+ int tq_tcount;
+ int tq_spin;
+ int tq_flags;
+ int tq_callouts;
+ taskqueue_callback_fn tq_callbacks[TASKQUEUE_NUM_CALLBACKS];
+ void *tq_cb_contexts[TASKQUEUE_NUM_CALLBACKS];
+};
+
+#define TQ_FLAGS_ACTIVE (1 << 0)
+#define TQ_FLAGS_BLOCKED (1 << 1)
+#define TQ_FLAGS_UNLOCKED_ENQUEUE (1 << 2)
+
+#define DT_CALLOUT_ARMED (1 << 0)
+#define DT_DRAIN_IN_PROGRESS (1 << 1)
+
+#define TQ_LOCK(tq)
\
+ do { \
+ if ((tq)->tq_spin) \
+ mtx_lock_spin(&(tq)->tq_mutex); \
+ else \
+ mtx_lock(&(tq)->tq_mutex); \
+ } while (0)
+#define TQ_ASSERT_LOCKED(tq) mtx_assert(&(tq)->tq_mutex, MA_OWNED)
+
+#define TQ_UNLOCK(tq)
\
+ do { \
+ if ((tq)->tq_spin) \
+ mtx_unlock_spin(&(tq)->tq_mutex); \
+ else \
+ mtx_unlock(&(tq)->tq_mutex); \
+ } while (0)
+#define TQ_ASSERT_UNLOCKED(tq) mtx_assert(&(tq)->tq_mutex, MA_NOTOWNED)
+
+void
+_timeout_task_init(struct taskqueue *queue, struct timeout_task *timeout_task,
+ int priority, task_fn_t func, void *context)
+{
+
+ TASK_INIT(&timeout_task->t, priority, func, context);
+ callout_init_mtx(&timeout_task->c, &queue->tq_mutex,
+ CALLOUT_RETURNUNLOCKED);
+ timeout_task->q = queue;
+ timeout_task->f = 0;
+}
+
+static struct taskqueue *
+_taskqueue_create(const char *name, int mflags,
+ taskqueue_enqueue_fn enqueue, void *context,
+ int mtxflags, const char *mtxname __unused)
+{
+ struct taskqueue *queue;
+ char *tq_name;
+
+ tq_name = malloc(TASKQUEUE_NAMELEN, M_TASKQUEUE, mflags | M_ZERO);
+ if (tq_name == NULL)
+ return (NULL);
+
+ queue = malloc(sizeof(struct taskqueue), M_TASKQUEUE, mflags | M_ZERO);
+ if (queue == NULL) {
+ free(tq_name, M_TASKQUEUE);
+ return (NULL);
+ }
+
+ snprintf(tq_name, TASKQUEUE_NAMELEN, "%s", (name) ? name : "taskqueue");
+
+ STAILQ_INIT(&queue->tq_queue);
+ TAILQ_INIT(&queue->tq_active);
+ queue->tq_enqueue = enqueue;
+ queue->tq_context = context;
+ queue->tq_name = tq_name;
+ queue->tq_spin = (mtxflags & MTX_SPIN) != 0;
+ queue->tq_flags |= TQ_FLAGS_ACTIVE;
+ if (enqueue == taskqueue_thread_enqueue)
+ queue->tq_flags |= TQ_FLAGS_UNLOCKED_ENQUEUE;
+ mtx_init(&queue->tq_mutex, tq_name, NULL, mtxflags);
+
+ return (queue);
+}
+
+struct taskqueue *
+taskqueue_create(const char *name, int mflags,
+ taskqueue_enqueue_fn enqueue, void *context)
+{
+
+ return _taskqueue_create(name, mflags, enqueue, context,
+ MTX_DEF, name);
+}
+
+void
+taskqueue_set_callback(struct taskqueue *queue,
+ enum taskqueue_callback_type cb_type, taskqueue_callback_fn callback,
+ void *context)
+{
+
+ KASSERT(((cb_type >= TASKQUEUE_CALLBACK_TYPE_MIN) &&
+ (cb_type <= TASKQUEUE_CALLBACK_TYPE_MAX)),
+ ("Callback type %d not valid, must be %d-%d", cb_type,
+ TASKQUEUE_CALLBACK_TYPE_MIN, TASKQUEUE_CALLBACK_TYPE_MAX));
+ KASSERT((queue->tq_callbacks[cb_type] == NULL),
+ ("Re-initialization of taskqueue callback?"));
+
+ queue->tq_callbacks[cb_type] = callback;
+ queue->tq_cb_contexts[cb_type] = context;
+}
+
+void
+taskqueue_free(struct taskqueue *queue)
+{
+
+ TQ_LOCK(queue);
+ queue->tq_flags &= ~TQ_FLAGS_ACTIVE;
+ taskqueue_terminate(queue->tq_threads, queue);
+ KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?"));
+ KASSERT(queue->tq_callouts == 0, ("Armed timeout tasks"));
+ mtx_destroy(&queue->tq_mutex);
+ free(queue->tq_threads, M_TASKQUEUE);
+ free(queue->tq_name, M_TASKQUEUE);
+ free(queue, M_TASKQUEUE);
+}
+
+static int
+taskqueue_enqueue_locked(struct taskqueue *queue, struct task *task)
+{
+ struct task *ins;
+ struct task *prev;
+
+ KASSERT(task->ta_func != NULL, ("enqueueing task with NULL func"));
+ /*
+ * Count multiple enqueues.
+ */
+ if (task->ta_pending) {
+ if (task->ta_pending < USHRT_MAX)
+ task->ta_pending++;
+ TQ_UNLOCK(queue);
+ return (0);
+ }
+
+ /*
+ * Optimise the case when all tasks have the same priority.
+ */
+ prev = STAILQ_LAST(&queue->tq_queue, task, ta_link);
+ if (!prev || prev->ta_priority >= task->ta_priority) {
+ STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link);
+ } else {
+ prev = NULL;
+ for (ins = STAILQ_FIRST(&queue->tq_queue); ins;
+ prev = ins, ins = STAILQ_NEXT(ins, ta_link))
+ if (ins->ta_priority < task->ta_priority)
+ break;
+
+ if (prev)
+ STAILQ_INSERT_AFTER(&queue->tq_queue, prev, task,
ta_link);
+ else
+ STAILQ_INSERT_HEAD(&queue->tq_queue, task, ta_link);
+ }
+
+ task->ta_pending = 1;
+ if ((queue->tq_flags & TQ_FLAGS_UNLOCKED_ENQUEUE) != 0)
+ TQ_UNLOCK(queue);
+ if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0)
+ queue->tq_enqueue(queue->tq_context);
+ if ((queue->tq_flags & TQ_FLAGS_UNLOCKED_ENQUEUE) == 0)
+ TQ_UNLOCK(queue);
+
+ /* Return with lock released. */
+ return (0);
+}
+
+int
+taskqueue_enqueue(struct taskqueue *queue, struct task *task)
+{
+ int res;
+
+ TQ_LOCK(queue);
+ res = taskqueue_enqueue_locked(queue, task);
+ /* The lock is released inside. */
+
+ return (res);
+}
+
+static void
+taskqueue_timeout_func(void *arg)
+{
+ struct taskqueue *queue;
+ struct timeout_task *timeout_task;
+
+ timeout_task = arg;
+ queue = timeout_task->q;
+ KASSERT((timeout_task->f & DT_CALLOUT_ARMED) != 0, ("Stray timeout"));
+ timeout_task->f &= ~DT_CALLOUT_ARMED;
+ queue->tq_callouts--;
+ taskqueue_enqueue_locked(timeout_task->q, &timeout_task->t);
+ /* The lock is released inside. */
+}
+
+int
+taskqueue_enqueue_timeout(struct taskqueue *queue,
+ struct timeout_task *timeout_task, int _ticks)
+{
+ int res;
+
+ TQ_LOCK(queue);
+ KASSERT(timeout_task->q == NULL || timeout_task->q == queue,
+ ("Migrated queue"));
+ KASSERT(!queue->tq_spin, ("Timeout for spin-queue"));
+ timeout_task->q = queue;
+ res = timeout_task->t.ta_pending;
+ if (timeout_task->f & DT_DRAIN_IN_PROGRESS) {
+ /* Do nothing */
+ TQ_UNLOCK(queue);
+ res = -1;
+ } else if (_ticks == 0) {
+ taskqueue_enqueue_locked(queue, &timeout_task->t);
+ /* The lock is released inside. */
+ } else {
+ if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
+ res++;
+ } else {
+ queue->tq_callouts++;
+ timeout_task->f |= DT_CALLOUT_ARMED;
+ if (_ticks < 0)
+ _ticks = -_ticks; /* Ignore overflow. */
+ }
+ if (_ticks > 0) {
+ callout_reset(&timeout_task->c, _ticks,
+ taskqueue_timeout_func, timeout_task);
+ }
+ TQ_UNLOCK(queue);
+ }
+ return (res);
+}
+
+static void
+taskqueue_task_nop_fn(void *context, int pending)
+{
+}
+
+void
+taskqueue_block(struct taskqueue *queue)
+{
+
+ TQ_LOCK(queue);
+ queue->tq_flags |= TQ_FLAGS_BLOCKED;
+ TQ_UNLOCK(queue);
+}
+
+void
+taskqueue_unblock(struct taskqueue *queue)
+{
+
+ TQ_LOCK(queue);
+ queue->tq_flags &= ~TQ_FLAGS_BLOCKED;
+ if (!STAILQ_EMPTY(&queue->tq_queue))
+ queue->tq_enqueue(queue->tq_context);
+ TQ_UNLOCK(queue);
+}
+
+static void
+taskqueue_run_locked(struct taskqueue *queue)
+{
+ struct taskqueue_busy tb;
+ struct taskqueue_busy *tb_first;
+ struct task *task;
+ int pending;
+
+ KASSERT(queue != NULL, ("tq is NULL"));
+ TQ_ASSERT_LOCKED(queue);
+ tb.tb_running = NULL;
+
+ while (STAILQ_FIRST(&queue->tq_queue)) {
+ TAILQ_INSERT_TAIL(&queue->tq_active, &tb, tb_link);
+
+ /*
+ * Carefully remove the first task from the queue and
+ * zero its pending count.
+ */
+ task = STAILQ_FIRST(&queue->tq_queue);
+ KASSERT(task != NULL, ("task is NULL"));
+ STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link);
+ pending = task->ta_pending;
+ task->ta_pending = 0;
+ tb.tb_running = task;
+ TQ_UNLOCK(queue);
+
+ KASSERT(task->ta_func != NULL, ("task->ta_func is NULL"));
+#ifdef __HAIKU__
+ if ((task->ta_flags & TASK_NEEDSGIANT) != 0)
+ mtx_lock(&Giant);
+#endif
+ task->ta_func(task->ta_context, pending);
+#ifdef __HAIKU__
+ if ((task->ta_flags & TASK_NEEDSGIANT) != 0)
+ mtx_unlock(&Giant);
+#endif
+
+ TQ_LOCK(queue);
+ tb.tb_running = NULL;
+
+ TAILQ_REMOVE(&queue->tq_active, &tb, tb_link);
+ tb_first = TAILQ_FIRST(&queue->tq_active);
+ }
+}
+
+void
+taskqueue_run(struct taskqueue *queue)
+{
+
+ TQ_LOCK(queue);
+ taskqueue_run_locked(queue);
+ TQ_UNLOCK(queue);
+}
+
+static int
+task_is_running(struct taskqueue *queue, struct task *task)
+{
+ struct taskqueue_busy *tb;
+
+ TQ_ASSERT_LOCKED(queue);
+ TAILQ_FOREACH(tb, &queue->tq_active, tb_link) {
+ if (tb->tb_running == task)
+ return (1);
+ }
+ return (0);
+}
+
+static int
+taskqueue_cancel_locked(struct taskqueue *queue, struct task *task,
+ u_int *pendp)
+{
+
+ if (task->ta_pending > 0)
+ STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link);
+ if (pendp != NULL)
+ *pendp = task->ta_pending;
+ task->ta_pending = 0;
+ return (task_is_running(queue, task) ? EBUSY : 0);
+}
+
+int
+taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp)
+{
+ int error;
+
+ TQ_LOCK(queue);
+ error = taskqueue_cancel_locked(queue, task, pendp);
+ TQ_UNLOCK(queue);
+
+ return (error);
+}
+
+int
+taskqueue_cancel_timeout(struct taskqueue *queue,
+ struct timeout_task *timeout_task, u_int *pendp)
+{
+ u_int pending, pending1;
+ int error;
+
+ TQ_LOCK(queue);
+ pending = !!(callout_stop(&timeout_task->c) > 0);
+ error = taskqueue_cancel_locked(queue, &timeout_task->t, &pending1);
+ if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
+ timeout_task->f &= ~DT_CALLOUT_ARMED;
+ queue->tq_callouts--;
+ }
+ TQ_UNLOCK(queue);
+
+ if (pendp != NULL)
+ *pendp = pending + pending1;
+ return (error);
+}
+
+void
+taskqueue_drain_timeout(struct taskqueue *queue,
+ struct timeout_task *timeout_task)
+{
+
+ /*
+ * Set flag to prevent timer from re-starting during drain:
+ */
+ TQ_LOCK(queue);
+ KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
+ ("Drain already in progress"));
+ timeout_task->f |= DT_DRAIN_IN_PROGRESS;
+ TQ_UNLOCK(queue);
+
+ callout_drain(&timeout_task->c);
+ taskqueue_drain(queue, &timeout_task->t);
+
+ /*
+ * Clear flag to allow timer to re-start:
+ */
+ TQ_LOCK(queue);
+ timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
+ TQ_UNLOCK(queue);
+}
+
+int
+taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
+ const char *format, ...)
+{
+ char name[64];
+ int error;
+ va_list vl;
+
+ va_start(vl, format);
+ vsnprintf(name, sizeof(name), format, vl);
+ va_end(vl);
+
+ error = _taskqueue_start_threads(tqp, count, pri, name);
+ return (error);
+}
+
+static inline void
+taskqueue_run_callback(struct taskqueue *tq,
+ enum taskqueue_callback_type cb_type)
+{
+ taskqueue_callback_fn tq_callback;
+
+ TQ_ASSERT_UNLOCKED(tq);
+ tq_callback = tq->tq_callbacks[cb_type];
+ if (tq_callback != NULL)
+ tq_callback(tq->tq_cb_contexts[cb_type]);
+}
+
+int
+taskqueue_member(struct taskqueue *queue, struct thread *td)
+{
+ int i, j, ret = 0;
+
+ for (i = 0, j = 0; ; i++) {
+ if (queue->tq_threads[i] == NULL)
+ continue;
+ if (queue->tq_threads[i] == td) {
+ ret = 1;
+ break;
+ }
+ if (++j >= queue->tq_tcount)
+ break;
+ }
+ return (ret);
+}
+
+struct taskqueue *
+taskqueue_create_fast(const char *name, int mflags,
+ taskqueue_enqueue_fn enqueue, void *context)
+{
+ return _taskqueue_create(name, mflags, enqueue, context,
+ MTX_SPIN, "fast_taskqueue");
+}
diff --git a/src/libs/compat/freebsd_network/taskqueue.c
b/src/libs/compat/freebsd_network/taskqueue.c
index 7ed80a2b78..50163c576f 100644
--- a/src/libs/compat/freebsd_network/taskqueue.c
+++ b/src/libs/compat/freebsd_network/taskqueue.c
@@ -1,13 +1,8 @@
/*
- * Copyright 2009, Colin Günther, coling@xxxxxx
- * Copyright 2007, Hugo Santos. All Rights Reserved.
+ * Copyright 2022, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
- *
- * Authors:
- * Hugo Santos, hugosantos@xxxxxxxxx
*/
-
#include "device.h"
#include <stdio.h>
@@ -17,125 +12,42 @@
#include <compat/sys/haiku-module.h>
-#define TQ_FLAGS_ACTIVE (1 << 0)
-#define TQ_FLAGS_BLOCKED (1 << 1)
-#define TQ_FLAGS_PENDING (1 << 2)
-
-#define DT_CALLOUT_ARMED (1 << 0)
-#define DT_DRAIN_IN_PROGRESS (1 << 1)
-
-struct taskqueue {
- char tq_name[TASKQUEUE_NAMELEN];
- struct mtx tq_mutex;
- struct list tq_list;
- taskqueue_enqueue_fn tq_enqueue;
- void *tq_arg;
- int tq_fast;
- sem_id tq_sem;
- thread_id *tq_threads;
- thread_id tq_thread_storage;
- int tq_threadcount;
- int tq_flags;
- int tq_callouts;
-};
-
-struct taskqueue *taskqueue_fast = NULL;
-struct taskqueue *taskqueue_swi = NULL;
-struct taskqueue *taskqueue_thread = NULL;
-
-
-static struct taskqueue *
-_taskqueue_create(const char *name, int mflags, int fast,
- taskqueue_enqueue_fn enqueueFunction, void *context)
-{
- struct taskqueue *tq = malloc(sizeof(struct taskqueue));
- if (tq == NULL)
- return NULL;
-
- tq->tq_fast = fast;
-
- if (fast) {
- mtx_init(&tq->tq_mutex, name, NULL, MTX_SPIN);
- } else {
- mtx_init(&tq->tq_mutex, name, NULL, MTX_DEF);
- }
+static int _taskqueue_start_threads(struct taskqueue **taskQueue,
+ int count, int priority, const char *name);
+static void taskqueue_terminate(struct thread **pp, struct taskqueue *tq);
- strlcpy(tq->tq_name, name, sizeof(tq->tq_name));
- list_init_etc(&tq->tq_list, offsetof(struct task, ta_link));
- tq->tq_enqueue = enqueueFunction;
- tq->tq_arg = context;
- tq->tq_sem = -1;
- tq->tq_threads = NULL;
- tq->tq_threadcount = 0;
- tq->tq_flags = TQ_FLAGS_ACTIVE;
- tq->tq_callouts = 0;
-
- return tq;
-}
+#define malloc kernel_malloc
+#define free kernel_free
+#include "fbsd_subr_taskqueue.c"
+#undef malloc
+#undef free
-static void
-tq_lock(struct taskqueue *taskQueue)
-{
- if (taskQueue->tq_fast) {
- mtx_lock_spin(&taskQueue->tq_mutex);
- } else {
- mtx_lock(&taskQueue->tq_mutex);
- }
-}
-
-
-static void
-tq_unlock(struct taskqueue *taskQueue)
-{
- if (taskQueue->tq_fast) {
- mtx_unlock_spin(&taskQueue->tq_mutex);
- } else {
- mtx_unlock(&taskQueue->tq_mutex);
- }
-}
-
-
-struct taskqueue *
-taskqueue_create(const char *name, int mflags,
- taskqueue_enqueue_fn enqueueFunction, void *context)
-{
- return _taskqueue_create(name, mflags, 0, enqueueFunction, context);
-}
+struct taskqueue *taskqueue_fast = NULL;
+struct taskqueue *taskqueue_swi = NULL;
+struct taskqueue *taskqueue_thread = NULL;
static int32
tq_handle_thread(void *data)
{
struct taskqueue *tq = data;
- struct task *t;
- int pending;
- sem_id sem;
- /* just a synchronization point */
- tq_lock(tq);
- sem = tq->tq_sem;
- tq_unlock(tq);
-
- while (acquire_sem(sem) == B_NO_ERROR) {
- tq_lock(tq);
- t = list_remove_head_item(&tq->tq_list);
- tq_unlock(tq);
- if (t == NULL)
- continue;
- pending = t->ta_pending;
- t->ta_pending = 0;
+ taskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_INIT);
- if ((t->ta_flags & TASK_NEEDSGIANT) != 0)
- mtx_lock(&Giant);
+ TQ_LOCK(tq);
+ sem_id sem = tq->tq_sem;
+ TQ_UNLOCK(tq);
- t->ta_handler(t->ta_argument, pending);
-
- if ((t->ta_flags & TASK_NEEDSGIANT) != 0)
- mtx_unlock(&Giant);
+ while (acquire_sem(sem) == B_NO_ERROR) {
+ TQ_LOCK(tq);
+ taskqueue_run_locked(tq);
+ TQ_UNLOCK(tq);
}
+ taskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_SHUTDOWN);
+
return 0;
}
@@ -193,56 +105,21 @@ _taskqueue_start_threads(struct taskqueue **taskQueue,
int count, int priority,
}
-int
-taskqueue_start_threads(struct taskqueue **taskQueue, int count, int priority,
- const char *format, ...)
-{
- /* we assume that start_threads is called in a sane place, and thus
- * don't need to be locked. This is mostly due to the fact that if
- * the TQ is 'fast', locking the TQ disables interrupts... and then
- * we can't create semaphores, threads and bananas. */
-
- char name[64];
- int result;
- va_list vl;
-
- va_start(vl, format);
- vsnprintf(name, sizeof(name), format, vl);
- va_end(vl);
-
- /*tq_lock(*tqp);*/
- result = _taskqueue_start_threads(taskQueue, count, priority, name);
- /*tq_unlock(*tqp);*/
-
- return result;
-}
-
-
-void
-taskqueue_free(struct taskqueue *taskQueue)
+static void
+taskqueue_terminate(struct thread **pp, struct taskqueue *tq)
{
- if (taskQueue == NULL)
+ if (tq->tq_sem == -1)
return;
- /* lock and drain list? */
- taskQueue->tq_flags &= ~TQ_FLAGS_ACTIVE;
- if (!taskQueue->tq_fast)
- mtx_destroy(&taskQueue->tq_mutex);
- if (taskQueue->tq_sem != -1) {
- int i;
-
- delete_sem(taskQueue->tq_sem);
-
- for (i = 0; i < taskQueue->tq_threadcount; i++) {
- status_t status;
- wait_for_thread(taskQueue->tq_threads[i], &status);
- }
+ delete_sem(tq->tq_sem);
- if (taskQueue->tq_threadcount > 1)
- free(taskQueue->tq_threads);
+ for (int i = 0; i < tq->tq_threadcount; i++) {
+ status_t status;
+ wait_for_thread(tq->tq_threads[i], &status);
}
- free(taskQueue);
+ if (tq->tq_threadcount > 1)
+ free(tq->tq_threads);
}
@@ -252,44 +129,13 @@ taskqueue_drain(struct taskqueue *taskQueue, struct task
*task)
if (taskQueue == NULL)
return;
- tq_lock(taskQueue);
- while (task->ta_pending != 0) {
- tq_unlock(taskQueue);
+ TQ_LOCK(taskQueue);
+ while (task->ta_pending != 0 || task_is_running(taskQueue, task)) {
+ TQ_UNLOCK(taskQueue);
snooze(0);
- tq_lock(taskQueue);
+ TQ_LOCK(taskQueue);
}
- tq_unlock(taskQueue);
-}
-
-
-void
-taskqueue_drain_timeout(struct taskqueue *queue,
- struct timeout_task *timeout_task)
-{
- /*
- * Set flag to prevent timer from re-starting during drain:
- */
- tq_lock(queue);
- KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
- ("Drain already in progress"));
- timeout_task->f |= DT_DRAIN_IN_PROGRESS;
- tq_unlock(queue);
-
- callout_drain(&timeout_task->c);
- taskqueue_drain(queue, &timeout_task->t);
-
- /*
- * Clear flag to allow timer to re-start:
- */
- tq_lock(queue);
- timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
- tq_unlock(queue);
-}
-
-
-static void
-taskqueue_task_nop_fn(void* context, int pending)
-{
+ TQ_UNLOCK(taskQueue);
}
@@ -309,165 +155,6 @@ taskqueue_drain_all(struct taskqueue *taskQueue)
}
-static void
-taskqueue_enqueue_locked(struct taskqueue *taskQueue, struct task *task)
-{
- /* we don't really support priorities */
- if (task->ta_pending) {
- task->ta_pending++;
- } else {
- list_add_item(&taskQueue->tq_list, task);
- task->ta_pending = 1;
- if ((taskQueue->tq_flags & TQ_FLAGS_BLOCKED) == 0)
- taskQueue->tq_enqueue(taskQueue->tq_arg);
- else
- taskQueue->tq_flags |= TQ_FLAGS_PENDING;
- }
- tq_unlock(taskQueue);
-}
-
-
-int
-taskqueue_enqueue(struct taskqueue *taskQueue, struct task *task)
-{
- tq_lock(taskQueue);
- taskqueue_enqueue_locked(taskQueue, task);
- /* The lock is released inside. */
-
- return 0;
-}
-
-
-static void
-taskqueue_timeout_func(void *arg)
-{
- struct taskqueue *queue;
- struct timeout_task *timeout_task;
-
- timeout_task = arg;
- queue = timeout_task->q;
- KASSERT((timeout_task->f & DT_CALLOUT_ARMED) != 0,
- ("stray timeout ('%s')", timeout_task->q->tq_name));
- timeout_task->f &= ~DT_CALLOUT_ARMED;
- queue->tq_callouts--;
- taskqueue_enqueue_locked(timeout_task->q, &timeout_task->t);
- /* The lock is released inside. */
-}
-
-
-int
-taskqueue_enqueue_timeout(struct taskqueue *queue,
- struct timeout_task *ttask, int _ticks)
-{
- int res;
-
- tq_lock(queue);
- KASSERT(ttask->q == NULL || ttask->q == queue,
- ("Migrated queue"));
- ttask->q = queue;
- res = ttask->t.ta_pending;
- if (ttask->f & DT_DRAIN_IN_PROGRESS) {
- /* Do nothing */
- tq_unlock(queue);
- res = -1;
- } else if (_ticks == 0) {
- tq_unlock(queue);
- taskqueue_enqueue(queue, &ttask->t);
- } else {
- if ((ttask->f & DT_CALLOUT_ARMED) != 0) {
- res++;
- } else {
- queue->tq_callouts++;
- ttask->f |= DT_CALLOUT_ARMED;
- if (_ticks < 0)
- _ticks = -_ticks; /* Ignore overflow. */
- }
- tq_unlock(queue);
- if (_ticks > 0) {
- callout_reset(&ttask->c, _ticks,
- taskqueue_timeout_func, ttask);
- }
- }
- return (res);
-}
-
-
-static int
-taskqueue_cancel_locked(struct taskqueue *queue, struct task *task,
- u_int *pendp)
-{
- if (task->ta_pending > 0)
- list_remove_item(&queue->tq_list, task);
- if (pendp != NULL)
- *pendp = task->ta_pending;
- task->ta_pending = 0;
- return 0;
-}
-
-
-int
-taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp)
-{
- int error;
-
- tq_lock(queue);
- error = taskqueue_cancel_locked(queue, task, pendp);
- tq_unlock(queue);
-
- return (error);
-}
-
-
-int
-taskqueue_cancel_timeout(struct taskqueue *queue,
- struct timeout_task *timeout_task, u_int *pendp)
-{
- u_int pending, pending1;
- int error;
-
- tq_lock(queue);
- pending = !!(callout_stop(&timeout_task->c) > 0);
- error = taskqueue_cancel_locked(queue, &timeout_task->t, &pending1);
- if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
- timeout_task->f &= ~DT_CALLOUT_ARMED;
- queue->tq_callouts--;
- }
- tq_unlock(queue);
-
- if (pendp != NULL)
- *pendp = pending + pending1;
- return (error);
-}
-
-
-void
-taskqueue_block(struct taskqueue *taskQueue)
-{
- if (taskQueue == NULL)
- return;
-
- tq_lock(taskQueue);
- taskQueue->tq_flags |= TQ_FLAGS_BLOCKED;
- tq_unlock(taskQueue);
-}
-
-
-void
-taskqueue_unblock(struct taskqueue *taskQueue)
-{
- if (taskQueue == NULL)
- return;
-
- tq_lock(taskQueue);
- taskQueue->tq_flags &= ~TQ_FLAGS_BLOCKED;
- if (taskQueue->tq_flags & TQ_FLAGS_PENDING) {
- taskQueue->tq_flags &= ~TQ_FLAGS_PENDING;
- taskQueue->tq_enqueue(taskQueue->tq_arg);
- }
- tq_unlock(taskQueue);
-}
-
-
void
taskqueue_thread_enqueue(void *context)
{
@@ -476,44 +163,17 @@ taskqueue_thread_enqueue(void *context)
}
-int
-taskqueue_enqueue_fast(struct taskqueue *taskQueue, struct task *task)
-{
- return taskqueue_enqueue(taskQueue, task);
-}
-
-
-struct taskqueue *
-taskqueue_create_fast(const char *name, int mflags,
- taskqueue_enqueue_fn enqueueFunction, void *context)
-{
- return _taskqueue_create(name, mflags, 1, enqueueFunction, context);
-}
-
-
void
-task_init(struct task *task, int prio, task_fn_t handler, void *context)
+_task_init(struct task *task, int prio, task_fn_t handler, void *context)
{
task->ta_priority = prio;
task->ta_flags = 0;
- task->ta_handler = handler;
- task->ta_argument = context;
+ task->ta_func = handler;
+ task->ta_context = context;
task->ta_pending = 0;
}
-void
-timeout_task_init(struct taskqueue *queue, struct timeout_task *timeout_task,
- int priority, task_fn_t func, void *context)
-{
- TASK_INIT(&timeout_task->t, priority, func, context);
- callout_init_mtx(&timeout_task->c, &queue->tq_mutex,
- CALLOUT_RETURNUNLOCKED);
- timeout_task->q = queue;
- timeout_task->f = 0;
-}
-
-
status_t
init_taskqueues()
{
@@ -546,7 +206,7 @@ init_taskqueues()
}
if (HAIKU_DRIVER_REQUIRES(FBSD_THREAD_TASKQUEUE)) {
- taskqueue_thread = taskqueue_create_fast("thread taskq", 0,
+ taskqueue_thread = taskqueue_create("thread taskq", 0,
taskqueue_thread_enqueue, &taskqueue_thread);
if (taskqueue_thread == NULL) {
status = B_NO_MEMORY;
diff --git a/src/libs/compat/openbsd_network/compat/sys/task.h
b/src/libs/compat/openbsd_network/compat/sys/task.h
index 7f14d1c11a..f4f3eb0df5 100644
--- a/src/libs/compat/openbsd_network/compat/sys/task.h
+++ b/src/libs/compat/openbsd_network/compat/sys/task.h
@@ -20,9 +20,7 @@ struct taskq {
static void
task_set(struct task *t, void (*fn)(void *), void *arg)
{
- t->ta_priority = 0;
- t->ta_handler = fn;
- t->ta_argument = arg;
+ TASK_INIT(t, 0, fn, arg);
}
@@ -41,7 +39,7 @@ task_add(struct taskq* tasq, struct task *w)
w->ta_flags |= TASK_NEEDSGIANT;
if (task_pending(w))
return 0;
- return (taskqueue_enqueue_fast(tq, w) == 0);
+ return (taskqueue_enqueue(tq, w) == 0);
}