npf_worker.c revision 1.1 1 1.1 rmind /* $NetBSD: npf_worker.c,v 1.1 2013/06/02 02:20:04 rmind Exp $ */
2 1.1 rmind
3 1.1 rmind /*-
4 1.1 rmind * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
5 1.1 rmind * All rights reserved.
6 1.1 rmind *
7 1.1 rmind * This material is based upon work partially supported by The
8 1.1 rmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9 1.1 rmind *
10 1.1 rmind * Redistribution and use in source and binary forms, with or without
11 1.1 rmind * modification, are permitted provided that the following conditions
12 1.1 rmind * are met:
13 1.1 rmind * 1. Redistributions of source code must retain the above copyright
14 1.1 rmind * notice, this list of conditions and the following disclaimer.
15 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 rmind * notice, this list of conditions and the following disclaimer in the
17 1.1 rmind * documentation and/or other materials provided with the distribution.
18 1.1 rmind *
19 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 rmind * POSSIBILITY OF SUCH DAMAGE.
30 1.1 rmind */
31 1.1 rmind
32 1.1 rmind #include <sys/cdefs.h>
33 1.1 rmind __KERNEL_RCSID(0, "$NetBSD: npf_worker.c,v 1.1 2013/06/02 02:20:04 rmind Exp $");
34 1.1 rmind
35 1.1 rmind #include <sys/param.h>
36 1.1 rmind #include <sys/types.h>
37 1.1 rmind
38 1.1 rmind #include <sys/mutex.h>
39 1.1 rmind #include <sys/kernel.h>
40 1.1 rmind #include <sys/kthread.h>
41 1.1 rmind
42 1.1 rmind #include "npf_impl.h"
43 1.1 rmind
44 1.1 rmind #define NPF_MAX_WORKS 4
45 1.1 rmind #define WORKER_INTERVAL mstohz(5 * 1000)
46 1.1 rmind
47 1.1 rmind static kmutex_t worker_lock;
48 1.1 rmind static kcondvar_t worker_cv;
49 1.1 rmind static kcondvar_t worker_event_cv;
50 1.1 rmind static lwp_t * worker_lwp;
51 1.1 rmind static uint64_t worker_loop;
52 1.1 rmind
53 1.1 rmind static npf_workfunc_t work_funcs[NPF_MAX_WORKS];
54 1.1 rmind
55 1.1 rmind static void npf_worker(void *) __dead;
56 1.1 rmind
57 1.1 rmind int
58 1.1 rmind npf_worker_sysinit(void)
59 1.1 rmind {
60 1.1 rmind mutex_init(&worker_lock, MUTEX_DEFAULT, IPL_SOFTNET);
61 1.1 rmind cv_init(&worker_cv, "npfgccv");
62 1.1 rmind cv_init(&worker_event_cv, "npfevcv");
63 1.1 rmind worker_lwp = (lwp_t *)0xdeadbabe;
64 1.1 rmind worker_loop = 1;
65 1.1 rmind
66 1.1 rmind if (kthread_create(PRI_NONE, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
67 1.1 rmind npf_worker, NULL, &worker_lwp, "npfgc")) {
68 1.1 rmind return ENOMEM;
69 1.1 rmind }
70 1.1 rmind return 0;
71 1.1 rmind }
72 1.1 rmind
73 1.1 rmind void
74 1.1 rmind npf_worker_sysfini(void)
75 1.1 rmind {
76 1.1 rmind lwp_t *l = worker_lwp;
77 1.1 rmind
78 1.1 rmind /* Notify the worker and wait for the exit. */
79 1.1 rmind mutex_enter(&worker_lock);
80 1.1 rmind worker_lwp = NULL;
81 1.1 rmind cv_broadcast(&worker_cv);
82 1.1 rmind mutex_exit(&worker_lock);
83 1.1 rmind kthread_join(l);
84 1.1 rmind
85 1.1 rmind /* LWP has exited, destroy the structures. */
86 1.1 rmind cv_destroy(&worker_cv);
87 1.1 rmind cv_destroy(&worker_event_cv);
88 1.1 rmind mutex_destroy(&worker_lock);
89 1.1 rmind }
90 1.1 rmind
91 1.1 rmind void
92 1.1 rmind npf_worker_signal(void)
93 1.1 rmind {
94 1.1 rmind mutex_enter(&worker_lock);
95 1.1 rmind cv_signal(&worker_cv);
96 1.1 rmind mutex_exit(&worker_lock);
97 1.1 rmind }
98 1.1 rmind
99 1.1 rmind static bool
100 1.1 rmind npf_worker_testset(npf_workfunc_t find, npf_workfunc_t set)
101 1.1 rmind {
102 1.1 rmind for (u_int i = 0; i < NPF_MAX_WORKS; i++) {
103 1.1 rmind if (work_funcs[i] == find) {
104 1.1 rmind work_funcs[i] = set;
105 1.1 rmind return true;
106 1.1 rmind }
107 1.1 rmind }
108 1.1 rmind return false;
109 1.1 rmind }
110 1.1 rmind
111 1.1 rmind void
112 1.1 rmind npf_worker_register(npf_workfunc_t func)
113 1.1 rmind {
114 1.1 rmind mutex_enter(&worker_lock);
115 1.1 rmind npf_worker_testset(NULL, func);
116 1.1 rmind mutex_exit(&worker_lock);
117 1.1 rmind }
118 1.1 rmind
119 1.1 rmind void
120 1.1 rmind npf_worker_unregister(npf_workfunc_t func)
121 1.1 rmind {
122 1.1 rmind uint64_t l = worker_loop;
123 1.1 rmind
124 1.1 rmind mutex_enter(&worker_lock);
125 1.1 rmind npf_worker_testset(func, NULL);
126 1.1 rmind while (worker_loop == l) {
127 1.1 rmind cv_signal(&worker_cv);
128 1.1 rmind cv_wait(&worker_event_cv, &worker_lock);
129 1.1 rmind }
130 1.1 rmind mutex_exit(&worker_lock);
131 1.1 rmind }
132 1.1 rmind
133 1.1 rmind static void
134 1.1 rmind npf_worker(void *arg)
135 1.1 rmind {
136 1.1 rmind for (;;) {
137 1.1 rmind const bool finish = (worker_lwp == NULL);
138 1.1 rmind u_int i = NPF_MAX_WORKS;
139 1.1 rmind npf_workfunc_t work;
140 1.1 rmind
141 1.1 rmind /* Run the jobs. */
142 1.1 rmind while (i--) {
143 1.1 rmind if ((work = work_funcs[i]) != NULL) {
144 1.1 rmind work();
145 1.1 rmind }
146 1.1 rmind }
147 1.1 rmind
148 1.1 rmind /* Exit if requested and all jobs are done. */
149 1.1 rmind if (finish) {
150 1.1 rmind break;
151 1.1 rmind }
152 1.1 rmind
153 1.1 rmind /* Sleep and periodically wake up, unless we get notified. */
154 1.1 rmind mutex_enter(&worker_lock);
155 1.1 rmind worker_loop++;
156 1.1 rmind cv_broadcast(&worker_event_cv);
157 1.1 rmind cv_timedwait(&worker_cv, &worker_lock, WORKER_INTERVAL);
158 1.1 rmind mutex_exit(&worker_lock);
159 1.1 rmind }
160 1.1 rmind kthread_exit(0);
161 1.1 rmind }
162