2 Unix SMB/CIFS implementation.
3 Regular background jobs as forked helpers
4 Copyright (C) Volker Lendecke 2012
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 "lib/util/tevent_ntstatus.h"
22 #include "lib/async_req/async_sock.h"
23 #include "include/messages.h"
24 #include "background.h"
26 struct background_job_state
{
27 struct tevent_context
*ev
;
28 struct messaging_context
*msg
;
29 uint32_t *trigger_msgs
;
30 size_t num_trigger_msgs
;
31 bool parent_longlived
;
32 int (*fn
)(void *private_data
);
35 struct tevent_req
*wakeup_req
;
37 struct tevent_req
*pipe_req
;
40 static int background_job_state_destructor(struct background_job_state
*s
);
41 static void background_job_waited(struct tevent_req
*subreq
);
42 static void background_job_done(struct tevent_req
*subreq
);
43 static void background_job_trigger(
44 struct messaging_context
*msg
, void *private_data
, uint32_t msg_type
,
45 struct server_id server_id
, DATA_BLOB
*data
);
47 struct tevent_req
*background_job_send(TALLOC_CTX
*mem_ctx
,
48 struct tevent_context
*ev
,
49 struct messaging_context
*msg
,
50 uint32_t *trigger_msgs
,
51 size_t num_trigger_msgs
,
52 time_t initial_wait_sec
,
53 int (*fn
)(void *private_data
),
56 struct tevent_req
*req
, *subreq
;
57 struct background_job_state
*state
;
60 req
= tevent_req_create(mem_ctx
, &state
,
61 struct background_job_state
);
69 if (num_trigger_msgs
!= 0) {
70 state
->trigger_msgs
= (uint32_t *)talloc_memdup(
72 sizeof(uint32_t) * num_trigger_msgs
);
73 if (tevent_req_nomem(state
->trigger_msgs
, req
)) {
74 return tevent_req_post(req
, ev
);
76 state
->num_trigger_msgs
= num_trigger_msgs
;
80 state
->private_data
= private_data
;
83 talloc_set_destructor(state
, background_job_state_destructor
);
85 for (i
=0; i
<num_trigger_msgs
; i
++) {
87 status
= messaging_register(msg
, state
, trigger_msgs
[i
],
88 background_job_trigger
);
89 if (tevent_req_nterror(req
, status
)) {
90 return tevent_req_post(req
, ev
);
94 subreq
= tevent_wakeup_send(
95 state
, state
->ev
, timeval_current_ofs(initial_wait_sec
, 0));
96 if (tevent_req_nomem(subreq
, req
)) {
97 return tevent_req_post(req
, ev
);
99 tevent_req_set_callback(subreq
, background_job_waited
, req
);
100 state
->wakeup_req
= subreq
;
104 static int background_job_state_destructor(struct background_job_state
*state
)
108 TALLOC_FREE(state
->pipe_req
);
109 if (state
->pipe_fd
!= -1) {
110 close(state
->pipe_fd
);
114 for (i
=0; i
<state
->num_trigger_msgs
; i
++) {
115 messaging_deregister(state
->msg
, state
->trigger_msgs
[i
],
122 static void background_job_trigger(
123 struct messaging_context
*msg
, void *private_data
, uint32_t msg_type
,
124 struct server_id server_id
, DATA_BLOB
*data
)
126 struct background_job_state
*state
= talloc_get_type_abort(
127 private_data
, struct background_job_state
);
129 if (state
->wakeup_req
== NULL
) {
132 if (!tevent_req_set_endtime(state
->wakeup_req
, state
->ev
,
134 DEBUG(10, ("tevent_req_set_endtime failed\n"));
138 static void background_job_waited(struct tevent_req
*subreq
)
140 struct tevent_req
*req
= tevent_req_callback_data(
141 subreq
, struct tevent_req
);
142 struct background_job_state
*state
= tevent_req_data(
143 req
, struct background_job_state
);
148 ret
= tevent_wakeup_recv(subreq
);
150 state
->wakeup_req
= NULL
;
152 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
158 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
167 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
179 status
= reinit_after_fork(state
->msg
, state
->ev
, true, NULL
);
180 if (NT_STATUS_IS_OK(status
)) {
181 res
= state
->fn(state
->private_data
);
185 written
= write(fds
[1], &res
, sizeof(res
));
191 * No TALLOC_FREE here, messaging_parent_dgm_cleanup_init for
192 * example calls background_job_send with "messaging_context"
193 * as talloc parent. Thus "state" will be freed with the
194 * following talloc_free will have removed "state" when it
195 * returns. TALLOC_FREE will then write a NULL into free'ed
196 * memory. talloc_free() is required although we immediately
197 * exit, the messaging_context's destructor will want to clean
200 talloc_free(state
->msg
);
207 state
->pipe_fd
= fds
[0];
209 subreq
= read_packet_send(state
, state
->ev
, state
->pipe_fd
,
210 sizeof(int), NULL
, NULL
);
211 if (tevent_req_nomem(subreq
, req
)) {
214 tevent_req_set_callback(subreq
, background_job_done
, req
);
215 state
->pipe_req
= subreq
;
218 static void background_job_done(struct tevent_req
*subreq
)
220 struct tevent_req
*req
= tevent_req_callback_data(
221 subreq
, struct tevent_req
);
222 struct background_job_state
*state
= tevent_req_data(
223 req
, struct background_job_state
);
229 state
->pipe_req
= NULL
;
231 ret
= read_packet_recv(subreq
, talloc_tos(), &buf
, &err
);
234 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
237 close(state
->pipe_fd
);
239 memcpy(&wait_secs
, buf
, sizeof(wait_secs
));
240 if (wait_secs
== -1) {
241 tevent_req_done(req
);
244 subreq
= tevent_wakeup_send(
245 state
, state
->ev
, timeval_current_ofs(wait_secs
, 0));
246 if (tevent_req_nomem(subreq
, req
)) {
249 tevent_req_set_callback(subreq
, background_job_waited
, req
);
250 state
->wakeup_req
= subreq
;
253 NTSTATUS
background_job_recv(struct tevent_req
*req
)
255 return tevent_req_simple_recv_ntstatus(req
);