2 Unix SMB/CIFS implementation.
5 Copyright (C) Simo Sorce <idra@samba.org> 2011
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/time.h"
23 #include "system/shmem.h"
24 #include "system/filesys.h"
25 #include "server_prefork.h"
26 #include "../lib/util/util.h"
27 #include "../lib/util/tevent_unix.h"
36 prefork_main_fn_t *main_fn;
40 struct pf_worker_data *pool;
44 prefork_sigchld_fn_t *sigchld_fn;
48 static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
49 struct prefork_pool *pfp);
51 static int prefork_pool_destructor(struct prefork_pool *pfp)
53 anonymous_shared_free(pfp->pool);
57 bool prefork_create_pool(TALLOC_CTX *mem_ctx,
58 struct tevent_context *ev_ctx,
59 struct messaging_context *msg_ctx,
60 int listen_fd_size, int *listen_fds,
61 int min_children, int max_children,
62 prefork_main_fn_t *main_fn, void *private_data,
63 struct prefork_pool **pf_pool)
65 struct prefork_pool *pfp;
67 time_t now = time(NULL);
73 pfp = talloc_zero(mem_ctx, struct prefork_pool);
75 DEBUG(1, ("Out of memory!\n"));
78 pfp->listen_fd_size = listen_fd_size;
79 pfp->listen_fds = talloc_array(pfp, int, listen_fd_size);
80 if (!pfp->listen_fds) {
81 DEBUG(1, ("Out of memory!\n"));
84 for (i = 0; i < listen_fd_size; i++) {
85 pfp->listen_fds[i] = listen_fds[i];
87 pfp->main_fn = main_fn;
88 pfp->private_data = private_data;
90 pfp->lock_fd = create_unlink_tmp(NULL);
91 if (pfp->lock_fd == -1) {
92 DEBUG(1, ("Failed to create prefork lock fd!\n"));
97 pfp->pool_size = max_children;
98 data_size = sizeof(struct pf_worker_data) * max_children;
100 pfp->pool = anonymous_shared_allocate(data_size);
101 if (pfp->pool == NULL) {
102 DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
106 talloc_set_destructor(pfp, prefork_pool_destructor);
108 for (i = 0; i < min_children; i++) {
110 pfp->pool[i].allowed_clients = 1;
111 pfp->pool[i].started = now;
116 DEBUG(1, ("Failed to prefork child n. %d !\n", i));
119 case 0: /* THE CHILD */
121 pfp->pool[i].status = PF_WORKER_IDLE;
122 ret = pfp->main_fn(ev_ctx, msg_ctx,
123 &pfp->pool[i], i + 1,
130 default: /* THE PARENT */
131 pfp->pool[i].pid = pid;
136 ok = prefork_setup_sigchld_handler(ev_ctx, pfp);
138 DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
147 /* Provide the new max children number in new_max
148 * (must be larger than current max).
149 * Returns: 0 if all fine
150 * ENOSPC if mremap fails to expand
151 * EINVAL if new_max is invalid
153 int prefork_expand_pool(struct prefork_pool *pfp, int new_max)
155 struct prefork_pool *pool;
160 if (new_max <= pfp->pool_size) {
164 old_size = sizeof(struct pf_worker_data) * pfp->pool_size;
165 new_size = sizeof(struct pf_worker_data) * new_max;
167 pool = anonymous_shared_resize(&pfp->pool, new_size, false);
170 DEBUG(3, ("Failed to mremap memory (%d: %s)!\n",
171 ret, strerror(ret)));
175 memset(&pool[pfp->pool_size], 0, new_size - old_size);
177 pfp->pool_size = new_max;
182 int prefork_add_children(struct tevent_context *ev_ctx,
183 struct messaging_context *msg_ctx,
184 struct prefork_pool *pfp,
188 time_t now = time(NULL);
192 for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
194 if (pfp->pool[i].status != PF_WORKER_NONE) {
198 pfp->pool[i].allowed_clients = 1;
199 pfp->pool[i].started = now;
204 DEBUG(1, ("Failed to prefork child n. %d !\n", j));
207 case 0: /* THE CHILD */
209 pfp->pool[i].status = PF_WORKER_IDLE;
210 ret = pfp->main_fn(ev_ctx, msg_ctx,
211 &pfp->pool[i], i + 1,
217 pfp->pool[i].status = PF_WORKER_EXITING;
220 default: /* THE PARENT */
221 pfp->pool[i].pid = pid;
227 DEBUG(5, ("Added %d children!\n", j));
232 struct prefork_oldest {
237 /* sort in inverse order */
238 static int prefork_sort_oldest(const void *ap, const void *bp)
240 const struct prefork_oldest *a = (const struct prefork_oldest *)ap;
241 const struct prefork_oldest *b = (const struct prefork_oldest *)bp;
243 if (a->started == b->started) {
246 if (a->started < b->started) {
252 int prefork_retire_children(struct prefork_pool *pfp,
253 int num_children, time_t age_limit)
255 time_t now = time(NULL);
256 struct prefork_oldest *oldest;
259 oldest = talloc_array(pfp, struct prefork_oldest, pfp->pool_size);
264 for (i = 0; i < pfp->pool_size; i++) {
266 if (pfp->pool[i].status == PF_WORKER_IDLE) {
267 oldest[i].started = pfp->pool[i].started;
269 oldest[i].started = now;
273 qsort(oldest, pfp->pool_size,
274 sizeof(struct prefork_oldest),
275 prefork_sort_oldest);
277 for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
278 if (pfp->pool[i].status == PF_WORKER_IDLE &&
279 pfp->pool[i].started <= age_limit) {
280 /* tell the child it's time to give up */
281 DEBUG(5, ("Retiring pid %d!\n", pfp->pool[i].pid));
282 pfp->pool[i].cmds = PF_SRV_MSG_EXIT;
283 kill(pfp->pool[i].pid, SIGHUP);
291 int prefork_count_active_children(struct prefork_pool *pfp, int *total)
297 for (i = 0; i < pfp->pool_size; i++) {
298 if (pfp->pool[i].status == PF_WORKER_NONE) {
304 if (pfp->pool[i].num_clients == 0) {
315 static void prefork_cleanup_loop(struct prefork_pool *pfp)
321 /* TODO: should we use a process group id wait instead of looping ? */
322 for (i = 0; i < pfp->pool_size; i++) {
323 if (pfp->pool[i].status == PF_WORKER_NONE ||
324 pfp->pool[i].pid == 0) {
328 pid = sys_waitpid(pfp->pool[i].pid, &status, WNOHANG);
331 if (pfp->pool[i].status != PF_WORKER_EXITING) {
332 DEBUG(3, ("Child (%d) terminated abnormally:"
333 " %d\n", (int)pid, status));
335 DEBUG(10, ("Child (%d) terminated with status:"
336 " %d\n", (int)pid, status));
340 * this makes status = PF_WORK_NONE */
341 memset(&pfp->pool[i], 0,
342 sizeof(struct pf_worker_data));
348 void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max)
352 for (i = 0; i < pfp->pool_size; i++) {
353 if (pfp->pool[i].status == PF_WORKER_NONE) {
357 if (pfp->pool[i].allowed_clients < max) {
358 pfp->pool[i].allowed_clients++;
363 void prefork_reset_allowed_clients(struct prefork_pool *pfp)
367 for (i = 0; i < pfp->pool_size; i++) {
368 pfp->pool[i].allowed_clients = 1;
372 void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
376 for (i = 0; i < pfp->pool_size; i++) {
377 if (pfp->pool[i].status == PF_WORKER_NONE) {
381 kill(pfp->pool[i].pid, signal_num);
385 static void prefork_sigchld_handler(struct tevent_context *ev_ctx,
386 struct tevent_signal *se,
387 int signum, int count,
388 void *siginfo, void *pvt)
390 struct prefork_pool *pfp;
392 pfp = talloc_get_type_abort(pvt, struct prefork_pool);
394 /* run the cleanup function to make sure all dead children are
395 * properly and timely retired. */
396 prefork_cleanup_loop(pfp);
398 if (pfp->sigchld_fn) {
399 pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data);
403 static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
404 struct prefork_pool *pfp)
406 struct tevent_signal *se;
408 se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0,
409 prefork_sigchld_handler, pfp);
411 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
418 void prefork_set_sigchld_callback(struct prefork_pool *pfp,
419 prefork_sigchld_fn_t *sigchld_fn,
422 pfp->sigchld_fn = sigchld_fn;
423 pfp->sigchld_data = private_data;
426 /* ==== Functions used by children ==== */
428 static SIG_ATOMIC_T pf_alarm;
430 static void pf_alarm_cb(int signum)
438 * pf - the worker shared data structure
439 * lock_fd - the file descriptor used for locking
440 * timeout - expressed in seconds:
442 * 0 timeouts immediately
443 * N seconds before timing out
446 * negative errno on fatal error
447 * 0 on success to acquire lock
448 * -1 on timeout/lock held by other
449 * -2 on server msg to terminate
450 * ERRNO on other errors
453 static int prefork_grab_lock(struct pf_worker_data *pf,
454 int lock_fd, int timeout)
460 if (pf->cmds == PF_SRV_MSG_EXIT) {
467 CatchSignal(SIGALRM, pf_alarm_cb);
480 lock.l_type = F_WRLCK;
481 lock.l_whence = SEEK_SET;
483 ret = fcntl(lock_fd, op, &lock);
488 if (pf->cmds == PF_SRV_MSG_EXIT) {
499 /* lock held by other proc */
511 } while (timeout != 0);
514 /* We have the Lock */
515 pf->status = PF_WORKER_ACCEPTING;
521 CatchSignal(SIGALRM, SIG_IGN);
525 DEBUG(1, ("Failed to get lock (%d, %s)!\n",
526 ret, strerror(ret)));
533 * pf - the worker shared data structure
534 * lock_fd - the file descriptor used for locking
535 * timeout - expressed in seconds:
537 * 0 timeouts immediately
538 * N seconds before timing out
541 * negative errno on fatal error
542 * 0 on success to release lock
547 static int prefork_release_lock(struct pf_worker_data *pf,
548 int lock_fd, int timeout)
557 CatchSignal(SIGALRM, pf_alarm_cb);
569 lock.l_type = F_UNLCK;
570 lock.l_whence = SEEK_SET;
572 ret = fcntl(lock_fd, op, &lock);
586 } while (timeout != 0);
591 CatchSignal(SIGALRM, SIG_IGN);
595 DEBUG(1, ("Failed to release lock (%d, %s)!\n",
596 ret, strerror(ret)));
601 /* ==== async code ==== */
603 #define PF_ASYNC_LOCK_GRAB 0x01
604 #define PF_ASYNC_LOCK_RELEASE 0x02
605 #define PF_ASYNC_ACTION_MASK 0x03
606 #define PF_ASYNC_LOCK_DONE 0x04
608 struct pf_lock_state {
609 struct pf_worker_data *pf;
614 static void prefork_lock_handler(struct tevent_context *ev,
615 struct tevent_timer *te,
616 struct timeval curtime, void *pvt);
618 static struct tevent_req *prefork_lock_send(TALLOC_CTX *mem_ctx,
619 struct tevent_context *ev,
620 struct pf_worker_data *pf,
621 int lock_fd, int action)
623 struct tevent_req *req;
624 struct pf_lock_state *state;
626 req = tevent_req_create(mem_ctx, &state, struct pf_lock_state);
632 state->lock_fd = lock_fd;
633 state->flags = action;
635 /* try once immediately */
636 prefork_lock_handler(ev, NULL, tevent_timeval_zero(), req);
637 if (state->flags & PF_ASYNC_LOCK_DONE) {
638 tevent_req_post(req, ev);
644 static void prefork_lock_handler(struct tevent_context *ev,
645 struct tevent_timer *te,
646 struct timeval curtime, void *pvt)
648 struct tevent_req *req;
649 struct pf_lock_state *state;
654 req = talloc_get_type_abort(pvt, struct tevent_req);
655 state = tevent_req_data(req, struct pf_lock_state);
657 if (state->pf->num_clients > 0) {
661 switch (state->flags & PF_ASYNC_ACTION_MASK) {
662 case PF_ASYNC_LOCK_GRAB:
663 ret = prefork_grab_lock(state->pf, state->lock_fd, timeout);
665 case PF_ASYNC_LOCK_RELEASE:
666 ret = prefork_release_lock(state->pf, state->lock_fd, timeout);
675 state->flags |= PF_ASYNC_LOCK_DONE;
676 tevent_req_done(req);
680 tv = tevent_timeval_zero();
682 tv = tevent_timeval_current_ofs(0, 100000);
684 te = tevent_add_timer(ev, state, tv,
685 prefork_lock_handler, req);
686 tevent_req_nomem(te, req);
689 /* server tells us to stop */
690 state->flags |= PF_ASYNC_LOCK_DONE;
691 tevent_req_error(req, -2);
694 state->flags |= PF_ASYNC_LOCK_DONE;
695 tevent_req_error(req, ret);
700 static int prefork_lock_recv(struct tevent_req *req)
704 if (!tevent_req_is_unix_error(req, &ret)) {
708 tevent_req_received(req);
712 struct pf_listen_state {
713 struct tevent_context *ev;
714 struct pf_worker_data *pf;
723 struct tsocket_address *srv_addr;
724 struct tsocket_address *cli_addr;
729 static void prefork_listen_lock_done(struct tevent_req *subreq);
730 static void prefork_listen_accept_handler(struct tevent_context *ev,
731 struct tevent_fd *fde,
732 uint16_t flags, void *pvt);
733 static void prefork_listen_release_done(struct tevent_req *subreq);
735 struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
736 struct tevent_context *ev,
737 struct pf_worker_data *pf,
742 struct tevent_req *req, *subreq;
743 struct pf_listen_state *state;
745 req = tevent_req_create(mem_ctx, &state, struct pf_listen_state);
752 state->lock_fd = lock_fd;
753 state->listen_fd_size = listen_fd_size;
754 state->listen_fds = listen_fds;
755 state->accept_fd = -1;
758 subreq = prefork_lock_send(state, state->ev, state->pf,
759 state->lock_fd, PF_ASYNC_LOCK_GRAB);
760 if (tevent_req_nomem(subreq, req)) {
761 return tevent_req_post(req, ev);
764 tevent_req_set_callback(subreq, prefork_listen_lock_done, req);
768 struct pf_listen_ctx {
770 struct tevent_req *req;
774 static void prefork_listen_lock_done(struct tevent_req *subreq)
776 struct tevent_req *req;
777 struct pf_listen_state *state;
778 struct pf_listen_ctx *ctx;
779 struct tevent_fd *fde;
784 req = tevent_req_callback_data(subreq, struct tevent_req);
785 state = tevent_req_data(req, struct pf_listen_state);
787 ret = prefork_lock_recv(subreq);
789 tevent_req_error(req, ret);
793 fde_ctx = talloc_new(state);
794 if (tevent_req_nomem(fde_ctx, req)) {
798 /* next step, accept */
799 for (i = 0; i < state->listen_fd_size; i++) {
800 ctx = talloc(fde_ctx, struct pf_listen_ctx);
801 if (tevent_req_nomem(ctx, req)) {
804 ctx->fde_ctx = fde_ctx;
806 ctx->listen_fd = state->listen_fds[i];
808 fde = tevent_add_fd(state->ev, fde_ctx,
809 ctx->listen_fd, TEVENT_FD_READ,
810 prefork_listen_accept_handler, ctx);
811 if (tevent_req_nomem(fde, req)) {
817 static void prefork_listen_accept_handler(struct tevent_context *ev,
818 struct tevent_fd *fde,
819 uint16_t flags, void *pvt)
821 struct pf_listen_state *state;
822 struct tevent_req *req, *subreq;
823 struct pf_listen_ctx *ctx;
824 struct sockaddr_storage addr;
830 ctx = talloc_get_type_abort(pvt, struct pf_listen_ctx);
831 state = tevent_req_data(ctx->req, struct pf_listen_state);
834 addrlen = sizeof(addr);
835 sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
837 if (errno == EINTR) {
842 DEBUG(6, ("Accept failed! (%d, %s)\n", err, strerror(err)));
845 /* do not track the listen fds anymore */
847 talloc_free(ctx->fde_ctx);
854 state->accept_fd = sd;
856 ret = tsocket_address_bsd_from_sockaddr(state,
857 (struct sockaddr *)(void *)&addr,
858 addrlen, &state->cli_addr);
860 state->error = errno;
865 addrlen = sizeof(addr);
866 ret = getsockname(sd, (struct sockaddr *)(void *)&addr, &addrlen);
868 state->error = errno;
872 ret = tsocket_address_bsd_from_sockaddr(state,
873 (struct sockaddr *)(void *)&addr,
874 addrlen, &state->srv_addr);
876 state->error = errno;
881 /* release lock now */
882 subreq = prefork_lock_send(state, state->ev, state->pf,
883 state->lock_fd, PF_ASYNC_LOCK_RELEASE);
884 if (tevent_req_nomem(subreq, req)) {
887 tevent_req_set_callback(subreq, prefork_listen_release_done, req);
890 static void prefork_listen_release_done(struct tevent_req *subreq)
892 struct tevent_req *req;
895 req = tevent_req_callback_data(subreq, struct tevent_req);
897 ret = prefork_lock_recv(subreq);
899 tevent_req_error(req, ret);
903 tevent_req_done(req);
906 int prefork_listen_recv(struct tevent_req *req,
907 TALLOC_CTX *mem_ctx, int *fd,
908 struct tsocket_address **srv_addr,
909 struct tsocket_address **cli_addr)
911 struct pf_listen_state *state;
914 state = tevent_req_data(req, struct pf_listen_state);
919 tevent_req_is_unix_error(req, &ret);
923 if (state->accept_fd != -1) {
924 close(state->accept_fd);
927 *fd = state->accept_fd;
928 *srv_addr = talloc_move(mem_ctx, &state->srv_addr);
929 *cli_addr = talloc_move(mem_ctx, &state->cli_addr);
930 state->pf->status = PF_WORKER_BUSY;
931 state->pf->num_clients++;
934 tevent_req_received(req);