2 * Unix SMB/CIFS implementation.
3 * cmocka tests for thread pool implementation
4 * Copyright (C) Christof Schmitt 2017
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <pthreadpool_tevent.h>
34 struct pthreadpool_tevent_test
{
35 struct tevent_context
*ev
;
36 struct pthreadpool_tevent
*upool
;
37 struct pthreadpool_tevent
*spool
;
38 struct pthreadpool_tevent
*opool
;
41 static int setup_pthreadpool_tevent(void **state
)
43 struct pthreadpool_tevent_test
*t
;
47 t
= talloc_zero(NULL
, struct pthreadpool_tevent_test
);
50 t
->ev
= tevent_context_init(t
);
51 assert_non_null(t
->ev
);
53 ret
= pthreadpool_tevent_init(t
->ev
, UINT_MAX
, &t
->upool
);
54 assert_int_equal(ret
, 0);
56 max_threads
= pthreadpool_tevent_max_threads(t
->upool
);
57 assert_int_equal(max_threads
, UINT_MAX
);
59 ret
= pthreadpool_tevent_init(t
->ev
, 1, &t
->opool
);
60 assert_int_equal(ret
, 0);
62 max_threads
= pthreadpool_tevent_max_threads(t
->opool
);
63 assert_int_equal(max_threads
, 1);
65 ret
= pthreadpool_tevent_init(t
->ev
, 0, &t
->spool
);
66 assert_int_equal(ret
, 0);
68 max_threads
= pthreadpool_tevent_max_threads(t
->spool
);
69 assert_int_equal(max_threads
, 0);
76 static int teardown_pthreadpool_tevent(void **state
)
78 struct pthreadpool_tevent_test
*t
= *state
;
85 int __wrap_pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
86 void *(*start_routine
) (void *), void *arg
);
87 int __real_pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
88 void *(*start_routine
) (void *), void *arg
);
90 int __wrap_pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
91 void *(*start_routine
) (void *), void *arg
)
95 error
= mock_type(int);
100 return __real_pthread_create(thread
, attr
, start_routine
, arg
);
103 static void test_job_threadid(void *ptr
)
105 pthread_t
*threadid
= ptr
;
107 *threadid
= pthread_self();
110 static int test_create_do(struct tevent_context
*ev
,
111 struct pthreadpool_tevent
*pool
,
113 bool *in_main_thread
)
115 struct tevent_req
*req
;
116 pthread_t zero_thread
;
117 pthread_t main_thread
;
118 pthread_t worker_thread
;
123 *in_main_thread
= false;
125 memset(&zero_thread
, 0, sizeof(zero_thread
));
126 main_thread
= pthread_self();
127 worker_thread
= zero_thread
;
129 req
= pthreadpool_tevent_job_send(
130 ev
, ev
, pool
, test_job_threadid
, &worker_thread
);
132 fprintf(stderr
, "pthreadpool_tevent_job_send failed\n");
136 ok
= tevent_req_poll(req
, ev
);
139 fprintf(stderr
, "tevent_req_poll failed: %s\n",
141 *executed
= !pthread_equal(worker_thread
, zero_thread
);
142 *in_main_thread
= pthread_equal(worker_thread
, main_thread
);
147 ret
= pthreadpool_tevent_job_recv(req
);
149 *executed
= !pthread_equal(worker_thread
, zero_thread
);
150 *in_main_thread
= pthread_equal(worker_thread
, main_thread
);
152 fprintf(stderr
, "tevent_req_recv failed: %s\n",
160 static void test_create(void **state
)
162 struct pthreadpool_tevent_test
*t
= *state
;
168 * When pthreadpool cannot create the first worker thread,
169 * this job will run in the sync fallback in the main thread.
171 will_return(__wrap_pthread_create
, EAGAIN
);
172 ret
= test_create_do(t
->ev
, t
->upool
, &executed
, &in_main_thread
);
173 assert_int_equal(ret
, EAGAIN
);
174 assert_false(executed
);
175 assert_false(in_main_thread
);
178 * The sync pool won't trigger pthread_create()
179 * It will be triggered by the one pool.
181 will_return(__wrap_pthread_create
, EAGAIN
);
183 ret
= test_create_do(t
->ev
, t
->spool
, &executed
, &in_main_thread
);
184 assert_int_equal(ret
, 0);
185 assert_true(executed
);
186 assert_true(in_main_thread
);
188 ret
= test_create_do(t
->ev
, t
->opool
, &executed
, &in_main_thread
);
189 assert_int_equal(ret
, EAGAIN
);
190 assert_false(executed
);
191 assert_false(in_main_thread
);
194 * When a thread can be created, the job will run in the worker thread.
196 will_return(__wrap_pthread_create
, 0);
197 ret
= test_create_do(t
->ev
, t
->upool
, &executed
, &in_main_thread
);
198 assert_int_equal(ret
, 0);
199 assert_true(executed
);
200 assert_false(in_main_thread
);
205 * Workerthread will still be active for a second; immediately
206 * running another job will also use the worker thread, even
207 * if a new thread cannot be created.
209 ret
= test_create_do(t
->ev
, t
->upool
, &executed
, &in_main_thread
);
210 assert_int_equal(ret
, 0);
211 assert_true(executed
);
212 assert_false(in_main_thread
);
215 * When a thread can be created, the job will run in the worker thread.
217 will_return(__wrap_pthread_create
, 0);
218 ret
= test_create_do(t
->ev
, t
->opool
, &executed
, &in_main_thread
);
219 assert_int_equal(ret
, 0);
220 assert_true(executed
);
221 assert_false(in_main_thread
);
226 * Workerthread will still be active for a second; immediately
227 * running another job will also use the worker thread, even
228 * if a new thread cannot be created.
230 ret
= test_create_do(t
->ev
, t
->opool
, &executed
, &in_main_thread
);
231 assert_int_equal(ret
, 0);
232 assert_true(executed
);
233 assert_false(in_main_thread
);
236 int main(int argc
, char **argv
)
238 const struct CMUnitTest tests
[] = {
239 cmocka_unit_test_setup_teardown(test_create
,
240 setup_pthreadpool_tevent
,
241 teardown_pthreadpool_tevent
),
244 cmocka_set_message_output(CM_OUTPUT_SUBUNIT
);
246 return cmocka_run_group_tests(tests
, NULL
, NULL
);