2 * Unix SMB/CIFS implementation.
3 * threadpool implementation based on pthreads
4 * Copyright (C) Volker Lendecke 2009,2011
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/>.
21 #include "pthreadpool_tevent.h"
22 #include "pthreadpool.h"
23 #include "lib/util/tevent_unix.h"
24 #include "lib/util/dlinklist.h"
26 struct pthreadpool_tevent_job_state
;
28 struct pthreadpool_tevent
{
29 struct pthreadpool
*pool
;
31 struct pthreadpool_tevent_job_state
*jobs
;
34 static int pthreadpool_tevent_destructor(struct pthreadpool_tevent
*pool
);
36 static int pthreadpool_tevent_job_signal(int jobid
,
37 void (*job_fn
)(void *private_data
),
38 void *job_private_data
,
41 int pthreadpool_tevent_init(TALLOC_CTX
*mem_ctx
, unsigned max_threads
,
42 struct pthreadpool_tevent
**presult
)
44 struct pthreadpool_tevent
*pool
;
47 pool
= talloc_zero(mem_ctx
, struct pthreadpool_tevent
);
52 ret
= pthreadpool_init(max_threads
, &pool
->pool
,
53 pthreadpool_tevent_job_signal
, pool
);
59 talloc_set_destructor(pool
, pthreadpool_tevent_destructor
);
65 static int pthreadpool_tevent_destructor(struct pthreadpool_tevent
*pool
)
69 ret
= pthreadpool_destroy(pool
->pool
);
75 if (pool
->jobs
!= NULL
) {
82 struct pthreadpool_tevent_job_state
{
83 struct pthreadpool_tevent_job_state
*prev
, *next
;
84 struct pthreadpool_tevent
*pool
;
85 struct tevent_context
*ev
;
86 struct tevent_threaded_context
*tctx
;
87 struct tevent_immediate
*im
;
88 struct tevent_req
*req
;
90 void (*fn
)(void *private_data
);
94 static void pthreadpool_tevent_job_fn(void *private_data
);
95 static void pthreadpool_tevent_job_done(struct tevent_context
*ctx
,
96 struct tevent_immediate
*im
,
99 static int pthreadpool_tevent_job_state_destructor(
100 struct pthreadpool_tevent_job_state
*state
)
102 if (state
->pool
== NULL
) {
107 * We should never be called with state->req == NULL,
108 * state->pool must be cleared before the 2nd talloc_free().
110 if (state
->req
== NULL
) {
115 * We need to reparent to a long term context.
117 (void)talloc_reparent(state
->req
, state
->pool
, state
);
122 struct tevent_req
*pthreadpool_tevent_job_send(
123 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
124 struct pthreadpool_tevent
*pool
,
125 void (*fn
)(void *private_data
), void *private_data
)
127 struct tevent_req
*req
;
128 struct pthreadpool_tevent_job_state
*state
;
131 req
= tevent_req_create(mem_ctx
, &state
,
132 struct pthreadpool_tevent_job_state
);
140 state
->private_data
= private_data
;
142 state
->im
= tevent_create_immediate(state
);
143 if (tevent_req_nomem(state
->im
, req
)) {
144 return tevent_req_post(req
, ev
);
148 state
->tctx
= tevent_threaded_context_create(state
, ev
);
149 if (state
->tctx
== NULL
&& errno
== ENOSYS
) {
151 * Samba build with pthread support but
154 tevent_req_error(req
, ENOSYS
);
155 return tevent_req_post(req
, ev
);
157 if (tevent_req_nomem(state
->tctx
, req
)) {
158 return tevent_req_post(req
, ev
);
162 ret
= pthreadpool_add_job(pool
->pool
, 0,
163 pthreadpool_tevent_job_fn
,
165 if (tevent_req_error(req
, ret
)) {
166 return tevent_req_post(req
, ev
);
170 * Once the job is scheduled, we need to protect
173 talloc_set_destructor(state
, pthreadpool_tevent_job_state_destructor
);
175 DLIST_ADD_END(pool
->jobs
, state
);
180 static void pthreadpool_tevent_job_fn(void *private_data
)
182 struct pthreadpool_tevent_job_state
*state
= talloc_get_type_abort(
183 private_data
, struct pthreadpool_tevent_job_state
);
184 state
->fn(state
->private_data
);
187 static int pthreadpool_tevent_job_signal(int jobid
,
188 void (*job_fn
)(void *private_data
),
189 void *job_private_data
,
192 struct pthreadpool_tevent_job_state
*state
= talloc_get_type_abort(
193 job_private_data
, struct pthreadpool_tevent_job_state
);
195 if (state
->tctx
!= NULL
) {
196 /* with HAVE_PTHREAD */
197 tevent_threaded_schedule_immediate(state
->tctx
, state
->im
,
198 pthreadpool_tevent_job_done
,
201 /* without HAVE_PTHREAD */
202 tevent_schedule_immediate(state
->im
, state
->ev
,
203 pthreadpool_tevent_job_done
,
210 static void pthreadpool_tevent_job_done(struct tevent_context
*ctx
,
211 struct tevent_immediate
*im
,
214 struct pthreadpool_tevent_job_state
*state
= talloc_get_type_abort(
215 private_data
, struct pthreadpool_tevent_job_state
);
217 DLIST_REMOVE(state
->pool
->jobs
, state
);
220 TALLOC_FREE(state
->tctx
);
222 if (state
->req
== NULL
) {
224 * There was a talloc_free() state->req
225 * while the job was pending,
226 * which mean we're reparented on a longterm
229 * We just cleanup here...
235 tevent_req_done(state
->req
);
238 int pthreadpool_tevent_job_recv(struct tevent_req
*req
)
240 return tevent_req_simple_recv_unix(req
);