subr_taskqueue.c revision 116182
1121936Sharti/*-
2121936Sharti * Copyright (c) 2000 Doug Rabson
3121936Sharti * All rights reserved.
4121936Sharti *
5121936Sharti * Redistribution and use in source and binary forms, with or without
6121936Sharti * modification, are permitted provided that the following conditions
7121936Sharti * are met:
8121936Sharti * 1. Redistributions of source code must retain the above copyright
9121936Sharti *    notice, this list of conditions and the following disclaimer.
10121936Sharti * 2. Redistributions in binary form must reproduce the above copyright
11121936Sharti *    notice, this list of conditions and the following disclaimer in the
12121936Sharti *    documentation and/or other materials provided with the distribution.
13121936Sharti *
14121936Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15121936Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16121936Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17121936Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18121936Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19121936Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20121936Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21121936Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22121936Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23121936Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24121936Sharti * SUCH DAMAGE.
25121936Sharti */
26121936Sharti
27121936Sharti#include <sys/cdefs.h>
28121936Sharti__FBSDID("$FreeBSD: head/sys/kern/subr_taskqueue.c 116182 2003-06-11 00:56:59Z obrien $");
29121936Sharti
30121936Sharti#include <sys/param.h>
31121936Sharti#include <sys/systm.h>
32121936Sharti#include <sys/bus.h>
33121936Sharti#include <sys/interrupt.h>
34121936Sharti#include <sys/kernel.h>
35121936Sharti#include <sys/lock.h>
36121936Sharti#include <sys/malloc.h>
37121936Sharti#include <sys/mutex.h>
38121936Sharti#include <sys/taskqueue.h>
39121936Sharti
40121936Shartistatic MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues");
41121936Sharti
42121936Shartistatic STAILQ_HEAD(taskqueue_list, taskqueue) taskqueue_queues;
43121936Sharti
44121936Shartistatic void	*taskqueue_ih;
45121936Shartistatic void	*taskqueue_giant_ih;
46121936Shartistatic struct mtx taskqueue_queues_mutex;
47121936Sharti
48121936Shartistruct taskqueue {
49121936Sharti	STAILQ_ENTRY(taskqueue)	tq_link;
50121936Sharti	STAILQ_HEAD(, task)	tq_queue;
51121936Sharti	const char		*tq_name;
52121936Sharti	taskqueue_enqueue_fn	tq_enqueue;
53121936Sharti	void			*tq_context;
54121936Sharti	int			tq_draining;
55121936Sharti	struct mtx		tq_mutex;
56121936Sharti};
57121936Sharti
58121936Shartistatic void	init_taskqueue_list(void *data);
59121936Sharti
60121936Shartistatic void
61121936Shartiinit_taskqueue_list(void *data __unused)
62121936Sharti{
63121936Sharti
64121936Sharti	mtx_init(&taskqueue_queues_mutex, "taskqueue list", NULL, MTX_DEF);
65121936Sharti	STAILQ_INIT(&taskqueue_queues);
66121936Sharti}
67121936ShartiSYSINIT(taskqueue_list, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_taskqueue_list,
68121936Sharti    NULL);
69121936Sharti
70121936Shartistruct taskqueue *
71121936Shartitaskqueue_create(const char *name, int mflags,
72121936Sharti		 taskqueue_enqueue_fn enqueue, void *context)
73121936Sharti{
74121936Sharti	struct taskqueue *queue;
75121936Sharti
76121936Sharti	queue = malloc(sizeof(struct taskqueue), M_TASKQUEUE, mflags | M_ZERO);
77121936Sharti	if (!queue)
78121936Sharti		return 0;
79121936Sharti
80121936Sharti	STAILQ_INIT(&queue->tq_queue);
81121936Sharti	queue->tq_name = name;
82121936Sharti	queue->tq_enqueue = enqueue;
83121936Sharti	queue->tq_context = context;
84121936Sharti	queue->tq_draining = 0;
85121936Sharti	mtx_init(&queue->tq_mutex, "taskqueue", NULL, MTX_DEF);
86121936Sharti
87121936Sharti	mtx_lock(&taskqueue_queues_mutex);
88121936Sharti	STAILQ_INSERT_TAIL(&taskqueue_queues, queue, tq_link);
89121936Sharti	mtx_unlock(&taskqueue_queues_mutex);
90121936Sharti
91121936Sharti	return queue;
92121936Sharti}
93121936Sharti
94121936Shartivoid
95121936Shartitaskqueue_free(struct taskqueue *queue)
96121936Sharti{
97121936Sharti
98121936Sharti	mtx_lock(&queue->tq_mutex);
99121936Sharti	KASSERT(queue->tq_draining == 0, ("free'ing a draining taskqueue"));
100121936Sharti	queue->tq_draining = 1;
101121936Sharti	mtx_unlock(&queue->tq_mutex);
102121936Sharti
103121936Sharti	taskqueue_run(queue);
104121936Sharti
105121936Sharti	mtx_lock(&taskqueue_queues_mutex);
106121936Sharti	STAILQ_REMOVE(&taskqueue_queues, queue, taskqueue, tq_link);
107121936Sharti	mtx_unlock(&taskqueue_queues_mutex);
108121936Sharti
109121936Sharti	mtx_destroy(&queue->tq_mutex);
110121936Sharti	free(queue, M_TASKQUEUE);
111121936Sharti}
112121936Sharti
113121936Sharti/*
114121936Sharti * Returns with the taskqueue locked.
115121936Sharti */
116121936Shartistruct taskqueue *
117121936Shartitaskqueue_find(const char *name)
118121936Sharti{
119121936Sharti	struct taskqueue *queue;
120121936Sharti
121121936Sharti	mtx_lock(&taskqueue_queues_mutex);
122121936Sharti	STAILQ_FOREACH(queue, &taskqueue_queues, tq_link) {
123121936Sharti		mtx_lock(&queue->tq_mutex);
124121936Sharti		if (!strcmp(queue->tq_name, name)) {
125121936Sharti			mtx_unlock(&taskqueue_queues_mutex);
126121936Sharti			return queue;
127121936Sharti		}
128121936Sharti		mtx_unlock(&queue->tq_mutex);
129121936Sharti	}
130121936Sharti	mtx_unlock(&taskqueue_queues_mutex);
131121936Sharti	return 0;
132121936Sharti}
133121936Sharti
134121936Shartiint
135121936Shartitaskqueue_enqueue(struct taskqueue *queue, struct task *task)
136121936Sharti{
137121936Sharti	struct task *ins;
138121936Sharti	struct task *prev;
139121936Sharti
140121936Sharti	mtx_lock(&queue->tq_mutex);
141121936Sharti
142121936Sharti	/*
143121936Sharti	 * Don't allow new tasks on a queue which is being freed.
144121936Sharti	 */
145121936Sharti	if (queue->tq_draining) {
146121936Sharti		mtx_unlock(&queue->tq_mutex);
147121936Sharti		return EPIPE;
148121936Sharti	}
149121936Sharti
150121936Sharti	/*
151121936Sharti	 * Count multiple enqueues.
152121936Sharti	 */
153121936Sharti	if (task->ta_pending) {
154121936Sharti		task->ta_pending++;
155121936Sharti		mtx_unlock(&queue->tq_mutex);
156121936Sharti		return 0;
157121936Sharti	}
158121936Sharti
159121936Sharti	/*
160121936Sharti	 * Optimise the case when all tasks have the same priority.
161121936Sharti	 */
162121936Sharti	prev = STAILQ_LAST(&queue->tq_queue, task, ta_link);
163121936Sharti	if (!prev || prev->ta_priority >= task->ta_priority) {
164121936Sharti		STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link);
165121936Sharti	} else {
166121936Sharti		prev = 0;
167121936Sharti		for (ins = STAILQ_FIRST(&queue->tq_queue); ins;
168121936Sharti		     prev = ins, ins = STAILQ_NEXT(ins, ta_link))
169121936Sharti			if (ins->ta_priority < task->ta_priority)
170121936Sharti				break;
171121936Sharti
172121936Sharti		if (prev)
173121936Sharti			STAILQ_INSERT_AFTER(&queue->tq_queue, prev, task, ta_link);
174121936Sharti		else
175121936Sharti			STAILQ_INSERT_HEAD(&queue->tq_queue, task, ta_link);
176121936Sharti	}
177121936Sharti
178121936Sharti	task->ta_pending = 1;
179121936Sharti	if (queue->tq_enqueue)
180121936Sharti		queue->tq_enqueue(queue->tq_context);
181121936Sharti
182121936Sharti	mtx_unlock(&queue->tq_mutex);
183121936Sharti
184121936Sharti	return 0;
185121936Sharti}
186121936Sharti
187121936Shartivoid
188121936Shartitaskqueue_run(struct taskqueue *queue)
189121936Sharti{
190121936Sharti	struct task *task;
191121936Sharti	int pending;
192121936Sharti
193121936Sharti	mtx_lock(&queue->tq_mutex);
194121936Sharti	while (STAILQ_FIRST(&queue->tq_queue)) {
195121936Sharti		/*
196121936Sharti		 * Carefully remove the first task from the queue and
197121936Sharti		 * zero its pending count.
198121936Sharti		 */
199121936Sharti		task = STAILQ_FIRST(&queue->tq_queue);
200121936Sharti		STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link);
201121936Sharti		pending = task->ta_pending;
202121936Sharti		task->ta_pending = 0;
203121936Sharti		mtx_unlock(&queue->tq_mutex);
204121936Sharti
205121936Sharti		task->ta_func(task->ta_context, pending);
206121936Sharti
207121936Sharti		mtx_lock(&queue->tq_mutex);
208121936Sharti	}
209121936Sharti	mtx_unlock(&queue->tq_mutex);
210121936Sharti}
211121936Sharti
212121936Shartistatic void
213121936Shartitaskqueue_swi_enqueue(void *context)
214121936Sharti{
215121936Sharti	swi_sched(taskqueue_ih, 0);
216121936Sharti}
217121936Sharti
218121936Shartistatic void
219121936Shartitaskqueue_swi_run(void *dummy)
220121936Sharti{
221121936Sharti	taskqueue_run(taskqueue_swi);
222121936Sharti}
223121936Sharti
224121936Shartistatic void
225121936Shartitaskqueue_swi_giant_enqueue(void *context)
226121936Sharti{
227121936Sharti	swi_sched(taskqueue_giant_ih, 0);
228121936Sharti}
229121936Sharti
230121936Shartistatic void
231121936Shartitaskqueue_swi_giant_run(void *dummy)
232121936Sharti{
233121936Sharti	taskqueue_run(taskqueue_swi_giant);
234121936Sharti}
235121936Sharti
236121936ShartiTASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, 0,
237121936Sharti		 swi_add(NULL, "task queue", taskqueue_swi_run, NULL, SWI_TQ,
238121936Sharti		     INTR_MPSAFE, &taskqueue_ih));
239121936Sharti
240121936ShartiTASKQUEUE_DEFINE(swi_giant, taskqueue_swi_giant_enqueue, 0,
241121936Sharti		 swi_add(NULL, "Giant task queue", taskqueue_swi_giant_run,
242121936Sharti		     NULL, SWI_TQ_GIANT, 0, &taskqueue_giant_ih));
243121936Sharti