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 munmap(pfp
->pool
, pfp
->pool_size
* sizeof(struct pf_worker_data
));
57 bool prefork_create_pool(struct tevent_context
*ev_ctx
, TALLOC_CTX
*mem_ctx
,
58 int listen_fd_size
, int *listen_fds
,
59 int min_children
, int max_children
,
60 prefork_main_fn_t
*main_fn
, void *private_data
,
61 struct prefork_pool
**pf_pool
)
63 struct prefork_pool
*pfp
;
65 time_t now
= time(NULL
);
71 pfp
= talloc_zero(mem_ctx
, struct prefork_pool
);
73 DEBUG(1, ("Out of memory!\n"));
76 pfp
->listen_fd_size
= listen_fd_size
;
77 pfp
->listen_fds
= talloc_array(pfp
, int, listen_fd_size
);
78 if (!pfp
->listen_fds
) {
79 DEBUG(1, ("Out of memory!\n"));
82 for (i
= 0; i
< listen_fd_size
; i
++) {
83 pfp
->listen_fds
[i
] = listen_fds
[i
];
85 pfp
->main_fn
= main_fn
;
86 pfp
->private_data
= private_data
;
88 pfp
->lock_fd
= create_unlink_tmp(NULL
);
89 if (pfp
->lock_fd
== -1) {
90 DEBUG(1, ("Failed to create prefork lock fd!\n"));
95 pfp
->pool_size
= max_children
;
96 data_size
= sizeof(struct pf_worker_data
) * max_children
;
98 pfp
->pool
= mmap(NULL
, data_size
, PROT_READ
|PROT_WRITE
,
99 MAP_SHARED
|MAP_ANONYMOUS
, -1, 0);
100 if (pfp
->pool
== MAP_FAILED
) {
101 DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
105 talloc_set_destructor(pfp
, prefork_pool_destructor
);
107 for (i
= 0; i
< min_children
; i
++) {
109 pfp
->pool
[i
].allowed_clients
= 1;
110 pfp
->pool
[i
].started
= now
;
115 DEBUG(1, ("Failed to prefork child n. %d !\n", i
));
118 case 0: /* THE CHILD */
120 pfp
->pool
[i
].status
= PF_WORKER_IDLE
;
121 ret
= pfp
->main_fn(ev_ctx
, &pfp
->pool
[i
],
128 default: /* THE PARENT */
129 pfp
->pool
[i
].pid
= pid
;
134 ok
= prefork_setup_sigchld_handler(ev_ctx
, pfp
);
136 DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
145 /* Provide the new max children number in new_max
146 * (must be larger than current max).
147 * Returns: 0 if all fine
148 * ENOSPC if mremap fails to expand
149 * EINVAL if new_max is invalid
151 int prefork_expand_pool(struct prefork_pool
*pfp
, int new_max
)
153 struct pf_worker_data
*pool
;
157 if (new_max
<= pfp
->pool_size
) {
161 old_size
= sizeof(struct pf_worker_data
) * pfp
->pool_size
;
162 new_size
= sizeof(struct pf_worker_data
) * new_max
;
164 pool
= mremap(pfp
->pool
, old_size
, new_size
, 0);
165 if (pool
== MAP_FAILED
) {
166 DEBUG(3, ("Failed to mremap memory for prefork pool!\n"));
170 memset(&pool
[pfp
->pool_size
], 0, new_size
- old_size
);
172 pfp
->pool_size
= new_max
;
177 int prefork_add_children(struct tevent_context
*ev_ctx
,
178 struct prefork_pool
*pfp
,
182 time_t now
= time(NULL
);
186 for (i
= 0, j
= 0; i
< pfp
->pool_size
&& j
< num_children
; i
++) {
188 if (pfp
->pool
[i
].status
!= PF_WORKER_NONE
) {
192 pfp
->pool
[i
].allowed_clients
= 1;
193 pfp
->pool
[i
].started
= now
;
198 DEBUG(1, ("Failed to prefork child n. %d !\n", j
));
201 case 0: /* THE CHILD */
203 pfp
->pool
[i
].status
= PF_WORKER_IDLE
;
204 ret
= pfp
->main_fn(ev_ctx
, &pfp
->pool
[i
],
210 pfp
->pool
[i
].status
= PF_WORKER_EXITING
;
213 default: /* THE PARENT */
214 pfp
->pool
[i
].pid
= pid
;
220 DEBUG(5, ("Added %d children!\n", j
));
225 struct prefork_oldest
{
230 /* sort in inverse order */
231 static int prefork_sort_oldest(const void *ap
, const void *bp
)
233 struct prefork_oldest
*a
= (struct prefork_oldest
*)ap
;
234 struct prefork_oldest
*b
= (struct prefork_oldest
*)bp
;
236 if (a
->started
== b
->started
) {
239 if (a
->started
< b
->started
) {
245 int prefork_retire_children(struct prefork_pool
*pfp
,
246 int num_children
, time_t age_limit
)
248 time_t now
= time(NULL
);
249 struct prefork_oldest
*oldest
;
252 oldest
= talloc_array(pfp
, struct prefork_oldest
, pfp
->pool_size
);
257 for (i
= 0; i
< pfp
->pool_size
; i
++) {
259 if (pfp
->pool
[i
].status
== PF_WORKER_IDLE
) {
260 oldest
[i
].started
= pfp
->pool
[i
].started
;
262 oldest
[i
].started
= now
;
266 qsort(oldest
, pfp
->pool_size
,
267 sizeof(struct prefork_oldest
),
268 prefork_sort_oldest
);
270 for (i
= 0, j
= 0; i
< pfp
->pool_size
&& j
< num_children
; i
++) {
271 if (pfp
->pool
[i
].status
== PF_WORKER_IDLE
&&
272 pfp
->pool
[i
].started
<= age_limit
) {
273 /* tell the child it's time to give up */
274 DEBUG(5, ("Retiring pid %d!\n", pfp
->pool
[i
].pid
));
275 pfp
->pool
[i
].cmds
= PF_SRV_MSG_EXIT
;
276 kill(pfp
->pool
[i
].pid
, SIGHUP
);
284 int prefork_count_active_children(struct prefork_pool
*pfp
, int *total
)
290 for (i
= 0; i
< pfp
->pool_size
; i
++) {
291 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
297 if (pfp
->pool
[i
].num_clients
== 0) {
308 static void prefork_cleanup_loop(struct prefork_pool
*pfp
)
314 /* TODO: should we use a process group id wait instead of looping ? */
315 for (i
= 0; i
< pfp
->pool_size
; i
++) {
316 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
||
317 pfp
->pool
[i
].pid
== 0) {
321 pid
= sys_waitpid(pfp
->pool
[i
].pid
, &status
, WNOHANG
);
324 if (pfp
->pool
[i
].status
!= PF_WORKER_EXITING
) {
325 DEBUG(3, ("Child (%d) terminated abnormally:"
326 " %d\n", (int)pid
, status
));
328 DEBUG(10, ("Child (%d) terminated with status:"
329 " %d\n", (int)pid
, status
));
333 * this makes status = PF_WORK_NONE */
334 memset(&pfp
->pool
[i
], 0,
335 sizeof(struct pf_worker_data
));
341 void prefork_increase_allowed_clients(struct prefork_pool
*pfp
, int max
)
345 for (i
= 0; i
< pfp
->pool_size
; i
++) {
346 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
350 if (pfp
->pool
[i
].allowed_clients
< max
) {
351 pfp
->pool
[i
].allowed_clients
++;
356 void prefork_reset_allowed_clients(struct prefork_pool
*pfp
)
360 for (i
= 0; i
< pfp
->pool_size
; i
++) {
361 pfp
->pool
[i
].allowed_clients
= 1;
365 void prefork_send_signal_to_all(struct prefork_pool
*pfp
, int signal_num
)
369 for (i
= 0; i
< pfp
->pool_size
; i
++) {
370 if (pfp
->pool
[i
].status
== PF_WORKER_NONE
) {
374 kill(pfp
->pool
[i
].pid
, signal_num
);
378 static void prefork_sigchld_handler(struct tevent_context
*ev_ctx
,
379 struct tevent_signal
*se
,
380 int signum
, int count
,
381 void *siginfo
, void *pvt
)
383 struct prefork_pool
*pfp
;
385 pfp
= talloc_get_type_abort(pvt
, struct prefork_pool
);
387 /* run the cleanup function to make sure all dead children are
388 * properly and timely retired. */
389 prefork_cleanup_loop(pfp
);
391 if (pfp
->sigchld_fn
) {
392 pfp
->sigchld_fn(ev_ctx
, pfp
, pfp
->sigchld_data
);
396 static bool prefork_setup_sigchld_handler(struct tevent_context
*ev_ctx
,
397 struct prefork_pool
*pfp
)
399 struct tevent_signal
*se
;
401 se
= tevent_add_signal(ev_ctx
, pfp
, SIGCHLD
, 0,
402 prefork_sigchld_handler
, pfp
);
404 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
411 void prefork_set_sigchld_callback(struct prefork_pool
*pfp
,
412 prefork_sigchld_fn_t
*sigchld_fn
,
415 pfp
->sigchld_fn
= sigchld_fn
;
416 pfp
->sigchld_data
= private_data
;
419 /* ==== Functions used by children ==== */
421 static SIG_ATOMIC_T pf_alarm
;
423 static void pf_alarm_cb(int signum
)
431 * pf - the worker shared data structure
432 * lock_fd - the file descriptor used for locking
433 * timeout - expressed in seconds:
435 * 0 timeouts immediately
436 * N seconds before timing out
439 * negative errno on fatal error
440 * 0 on success to acquire lock
441 * -1 on timeout/lock held by other
442 * -2 on server msg to terminate
443 * ERRNO on other errors
446 static int prefork_grab_lock(struct pf_worker_data
*pf
,
447 int lock_fd
, int timeout
)
453 if (pf
->cmds
== PF_SRV_MSG_EXIT
) {
460 CatchSignal(SIGALRM
, pf_alarm_cb
);
473 lock
.l_type
= F_WRLCK
;
474 lock
.l_whence
= SEEK_SET
;
476 ret
= fcntl(lock_fd
, op
, &lock
);
481 if (pf
->cmds
== PF_SRV_MSG_EXIT
) {
492 /* lock held by other proc */
504 } while (timeout
!= 0);
507 /* We have the Lock */
508 pf
->status
= PF_WORKER_ACCEPTING
;
514 CatchSignal(SIGALRM
, SIG_IGN
);
518 DEBUG(1, ("Failed to get lock (%d, %s)!\n",
519 ret
, strerror(ret
)));
526 * pf - the worker shared data structure
527 * lock_fd - the file descriptor used for locking
528 * timeout - expressed in seconds:
530 * 0 timeouts immediately
531 * N seconds before timing out
534 * negative errno on fatal error
535 * 0 on success to release lock
540 static int prefork_release_lock(struct pf_worker_data
*pf
,
541 int lock_fd
, int timeout
)
550 CatchSignal(SIGALRM
, pf_alarm_cb
);
562 lock
.l_type
= F_UNLCK
;
563 lock
.l_whence
= SEEK_SET
;
565 ret
= fcntl(lock_fd
, op
, &lock
);
579 } while (timeout
!= 0);
584 CatchSignal(SIGALRM
, SIG_IGN
);
588 DEBUG(1, ("Failed to release lock (%d, %s)!\n",
589 ret
, strerror(ret
)));
594 /* ==== async code ==== */
596 #define PF_ASYNC_LOCK_GRAB 0x01
597 #define PF_ASYNC_LOCK_RELEASE 0x02
598 #define PF_ASYNC_ACTION_MASK 0x03
599 #define PF_ASYNC_LOCK_DONE 0x04
601 struct pf_lock_state
{
602 struct pf_worker_data
*pf
;
607 static void prefork_lock_handler(struct tevent_context
*ev
,
608 struct tevent_timer
*te
,
609 struct timeval curtime
, void *pvt
);
611 static struct tevent_req
*prefork_lock_send(TALLOC_CTX
*mem_ctx
,
612 struct tevent_context
*ev
,
613 struct pf_worker_data
*pf
,
614 int lock_fd
, int action
)
616 struct tevent_req
*req
;
617 struct pf_lock_state
*state
;
619 req
= tevent_req_create(mem_ctx
, &state
, struct pf_lock_state
);
625 state
->lock_fd
= lock_fd
;
626 state
->flags
= action
;
628 /* try once immediately */
629 prefork_lock_handler(ev
, NULL
, tevent_timeval_zero(), req
);
630 if (state
->flags
& PF_ASYNC_LOCK_DONE
) {
631 tevent_req_post(req
, ev
);
637 static void prefork_lock_handler(struct tevent_context
*ev
,
638 struct tevent_timer
*te
,
639 struct timeval curtime
, void *pvt
)
641 struct tevent_req
*req
;
642 struct pf_lock_state
*state
;
647 req
= talloc_get_type_abort(pvt
, struct tevent_req
);
648 state
= tevent_req_data(req
, struct pf_lock_state
);
650 if (state
->pf
->num_clients
> 0) {
654 switch (state
->flags
& PF_ASYNC_ACTION_MASK
) {
655 case PF_ASYNC_LOCK_GRAB
:
656 ret
= prefork_grab_lock(state
->pf
, state
->lock_fd
, timeout
);
658 case PF_ASYNC_LOCK_RELEASE
:
659 ret
= prefork_release_lock(state
->pf
, state
->lock_fd
, timeout
);
668 state
->flags
|= PF_ASYNC_LOCK_DONE
;
669 tevent_req_done(req
);
673 tv
= tevent_timeval_zero();
675 tv
= tevent_timeval_current_ofs(0, 100000);
677 te
= tevent_add_timer(ev
, state
, tv
,
678 prefork_lock_handler
, req
);
679 tevent_req_nomem(te
, req
);
682 /* server tells us to stop */
683 state
->flags
|= PF_ASYNC_LOCK_DONE
;
684 tevent_req_error(req
, -2);
687 state
->flags
|= PF_ASYNC_LOCK_DONE
;
688 tevent_req_error(req
, ret
);
693 static int prefork_lock_recv(struct tevent_req
*req
)
697 if (!tevent_req_is_unix_error(req
, &ret
)) {
701 tevent_req_received(req
);
705 struct pf_listen_state
{
706 struct tevent_context
*ev
;
707 struct pf_worker_data
*pf
;
714 struct sockaddr
*addr
;
722 static void prefork_listen_lock_done(struct tevent_req
*subreq
);
723 static void prefork_listen_accept_handler(struct tevent_context
*ev
,
724 struct tevent_fd
*fde
,
725 uint16_t flags
, void *pvt
);
726 static void prefork_listen_release_done(struct tevent_req
*subreq
);
728 struct tevent_req
*prefork_listen_send(TALLOC_CTX
*mem_ctx
,
729 struct tevent_context
*ev
,
730 struct pf_worker_data
*pf
,
734 struct sockaddr
*addr
,
737 struct tevent_req
*req
, *subreq
;
738 struct pf_listen_state
*state
;
740 req
= tevent_req_create(mem_ctx
, &state
, struct pf_listen_state
);
747 state
->lock_fd
= lock_fd
;
748 state
->listen_fd_size
= listen_fd_size
;
749 state
->listen_fds
= listen_fds
;
751 state
->addrlen
= addrlen
;
752 state
->accept_fd
= -1;
755 subreq
= prefork_lock_send(state
, state
->ev
, state
->pf
,
756 state
->lock_fd
, PF_ASYNC_LOCK_GRAB
);
757 if (tevent_req_nomem(subreq
, req
)) {
758 return tevent_req_post(req
, ev
);
761 tevent_req_set_callback(subreq
, prefork_listen_lock_done
, req
);
765 struct pf_listen_ctx
{
767 struct tevent_req
*req
;
771 static void prefork_listen_lock_done(struct tevent_req
*subreq
)
773 struct tevent_req
*req
;
774 struct pf_listen_state
*state
;
775 struct pf_listen_ctx
*ctx
;
776 struct tevent_fd
*fde
;
781 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
782 state
= tevent_req_data(req
, struct pf_listen_state
);
784 ret
= prefork_lock_recv(subreq
);
786 tevent_req_error(req
, ret
);
790 fde_ctx
= talloc_new(state
);
791 if (tevent_req_nomem(fde_ctx
, req
)) {
795 /* next step, accept */
796 for (i
= 0; i
< state
->listen_fd_size
; i
++) {
797 ctx
= talloc(fde_ctx
, struct pf_listen_ctx
);
798 if (tevent_req_nomem(ctx
, req
)) {
801 ctx
->fde_ctx
= fde_ctx
;
803 ctx
->listen_fd
= state
->listen_fds
[i
];
805 fde
= tevent_add_fd(state
->ev
, fde_ctx
,
806 ctx
->listen_fd
, TEVENT_FD_READ
,
807 prefork_listen_accept_handler
, ctx
);
808 if (tevent_req_nomem(fde
, req
)) {
814 static void prefork_listen_accept_handler(struct tevent_context
*ev
,
815 struct tevent_fd
*fde
,
816 uint16_t flags
, void *pvt
)
818 struct pf_listen_state
*state
;
819 struct tevent_req
*req
, *subreq
;
820 struct pf_listen_ctx
*ctx
;
824 ctx
= talloc_get_type_abort(pvt
, struct pf_listen_ctx
);
825 state
= tevent_req_data(ctx
->req
, struct pf_listen_state
);
827 sd
= accept(ctx
->listen_fd
, state
->addr
, state
->addrlen
);
829 if (errno
== EINTR
) {
834 DEBUG(6, ("Accept failed! (%d, %s)\n", err
, strerror(err
)));
838 /* do not track the listen fds anymore */
840 talloc_free(ctx
->fde_ctx
);
843 tevent_req_error(req
, err
);
847 state
->accept_fd
= sd
;
849 /* release lock now */
850 subreq
= prefork_lock_send(state
, state
->ev
, state
->pf
,
851 state
->lock_fd
, PF_ASYNC_LOCK_RELEASE
);
852 if (tevent_req_nomem(subreq
, req
)) {
855 tevent_req_set_callback(subreq
, prefork_listen_release_done
, req
);
858 static void prefork_listen_release_done(struct tevent_req
*subreq
)
860 struct tevent_req
*req
;
863 req
= tevent_req_callback_data(subreq
, struct tevent_req
);
865 ret
= prefork_lock_recv(subreq
);
867 tevent_req_error(req
, ret
);
871 tevent_req_done(req
);
874 int prefork_listen_recv(struct tevent_req
*req
, int *fd
)
876 struct pf_listen_state
*state
;
879 state
= tevent_req_data(req
, struct pf_listen_state
);
881 if (tevent_req_is_unix_error(req
, &ret
)) {
882 if (state
->accept_fd
!= -1) {
883 close(state
->accept_fd
);
886 *fd
= state
->accept_fd
;
888 state
->pf
->status
= PF_WORKER_BUSY
;
889 state
->pf
->num_clients
++;
892 tevent_req_received(req
);