mdssvc: move calling mds_es_search_set_pending() to mds_es_next_search_trigger()
[Samba.git] / source4 / samba / process_prefork.c
blobf2927efbb06d1f925c6295c1f50eeaf3012b0297
1 /*
2 Unix SMB/CIFS implementation.
4 process model: prefork (n client connections per process)
6 Copyright (C) Andrew Tridgell 1992-2005
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
8 Copyright (C) Stefan (metze) Metzmacher 2004
9 Copyright (C) Andrew Bartlett 2008 <abartlet@samba.org>
10 Copyright (C) David Disseldorp 2008 <ddiss@sgi.com>
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * The pre-fork process model distributes the server workload amongst several
27 * designated worker threads (e.g. 'prefork-worker-ldap-0',
28 * 'prefork-worker-ldap-1', etc). The number of worker threads is controlled
29 * by the 'prefork children' conf setting. The worker threads are controlled
30 * by a prefork master process (e.g. 'prefork-master-ldap'). The prefork master
31 * doesn't handle the server workload (i.e. processing messages) itself, but is
32 * responsible for restarting workers if they exit unexpectedly. The top-level
33 * samba process is responsible for restarting the master process if it exits.
35 #include "includes.h"
36 #include <unistd.h>
38 #include "lib/events/events.h"
39 #include "lib/messaging/messaging.h"
40 #include "lib/socket/socket.h"
41 #include "samba/process_model.h"
42 #include "cluster/cluster.h"
43 #include "param/param.h"
44 #include "ldb_wrap.h"
45 #include "lib/util/tfork.h"
46 #include "lib/messaging/irpc.h"
47 #include "lib/util/util_process.h"
48 #include "server_util.h"
50 #define min(a, b) (((a) < (b)) ? (a) : (b))
52 NTSTATUS process_model_prefork_init(void);
53 static void prefork_new_task(
54 struct tevent_context *ev,
55 struct loadparm_context *lp_ctx,
56 const char *service_name,
57 struct task_server *(*new_task_fn)(struct tevent_context *,
58 struct loadparm_context *lp_ctx,
59 struct server_id,
60 void *,
61 void *),
62 void *private_data,
63 const struct service_details *service_details,
64 int from_parent_fd);
65 static void prefork_fork_worker(struct task_server *task,
66 struct tevent_context *ev,
67 struct tevent_context *ev2,
68 struct loadparm_context *lp_ctx,
69 const struct service_details *service_details,
70 const char *service_name,
71 int control_pipe[2],
72 unsigned restart_delay,
73 struct process_details *pd);
74 static void prefork_child_pipe_handler(struct tevent_context *ev,
75 struct tevent_fd *fde,
76 uint16_t flags,
77 void *private_data);
78 static void setup_handlers(struct tevent_context *ev,
79 struct loadparm_context *lp_ctx,
80 int from_parent_fd);
83 * State needed to restart the master process or a worker process if they
84 * terminate early.
86 struct master_restart_context {
87 struct task_server *(*new_task_fn)(struct tevent_context *,
88 struct loadparm_context *lp_ctx,
89 struct server_id,
90 void *,
91 void *);
92 void *private_data;
95 struct worker_restart_context {
96 unsigned int instance;
97 struct task_server *task;
98 struct tevent_context *ev2;
99 int control_pipe[2];
102 struct restart_context {
103 struct loadparm_context *lp_ctx;
104 struct tfork *t;
105 int from_parent_fd;
106 const struct service_details *service_details;
107 const char *service_name;
108 unsigned restart_delay;
109 struct master_restart_context *master;
110 struct worker_restart_context *worker;
113 static void sighup_signal_handler(struct tevent_context *ev,
114 struct tevent_signal *se,
115 int signum, int count, void *siginfo,
116 void *private_data)
118 reopen_logs_internal();
121 static void sigterm_signal_handler(struct tevent_context *ev,
122 struct tevent_signal *se,
123 int signum, int count, void *siginfo,
124 void *private_data)
126 #ifdef HAVE_GETPGRP
127 if (getpgrp() == getpid()) {
129 * We're the process group leader, send
130 * SIGTERM to our process group.
132 DBG_NOTICE("SIGTERM: killing children\n");
133 kill(-getpgrp(), SIGTERM);
135 #endif
136 DBG_NOTICE("Exiting pid %d on SIGTERM\n", getpid());
137 TALLOC_FREE(ev);
138 exit(127);
142 called when the process model is selected
144 static void prefork_model_init(void)
148 static void prefork_reload_after_fork(void)
150 NTSTATUS status;
152 ldb_wrap_fork_hook();
153 /* Must be done after a fork() to reset messaging contexts. */
154 status = imessaging_reinit_all();
155 if (!NT_STATUS_IS_OK(status)) {
156 smb_panic("Failed to re-initialise imessaging after fork");
158 force_check_log_size();
162 * clean up any messaging associated with the old process.
165 static void irpc_cleanup(
166 struct loadparm_context *lp_ctx,
167 struct tevent_context *ev,
168 pid_t pid)
170 TALLOC_CTX *mem_ctx = talloc_new(NULL);
171 struct imessaging_context *msg_ctx = NULL;
172 NTSTATUS status = NT_STATUS_OK;
174 if (mem_ctx == NULL) {
175 DBG_ERR("OOM cleaning up irpc\n");
176 return;
178 msg_ctx = imessaging_client_init(mem_ctx, lp_ctx, ev);
179 if (msg_ctx == NULL) {
180 DBG_ERR("Unable to create imessaging_context\n");
181 TALLOC_FREE(mem_ctx);
182 return;
184 status = imessaging_process_cleanup(msg_ctx, pid);
185 if (!NT_STATUS_IS_OK(status)) {
186 DBG_ERR("imessaging_process_cleanup returned (%s)\n",
187 nt_errstr(status));
188 TALLOC_FREE(mem_ctx);
189 return;
192 TALLOC_FREE(mem_ctx);
196 * handle EOF on the parent-to-all-children pipe in the child, i.e.
197 * the parent has died and its end of the pipe has been closed.
198 * The child handles this by exiting as well.
200 static void prefork_pipe_handler(struct tevent_context *event_ctx,
201 struct tevent_fd *fde, uint16_t flags,
202 void *private_data)
204 struct loadparm_context *lp_ctx = NULL;
205 pid_t pid;
208 * free the fde which removes the event and stops it firing again
210 TALLOC_FREE(fde);
213 * Clean up any irpc end points this process had.
215 pid = getpid();
216 lp_ctx = talloc_get_type_abort(private_data, struct loadparm_context);
217 irpc_cleanup(lp_ctx, event_ctx, pid);
219 DBG_NOTICE("Child %d exiting\n", getpid());
220 TALLOC_FREE(event_ctx);
221 exit(0);
226 * Called by the top-level samba process to create a new prefork master process
228 static void prefork_fork_master(
229 struct tevent_context *ev,
230 struct loadparm_context *lp_ctx,
231 const char *service_name,
232 struct task_server *(*new_task_fn)(struct tevent_context *,
233 struct loadparm_context *lp_ctx,
234 struct server_id,
235 void *,
236 void *),
237 void *private_data,
238 const struct service_details *service_details,
239 unsigned restart_delay,
240 int from_parent_fd)
242 pid_t pid;
243 struct tfork* t = NULL;
244 int i, num_children;
246 struct tevent_context *ev2;
247 struct task_server *task = NULL;
248 struct process_details pd = initial_process_details;
249 struct samba_tevent_trace_state *samba_tevent_trace_state = NULL;
250 int control_pipe[2];
252 t = tfork_create();
253 if (t == NULL) {
254 smb_panic("failure in tfork\n");
257 DBG_NOTICE("Forking [%s] pre-fork master process\n", service_name);
258 pid = tfork_child_pid(t);
259 if (pid != 0) {
260 struct tevent_fd *fde = NULL;
261 int fd = tfork_event_fd(t);
262 struct restart_context *rc = NULL;
264 /* Register a pipe handler that gets called when the prefork
265 * master process terminates.
267 rc = talloc_zero(ev, struct restart_context);
268 if (rc == NULL) {
269 smb_panic("OOM allocating restart context\n");
271 rc->t = t;
272 rc->lp_ctx = lp_ctx;
273 rc->service_name = service_name;
274 rc->service_details = service_details;
275 rc->from_parent_fd = from_parent_fd;
276 rc->restart_delay = restart_delay;
277 rc->master = talloc_zero(rc, struct master_restart_context);
278 if (rc->master == NULL) {
279 smb_panic("OOM allocating master restart context\n");
282 rc->master->new_task_fn = new_task_fn;
283 rc->master->private_data = private_data;
285 fde = tevent_add_fd(
286 ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
287 if (fde == NULL) {
288 smb_panic("Failed to add child pipe handler, "
289 "after fork");
291 tevent_fd_set_auto_close(fde);
292 return;
295 pid = getpid();
296 setproctitle("task[%s] pre-fork master", service_name);
298 * We must fit within 15 chars of text or we will truncate, so
299 * we put the constant part last
301 prctl_set_comment("%s[master]", service_name);
304 * this will free all the listening sockets and all state that
305 * is not associated with this new connection
307 if (tevent_re_initialise(ev) != 0) {
308 smb_panic("Failed to re-initialise tevent after fork");
310 prefork_reload_after_fork();
311 setup_handlers(ev, lp_ctx, from_parent_fd);
313 if (service_details->inhibit_pre_fork) {
314 task = new_task_fn(
315 ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
317 * The task does not support pre-fork
319 if (task != NULL && service_details->post_fork != NULL) {
320 service_details->post_fork(task, &pd);
322 tevent_loop_wait(ev);
323 TALLOC_FREE(ev);
324 exit(0);
328 * This is now the child code. We need a completely new event_context
329 * to work with
331 ev2 = s4_event_context_init(NULL);
333 samba_tevent_trace_state = create_samba_tevent_trace_state(ev2);
334 if (samba_tevent_trace_state == NULL) {
335 TALLOC_FREE(ev);
336 TALLOC_FREE(ev2);
337 exit(127);
340 tevent_set_trace_callback(ev2,
341 samba_tevent_trace_callback,
342 samba_tevent_trace_state);
344 /* setup this new connection: process will bind to it's sockets etc
346 * While we can use ev for the child, which has been re-initialised
347 * above we must run the new task under ev2 otherwise the children would
348 * be listening on the sockets. Also we don't want the top level
349 * process accepting and handling requests, it's responsible for
350 * monitoring and controlling the child work processes.
352 task = new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
353 if (task == NULL) {
354 TALLOC_FREE(ev);
355 TALLOC_FREE(ev2);
356 exit(127);
360 * Register an irpc name that can be used by the samba-tool processes
361 * command
364 struct talloc_ctx *ctx = talloc_new(NULL);
365 char *name = NULL;
366 if (ctx == NULL) {
367 DBG_ERR("Out of memory");
368 exit(127);
370 name = talloc_asprintf(ctx, "prefork-master-%s", service_name);
371 irpc_add_name(task->msg_ctx, name);
372 TALLOC_FREE(ctx);
376 int default_children;
377 default_children = lpcfg_prefork_children(lp_ctx);
378 num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children",
379 service_name, default_children);
381 if (num_children == 0) {
382 DBG_WARNING("Number of pre-fork children for %s is zero, "
383 "NO worker processes will be started for %s\n",
384 service_name, service_name);
386 DBG_NOTICE("Forking %d %s worker processes\n",
387 num_children, service_name);
390 * the prefork master creates its own control pipe, so the prefork
391 * workers can detect if the master exits (in which case an EOF gets
392 * written). (Whereas from_parent_fd is the control pipe from the
393 * top-level process that the prefork master listens on)
396 int ret;
397 ret = pipe(control_pipe);
398 if (ret != 0) {
399 smb_panic("Unable to create worker control pipe\n");
401 smb_set_close_on_exec(control_pipe[0]);
402 smb_set_close_on_exec(control_pipe[1]);
406 * We are now free to spawn some worker processes
408 for (i=0; i < num_children; i++) {
409 prefork_fork_worker(task,
411 ev2,
412 lp_ctx,
413 service_details,
414 service_name,
415 control_pipe,
417 &pd);
418 pd.instances++;
421 /* Don't listen on the sockets we just gave to the children */
422 tevent_loop_wait(ev);
423 TALLOC_FREE(ev);
424 /* We need to keep ev2 until we're finished for the messaging to work */
425 TALLOC_FREE(ev2);
426 exit(0);
429 static void prefork_restart_fn(struct tevent_context *ev,
430 struct tevent_timer *te,
431 struct timeval tv,
432 void *private_data);
435 * Restarts a child process if it exits unexpectedly
437 static bool prefork_restart(struct tevent_context *ev,
438 struct restart_context *rc)
440 struct tevent_timer *te = NULL;
442 if (rc->restart_delay > 0) {
443 DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
444 rc->service_name,
445 (rc->master == NULL) ? "worker" : "master",
446 rc->restart_delay);
450 * Always use an async timer event. If
451 * rc->restart_delay is zero this is the
452 * same as an immediate event and will be
453 * called immediately we go back into the
454 * event loop.
456 te = tevent_add_timer(ev,
458 tevent_timeval_current_ofs(rc->restart_delay, 0),
459 prefork_restart_fn,
460 rc);
461 if (te == NULL) {
462 DBG_ERR("tevent_add_timer fail [%s] pre-fork event %s\n",
463 rc->service_name,
464 (rc->master == NULL) ? "worker" : "master");
465 /* Caller needs to free rc. */
466 return false;
468 /* Caller must not free rc - it's in use. */
469 return true;
472 static void prefork_restart_fn(struct tevent_context *ev,
473 struct tevent_timer *te,
474 struct timeval tv,
475 void *private_data)
477 unsigned max_backoff = 0;
478 unsigned backoff = 0;
479 unsigned default_value = 0;
480 struct restart_context *rc = talloc_get_type(private_data,
481 struct restart_context);
482 unsigned restart_delay = rc->restart_delay;
484 TALLOC_FREE(te);
487 * If the child process is constantly exiting, then restarting it can
488 * consume a lot of resources. In which case, we want to backoff a bit
489 * before respawning it
491 default_value = lpcfg_prefork_backoff_increment(rc->lp_ctx);
492 backoff = lpcfg_parm_int(rc->lp_ctx,
493 NULL,
494 "prefork backoff increment",
495 rc->service_name,
496 default_value);
498 default_value = lpcfg_prefork_maximum_backoff(rc->lp_ctx);
499 max_backoff = lpcfg_parm_int(rc->lp_ctx,
500 NULL,
501 "prefork maximum backoff",
502 rc->service_name,
503 default_value);
505 restart_delay += backoff;
506 restart_delay = min(restart_delay, max_backoff);
508 if (rc->master != NULL) {
509 DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
510 prefork_fork_master(ev,
511 rc->lp_ctx,
512 rc->service_name,
513 rc->master->new_task_fn,
514 rc->master->private_data,
515 rc->service_details,
516 restart_delay,
517 rc->from_parent_fd);
518 } else if (rc->worker != NULL) {
519 struct process_details pd = initial_process_details;
520 DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
521 rc->service_name,
522 rc->worker->instance);
523 pd.instances = rc->worker->instance;
524 prefork_fork_worker(rc->worker->task,
526 rc->worker->ev2,
527 rc->lp_ctx,
528 rc->service_details,
529 rc->service_name,
530 rc->worker->control_pipe,
531 restart_delay,
532 &pd);
534 /* tfork allocates tfork structures with malloc */
535 tfork_destroy(&rc->t);
536 free(rc->t);
537 TALLOC_FREE(rc);
541 handle EOF on the child pipe in the parent, so we know when a
542 process terminates without using SIGCHLD or waiting on all possible pids.
544 We need to ensure we do not ignore SIGCHLD because we need it to
545 work to get a valid error code from samba_runcmd_*().
547 static void prefork_child_pipe_handler(struct tevent_context *ev,
548 struct tevent_fd *fde,
549 uint16_t flags,
550 void *private_data)
552 struct restart_context *rc = NULL;
553 int status = 0;
554 pid_t pid = 0;
555 bool rc_inuse = false;
557 /* free the fde which removes the event and stops it firing again */
558 TALLOC_FREE(fde);
560 /* the child has closed the pipe, assume its dead */
562 rc = talloc_get_type_abort(private_data, struct restart_context);
563 pid = tfork_child_pid(rc->t);
564 errno = 0;
566 irpc_cleanup(rc->lp_ctx, ev, pid);
567 status = tfork_status(&rc->t, false);
568 if (status == -1) {
569 DBG_ERR("Parent %d, Child %d terminated, "
570 "unable to get status code from tfork\n",
571 getpid(), pid);
572 rc_inuse = prefork_restart(ev, rc);
573 } else if (WIFEXITED(status)) {
574 status = WEXITSTATUS(status);
575 DBG_ERR("Parent %d, Child %d exited with status %d\n",
576 getpid(), pid, status);
577 if (status != 0) {
578 rc_inuse = prefork_restart(ev, rc);
580 } else if (WIFSIGNALED(status)) {
581 status = WTERMSIG(status);
582 DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
583 getpid(), pid, status);
584 if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
585 status == SIGILL || status == SIGSYS || status == SIGSEGV ||
586 status == SIGKILL) {
588 rc_inuse = prefork_restart(ev, rc);
591 if (!rc_inuse) {
592 /* tfork allocates tfork structures with malloc */
593 tfork_destroy(&rc->t);
594 free(rc->t);
595 TALLOC_FREE(rc);
597 return;
601 called when a listening socket becomes readable.
603 static void prefork_accept_connection(
604 struct tevent_context *ev,
605 struct loadparm_context *lp_ctx,
606 struct socket_context *listen_socket,
607 void (*new_conn)(struct tevent_context *,
608 struct loadparm_context *,
609 struct socket_context *,
610 struct server_id,
611 void *,
612 void *),
613 void *private_data,
614 void *process_context)
616 NTSTATUS status;
617 struct socket_context *connected_socket;
618 pid_t pid = getpid();
620 /* accept an incoming connection. */
621 status = socket_accept(listen_socket, &connected_socket);
622 if (!NT_STATUS_IS_OK(status)) {
624 * For prefork we can ignore STATUS_MORE_ENTRIES, as once a
625 * connection becomes available all waiting processes are
626 * woken, but only one gets work to process.
627 * AKA the thundering herd.
628 * In the short term this should not be an issue as the number
629 * of workers should be a small multiple of the number of cpus
630 * In the longer term socket_accept needs to implement a
631 * mutex/semaphore (like apache does) to serialise the accepts
633 if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
634 DBG_ERR("Worker process (%d), error in accept [%s]\n",
635 getpid(), nt_errstr(status));
637 return;
640 talloc_steal(private_data, connected_socket);
642 new_conn(ev, lp_ctx, connected_socket,
643 cluster_id(pid, socket_get_fd(connected_socket)),
644 private_data, process_context);
647 static void setup_handlers(
648 struct tevent_context *ev,
649 struct loadparm_context *lp_ctx,
650 int from_parent_fd)
652 struct tevent_fd *fde = NULL;
653 struct tevent_signal *se = NULL;
655 fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
656 prefork_pipe_handler, lp_ctx);
657 if (fde == NULL) {
658 smb_panic("Failed to add fd handler after fork");
661 se = tevent_add_signal(ev,
663 SIGHUP,
665 sighup_signal_handler,
666 NULL);
667 if (se == NULL) {
668 smb_panic("Failed to add SIGHUP handler after fork");
671 se = tevent_add_signal(ev,
673 SIGTERM,
675 sigterm_signal_handler,
676 NULL);
677 if (se == NULL) {
678 smb_panic("Failed to add SIGTERM handler after fork");
683 * Called by the prefork master to create a new prefork worker process
685 static void prefork_fork_worker(struct task_server *task,
686 struct tevent_context *ev,
687 struct tevent_context *ev2,
688 struct loadparm_context *lp_ctx,
689 const struct service_details *service_details,
690 const char *service_name,
691 int control_pipe[2],
692 unsigned restart_delay,
693 struct process_details *pd)
695 struct tfork *w = NULL;
696 pid_t pid;
698 w = tfork_create();
699 if (w == NULL) {
700 smb_panic("failure in tfork\n");
703 pid = tfork_child_pid(w);
704 if (pid != 0) {
705 struct tevent_fd *fde = NULL;
706 int fd = tfork_event_fd(w);
707 struct restart_context *rc = NULL;
710 * we're the parent (prefork master), so store enough info to
711 * restart the worker/child if it exits unexpectedly
713 rc = talloc_zero(ev, struct restart_context);
714 if (rc == NULL) {
715 smb_panic("OOM allocating restart context\n");
717 rc->t = w;
718 rc->lp_ctx = lp_ctx;
719 rc->service_name = service_name;
720 rc->service_details = service_details;
721 rc->restart_delay = restart_delay;
722 rc->master = NULL;
723 rc->worker = talloc_zero(rc, struct worker_restart_context);
724 if (rc->worker == NULL) {
725 smb_panic("OOM allocating master restart context\n");
727 rc->worker->ev2 = ev2;
728 rc->worker->instance = pd->instances;
729 rc->worker->task = task;
730 rc->worker->control_pipe[0] = control_pipe[0];
731 rc->worker->control_pipe[1] = control_pipe[1];
733 fde = tevent_add_fd(
734 ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
735 if (fde == NULL) {
736 smb_panic("Failed to add child pipe handler, "
737 "after fork");
739 tevent_fd_set_auto_close(fde);
740 } else {
743 * we're the child (prefork-worker). We never write to the
744 * control pipe, but listen on the read end in case our parent
745 * (the pre-fork master) exits
747 close(control_pipe[1]);
748 setup_handlers(ev2, lp_ctx, control_pipe[0]);
751 * tfork uses malloc
753 free(w);
755 TALLOC_FREE(ev);
756 setproctitle("task[%s] pre-forked worker(%d)",
757 service_name,
758 pd->instances);
760 * We must fit within 15 chars of text or we will truncate, so
761 * we put child number last
763 prctl_set_comment("%s(%d)",
764 service_name,
765 pd->instances);
766 prefork_reload_after_fork();
767 if (service_details->post_fork != NULL) {
768 service_details->post_fork(task, pd);
771 struct talloc_ctx *ctx = talloc_new(NULL);
772 char *name = NULL;
773 if (ctx == NULL) {
774 smb_panic("OOM allocating talloc context\n");
776 name = talloc_asprintf(ctx,
777 "prefork-worker-%s-%d",
778 service_name,
779 pd->instances);
780 irpc_add_name(task->msg_ctx, name);
781 TALLOC_FREE(ctx);
783 tevent_loop_wait(ev2);
784 talloc_free(ev2);
785 exit(0);
789 * called to create a new server task
791 static void prefork_new_task(
792 struct tevent_context *ev,
793 struct loadparm_context *lp_ctx,
794 const char *service_name,
795 struct task_server *(*new_task_fn)(struct tevent_context *,
796 struct loadparm_context *lp_ctx,
797 struct server_id , void *, void *),
798 void *private_data,
799 const struct service_details *service_details,
800 int from_parent_fd)
802 prefork_fork_master(ev,
803 lp_ctx,
804 service_name,
805 new_task_fn,
806 private_data,
807 service_details,
809 from_parent_fd);
814 * called when a task terminates
816 static void prefork_terminate_task(struct tevent_context *ev,
817 struct loadparm_context *lp_ctx,
818 const char *reason,
819 bool fatal,
820 void *process_context)
822 DBG_DEBUG("called with reason[%s]\n", reason);
823 TALLOC_FREE(ev);
824 if (fatal == true) {
825 exit(127);
826 } else {
827 exit(0);
832 * called when a connection completes
834 static void prefork_terminate_connection(struct tevent_context *ev,
835 struct loadparm_context *lp_ctx,
836 const char *reason,
837 void *process_context)
841 /* called to set a title of a task or connection */
842 static void prefork_set_title(struct tevent_context *ev, const char *title)
846 static const struct model_ops prefork_ops = {
847 .name = "prefork",
848 .model_init = prefork_model_init,
849 .accept_connection = prefork_accept_connection,
850 .new_task = prefork_new_task,
851 .terminate_task = prefork_terminate_task,
852 .terminate_connection = prefork_terminate_connection,
853 .set_title = prefork_set_title,
857 * initialise the prefork process model, registering ourselves with the
858 * process model subsystem
860 NTSTATUS process_model_prefork_init(void)
862 return register_process_model(&prefork_ops);