ldb:kv_index: use subtransaction_cancel in transaction_cancel
[Samba.git] / lib / pthreadpool / tests_cmocka.c
blobe6af8849f01ddf7a8d7e3187e3443280ea165a86
1 /*
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/>.
20 #include <errno.h>
21 #include <pthread.h>
22 #include <setjmp.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
27 #include <talloc.h>
28 #include <tevent.h>
29 #include <pthreadpool_tevent.h>
31 #include <cmocka.h>
32 #include <poll.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;
44 int ret;
45 size_t max_threads;
47 t = talloc_zero(NULL, struct pthreadpool_tevent_test);
48 assert_non_null(t);
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);
71 *state = t;
73 return 0;
76 static int teardown_pthreadpool_tevent(void **state)
78 struct pthreadpool_tevent_test *t = *state;
80 TALLOC_FREE(t);
82 return 0;
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)
93 int error;
95 error = mock_type(int);
96 if (error != 0) {
97 return error;
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,
112 bool *executed,
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;
119 bool ok;
120 int ret;
122 *executed = false;
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);
131 if (req == NULL) {
132 fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
133 return ENOMEM;
136 ok = tevent_req_poll(req, ev);
137 if (!ok) {
138 ret = errno;
139 fprintf(stderr, "tevent_req_poll failed: %s\n",
140 strerror(ret));
141 *executed = !pthread_equal(worker_thread, zero_thread);
142 *in_main_thread = pthread_equal(worker_thread, main_thread);
143 return ret;
147 ret = pthreadpool_tevent_job_recv(req);
148 TALLOC_FREE(req);
149 *executed = !pthread_equal(worker_thread, zero_thread);
150 *in_main_thread = pthread_equal(worker_thread, main_thread);
151 if (ret != 0) {
152 fprintf(stderr, "tevent_req_recv failed: %s\n",
153 strerror(ret));
154 return ret;
157 return 0;
160 static void test_create(void **state)
162 struct pthreadpool_tevent_test *t = *state;
163 bool executed;
164 bool in_main_thread;
165 int ret;
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);
202 poll(NULL, 0, 10);
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);
223 poll(NULL, 0, 10);
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);