4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
33 #include <sys/debug.h>
35 #include <sys/dmu_ctl.h>
36 #include <sys/dmu_ctl_impl.h>
38 static dctl_thr_info_t thr_pool = {
39 .dti_mtx = PTHREAD_MUTEX_INITIALIZER
44 * Callers must acquire thr_pool.dti_mtx first.
46 static int dctl_thr_create(int n)
48 dctl_thr_info_t *p = &thr_pool;
51 for (int i = 0; i < n; i++) {
52 wthr_info_t *thr = malloc(sizeof(wthr_info_t));
56 thr->wthr_exit = B_FALSE;
57 thr->wthr_free = B_TRUE;
59 error = pthread_create(&thr->wthr_id, NULL, p->dti_thr_func,
68 list_insert_tail(&p->dti_list, thr);
74 * Mark the thread as dead.
75 * Must be called right before exiting the main thread function.
77 void dctl_thr_die(wthr_info_t *thr)
79 dctl_thr_info_t *p = &thr_pool;
81 thr->wthr_exit = B_TRUE;
82 dctl_thr_rebalance(thr, B_FALSE);
84 pthread_mutex_lock(&p->dti_mtx);
86 list_remove(&p->dti_list, thr);
87 list_insert_tail(&p->dti_join_list, thr);
89 pthread_mutex_unlock(&p->dti_mtx);
93 * Clean-up dead threads.
97 dctl_thr_info_t *p = &thr_pool;
100 pthread_mutex_lock(&p->dti_mtx);
102 while ((thr = list_head(&p->dti_join_list))) {
103 list_remove(&p->dti_join_list, thr);
105 ASSERT(!pthread_equal(thr->wthr_id, pthread_self()));
108 * This should not block because all the threads
109 * on this list should have died already.
111 * pthread_join() can only return an error if
112 * we made a programming mistake.
114 VERIFY(pthread_join(thr->wthr_id, NULL) == 0);
116 ASSERT(thr->wthr_exit);
117 ASSERT(!thr->wthr_free);
122 pthread_mutex_unlock(&p->dti_mtx);
126 * Adjust the number of free threads in the pool and the thread status.
128 * Callers must acquire thr_pool.dti_mtx first.
130 static void dctl_thr_adjust_free(wthr_info_t *thr, boolean_t set_free)
132 dctl_thr_info_t *p = &thr_pool;
134 ASSERT(p->dti_free >= 0);
136 if (!thr->wthr_free && set_free)
138 else if (thr->wthr_free && !set_free)
141 ASSERT(p->dti_free >= 0);
143 thr->wthr_free = set_free;
147 * Rebalance threads. Also adjusts the free status of the thread.
148 * Will set the thread exit flag if the number of free threads is above
151 void dctl_thr_rebalance(wthr_info_t *thr, boolean_t set_free)
153 dctl_thr_info_t *p = &thr_pool;
155 pthread_mutex_lock(&p->dti_mtx);
157 if (p->dti_exit || p->dti_free > p->dti_max_free)
158 thr->wthr_exit = B_TRUE;
163 dctl_thr_adjust_free(thr, set_free);
165 if (!p->dti_exit && p->dti_free == 0)
168 pthread_mutex_unlock(&p->dti_mtx);
172 * Stop the thread pool.
174 * This can take a while since it actually waits for all threads to exit.
176 void dctl_thr_pool_stop()
178 dctl_thr_info_t *p = &thr_pool;
182 pthread_mutex_lock(&p->dti_mtx);
184 ASSERT(!p->dti_exit);
185 p->dti_exit = B_TRUE;
187 /* Let's flag the threads first */
188 thr = list_head(&p->dti_list);
189 while (thr != NULL) {
190 thr->wthr_exit = B_TRUE;
191 dctl_thr_adjust_free(thr, B_FALSE);
193 thr = list_next(&p->dti_list, thr);
196 pthread_mutex_unlock(&p->dti_mtx);
198 /* Now let's wait for them to exit */
200 ts.tv_nsec = 50000000; /* 50ms */
202 nanosleep(&ts, NULL);
204 pthread_mutex_lock(&p->dti_mtx);
205 thr = list_head(&p->dti_list);
206 pthread_mutex_unlock(&p->dti_mtx);
209 } while(thr != NULL);
211 ASSERT(p->dti_free == 0);
213 ASSERT(list_is_empty(&p->dti_list));
214 ASSERT(list_is_empty(&p->dti_join_list));
216 list_destroy(&p->dti_list);
217 list_destroy(&p->dti_join_list);
221 * Create thread pool.
223 * If at least one thread creation fails, it will stop all previous
224 * threads and return a non-zero value.
226 int dctl_thr_pool_create(int min_thr, int max_free_thr,
227 thr_func_t *thr_func)
230 dctl_thr_info_t *p = &thr_pool;
232 ASSERT(p->dti_free == 0);
234 /* Initialize global variables */
235 p->dti_min = min_thr;
236 p->dti_max_free = max_free_thr;
237 p->dti_exit = B_FALSE;
238 p->dti_thr_func = thr_func;
240 list_create(&p->dti_list, sizeof(wthr_info_t), offsetof(wthr_info_t,
242 list_create(&p->dti_join_list, sizeof(wthr_info_t),
243 offsetof(wthr_info_t, wthr_node));
245 pthread_mutex_lock(&p->dti_mtx);
246 error = dctl_thr_create(min_thr);
247 pthread_mutex_unlock(&p->dti_mtx);
250 dctl_thr_pool_stop();