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();