2019-04-01 05:29:53 -04:00
/*
* Master Worker
*
* Copyright HAProxy Technologies 2019 - William Lallemand < wlallemand @ haproxy . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
2019-04-01 05:29:55 -04:00
# include <errno.h>
# include <fcntl.h>
# include <signal.h>
2019-04-01 05:29:53 -04:00
# include <stdlib.h>
# include <string.h>
2019-04-01 05:29:56 -04:00
# include <sys/wait.h>
2019-04-01 05:29:53 -04:00
2019-05-07 11:49:33 -04:00
# include <common/cfgparse.h>
2019-04-01 05:30:01 -04:00
# include <common/initcall.h>
2019-04-01 05:29:53 -04:00
# include <common/mini-clist.h>
2019-04-01 05:30:01 -04:00
# include <types/cli.h>
# include <types/global.h>
# include <types/peers.h>
# include <types/signal.h>
# include <proto/cli.h>
2019-04-01 05:29:55 -04:00
# include <proto/fd.h>
# include <proto/listener.h>
2019-04-01 05:29:56 -04:00
# include <proto/log.h>
2019-04-01 05:29:53 -04:00
# include <proto/mworker.h>
2019-04-01 05:30:01 -04:00
# include <proto/proxy.h>
2019-04-01 05:29:54 -04:00
# include <proto/signal.h>
2019-04-01 05:30:01 -04:00
# include <proto/stream.h>
# include <proto/stream_interface.h>
2019-04-01 05:29:53 -04:00
2019-04-01 05:29:56 -04:00
# if defined(USE_SYSTEMD)
# include <systemd/sd-daemon.h>
# endif
static int exitcode = - 1 ;
2019-05-07 11:49:33 -04:00
static int max_reloads = - 1 ; /* number max of reloads a worker can have until they are killed */
2019-04-01 05:29:56 -04:00
/* ----- children processes handling ----- */
/*
* Send signal to every known children .
*/
static void mworker_kill ( int sig )
{
2019-04-01 05:29:59 -04:00
struct mworker_proc * child ;
2019-04-01 05:29:56 -04:00
2019-04-01 05:29:59 -04:00
list_for_each_entry ( child , & proc_list , list ) {
/* careful there, we must be sure that the pid > 0, we don't want to emit a kill -1 */
2019-04-16 11:42:42 -04:00
if ( ( child - > options & ( PROC_O_TYPE_WORKER | PROC_O_TYPE_PROG ) ) & & ( child - > pid > 0 ) )
2019-04-01 05:29:59 -04:00
kill ( child - > pid , sig ) ;
2019-04-01 05:29:56 -04:00
}
}
2019-05-07 11:49:33 -04:00
void mworker_kill_max_reloads ( int sig )
{
struct mworker_proc * child ;
list_for_each_entry ( child , & proc_list , list ) {
if ( max_reloads ! = - 1 & & ( child - > options & PROC_O_TYPE_WORKER ) & &
( child - > pid > 0 ) & & ( child - > reloads > max_reloads ) )
kill ( child - > pid , sig ) ;
}
}
2019-04-01 05:29:56 -04:00
/* return 1 if a pid is a current child otherwise 0 */
2019-04-01 05:29:59 -04:00
int mworker_current_child ( int pid )
2019-04-01 05:29:56 -04:00
{
2019-04-01 05:29:59 -04:00
struct mworker_proc * child ;
2019-04-01 05:29:56 -04:00
2019-04-01 05:29:59 -04:00
list_for_each_entry ( child , & proc_list , list ) {
2019-04-12 10:09:23 -04:00
if ( ( child - > options & ( PROC_O_TYPE_WORKER | PROC_O_TYPE_PROG ) ) & & ( ! ( child - > options & PROC_O_LEAVING ) ) & & ( child - > pid = = pid ) )
2019-04-01 05:29:56 -04:00
return 1 ;
}
return 0 ;
}
2019-04-01 05:29:53 -04:00
2019-04-01 05:29:59 -04:00
/*
* Return the number of new and old children ( including workers and external
* processes )
*/
int mworker_child_nb ( )
{
struct mworker_proc * child ;
int ret = 0 ;
list_for_each_entry ( child , & proc_list , list ) {
2019-04-12 10:09:23 -04:00
if ( child - > options & ( PROC_O_TYPE_WORKER | PROC_O_TYPE_PROG ) )
2019-04-01 05:29:59 -04:00
ret + + ;
}
return ret ;
}
2019-04-01 05:29:53 -04:00
/*
* serialize the proc list and put it in the environment
*/
void mworker_proc_list_to_env ( )
{
char * msg = NULL ;
struct mworker_proc * child ;
list_for_each_entry ( child , & proc_list , list ) {
2019-04-12 10:09:23 -04:00
char type = ' ? ' ;
if ( child - > options & PROC_O_TYPE_MASTER )
type = ' m ' ;
else if ( child - > options & PROC_O_TYPE_PROG )
type = ' e ' ;
else if ( child - > options & = PROC_O_TYPE_WORKER )
type = ' w ' ;
2019-04-01 05:29:53 -04:00
if ( child - > pid > - 1 )
2019-04-12 10:09:23 -04:00
memprintf ( & msg , " %s|type=%c;fd=%d;pid=%d;rpid=%d;reloads=%d;timestamp=%d;id=%s " , msg ? msg : " " , type , child - > ipc_fd [ 0 ] , child - > pid , child - > relative_pid , child - > reloads , child - > timestamp , child - > id ? child - > id : " " ) ;
2019-04-01 05:29:53 -04:00
}
if ( msg )
setenv ( " HAPROXY_PROCESSES " , msg , 1 ) ;
}
/*
* unserialize the proc list from the environment
*/
void mworker_env_to_proc_list ( )
{
char * msg , * token = NULL , * s1 ;
msg = getenv ( " HAPROXY_PROCESSES " ) ;
if ( ! msg )
return ;
while ( ( token = strtok_r ( msg , " | " , & s1 ) ) ) {
struct mworker_proc * child ;
char * subtoken = NULL ;
char * s2 ;
msg = NULL ;
child = calloc ( 1 , sizeof ( * child ) ) ;
while ( ( subtoken = strtok_r ( token , " ; " , & s2 ) ) ) {
token = NULL ;
if ( strncmp ( subtoken , " type= " , 5 ) = = 0 ) {
2019-04-12 10:09:23 -04:00
char type ;
type = * ( subtoken + 5 ) ;
if ( type = = ' m ' ) { /* we are in the master, assign it */
2019-04-01 05:29:53 -04:00
proc_self = child ;
2019-04-12 10:09:23 -04:00
child - > options | = PROC_O_TYPE_MASTER ;
} else if ( type = = ' e ' ) {
child - > options | = PROC_O_TYPE_PROG ;
} else if ( type = = ' w ' ) {
child - > options | = PROC_O_TYPE_WORKER ;
}
2019-04-01 05:29:53 -04:00
} else if ( strncmp ( subtoken , " fd= " , 3 ) = = 0 ) {
child - > ipc_fd [ 0 ] = atoi ( subtoken + 3 ) ;
} else if ( strncmp ( subtoken , " pid= " , 4 ) = = 0 ) {
child - > pid = atoi ( subtoken + 4 ) ;
} else if ( strncmp ( subtoken , " rpid= " , 5 ) = = 0 ) {
child - > relative_pid = atoi ( subtoken + 5 ) ;
} else if ( strncmp ( subtoken , " reloads= " , 8 ) = = 0 ) {
/* we reloaded this process once more */
child - > reloads = atoi ( subtoken + 8 ) + 1 ;
} else if ( strncmp ( subtoken , " timestamp= " , 10 ) = = 0 ) {
child - > timestamp = atoi ( subtoken + 10 ) ;
2019-04-01 05:30:02 -04:00
} else if ( strncmp ( subtoken , " id= " , 3 ) = = 0 ) {
child - > id = strdup ( subtoken + 3 ) ;
2019-04-01 05:29:53 -04:00
}
}
2019-04-01 05:30:02 -04:00
if ( child - > pid ) {
2019-05-14 05:15:18 -04:00
/* this is a process inherited from a reload that should be leaving */
child - > options | = PROC_O_LEAVING ;
2019-04-01 05:29:53 -04:00
LIST_ADDQ ( & proc_list , & child - > list ) ;
2019-04-01 05:30:02 -04:00
} else {
2019-05-16 14:23:22 -04:00
mworker_free_child ( child ) ;
2019-04-01 05:30:02 -04:00
}
2019-04-01 05:29:53 -04:00
}
unsetenv ( " HAPROXY_PROCESSES " ) ;
}
2019-04-01 05:29:54 -04:00
/* Signal blocking and unblocking */
void mworker_block_signals ( )
{
sigset_t set ;
sigemptyset ( & set ) ;
sigaddset ( & set , SIGUSR1 ) ;
sigaddset ( & set , SIGUSR2 ) ;
sigaddset ( & set , SIGHUP ) ;
sigaddset ( & set , SIGCHLD ) ;
ha_sigmask ( SIG_SETMASK , & set , NULL ) ;
}
void mworker_unblock_signals ( )
{
haproxy_unblock_signals ( ) ;
}
2019-04-01 05:29:55 -04:00
2019-04-01 05:29:56 -04:00
/* ----- mworker signal handlers ----- */
/*
* When called , this function reexec haproxy with - sf followed by current
* children PIDs and possibly old children PIDs if they didn ' t leave yet .
*/
void mworker_catch_sighup ( struct sig_handler * sh )
{
mworker_reload ( ) ;
}
void mworker_catch_sigterm ( struct sig_handler * sh )
{
int sig = sh - > arg ;
# if defined(USE_SYSTEMD)
if ( global . tune . options & GTUNE_USE_SYSTEMD ) {
sd_notify ( 0 , " STOPPING=1 " ) ;
}
# endif
ha_warning ( " Exiting Master process... \n " ) ;
mworker_kill ( sig ) ;
}
/*
* Wait for every children to exit
*/
void mworker_catch_sigchld ( struct sig_handler * sh )
{
int exitpid = - 1 ;
int status = 0 ;
int childfound ;
restart_wait :
childfound = 0 ;
exitpid = waitpid ( - 1 , & status , WNOHANG ) ;
if ( exitpid > 0 ) {
2019-05-16 14:23:22 -04:00
struct mworker_proc * child , * it ;
2019-04-01 05:29:56 -04:00
if ( WIFEXITED ( status ) )
status = WEXITSTATUS ( status ) ;
else if ( WIFSIGNALED ( status ) )
status = 128 + WTERMSIG ( status ) ;
else if ( WIFSTOPPED ( status ) )
status = 128 + WSTOPSIG ( status ) ;
else
status = 255 ;
2019-04-01 05:29:59 -04:00
/* delete the child from the process list */
2019-04-01 05:29:56 -04:00
list_for_each_entry_safe ( child , it , & proc_list , list ) {
if ( child - > pid ! = exitpid )
continue ;
LIST_DEL ( & child - > list ) ;
close ( child - > ipc_fd [ 0 ] ) ;
childfound = 1 ;
break ;
}
2019-04-01 05:29:59 -04:00
if ( ! childfound ) {
/* We didn't find the PID in the list, that shouldn't happen but we can emit a warning */
2019-04-01 05:30:02 -04:00
ha_warning ( " Process %d exited with code %d (%s) \n " , exitpid , status , ( status > = 128 ) ? strsignal ( status - 128 ) : " Exit " ) ;
2019-04-01 05:29:56 -04:00
} else {
2019-04-01 05:30:02 -04:00
/* check if exited child is a current child */
2019-04-12 10:09:21 -04:00
if ( ! ( child - > options & PROC_O_LEAVING ) ) {
2019-04-12 10:09:23 -04:00
if ( child - > options & PROC_O_TYPE_WORKER )
2019-04-01 05:29:59 -04:00
ha_alert ( " Current worker #%d (%d) exited with code %d (%s) \n " , child - > relative_pid , exitpid , status , ( status > = 128 ) ? strsignal ( status - 128 ) : " Exit " ) ;
2019-04-12 10:09:23 -04:00
else if ( child - > options & PROC_O_TYPE_PROG )
2019-04-01 05:30:02 -04:00
ha_alert ( " Current program '%s' (%d) exited with code %d (%s) \n " , child - > id , exitpid , status , ( status > = 128 ) ? strsignal ( status - 128 ) : " Exit " ) ;
2019-04-01 05:29:59 -04:00
2019-04-01 05:29:56 -04:00
if ( status ! = 0 & & status ! = 130 & & status ! = 143
& & ! ( global . tune . options & GTUNE_NOEXIT_ONFAILURE ) ) {
2019-04-01 05:30:02 -04:00
ha_alert ( " exit-on-failure: killing every processes with SIGTERM \n " ) ;
2019-04-01 05:29:56 -04:00
mworker_kill ( SIGTERM ) ;
}
2019-04-16 11:42:44 -04:00
/* 0 & SIGTERM (143) are normal, but we should report SIGINT (130) and other signals */
if ( exitcode < 0 & & status ! = 0 & & status ! = 143 )
exitcode = status ;
2019-04-01 05:29:56 -04:00
} else {
2019-04-12 10:09:23 -04:00
if ( child - > options & PROC_O_TYPE_WORKER ) {
2019-04-01 05:29:59 -04:00
ha_warning ( " Former worker #%d (%d) exited with code %d (%s) \n " , child - > relative_pid , exitpid , status , ( status > = 128 ) ? strsignal ( status - 128 ) : " Exit " ) ;
delete_oldpid ( exitpid ) ;
2019-04-12 10:09:23 -04:00
} else if ( child - > options & PROC_O_TYPE_PROG ) {
2019-04-01 05:30:02 -04:00
ha_warning ( " Former program '%s' (%d) exited with code %d (%s) \n " , child - > id , exitpid , status , ( status > = 128 ) ? strsignal ( status - 128 ) : " Exit " ) ;
2019-04-01 05:29:59 -04:00
}
2019-04-01 05:29:56 -04:00
}
2019-05-16 14:23:22 -04:00
mworker_free_child ( child ) ;
child = NULL ;
2019-04-01 05:29:56 -04:00
}
/* do it again to check if it was the last worker */
goto restart_wait ;
}
/* Better rely on the system than on a list of process to check if it was the last one */
else if ( exitpid = = - 1 & & errno = = ECHILD ) {
2019-04-16 11:42:43 -04:00
ha_warning ( " All workers exited. Exiting... (%d) \n " , ( exitcode > 0 ) ? exitcode : EXIT_SUCCESS ) ;
2019-04-01 05:29:56 -04:00
atexit_flag = 0 ;
if ( exitcode > 0 )
2019-04-16 11:42:43 -04:00
exit ( exitcode ) ; /* parent must leave using the status code that provoked the exit */
exit ( EXIT_SUCCESS ) ;
2019-04-01 05:29:56 -04:00
}
}
2019-04-01 05:29:55 -04:00
/* ----- IPC FD (sockpair) related ----- */
/* This wrapper is called from the workers. It is registered instead of the
* normal listener_accept ( ) so the worker can exit ( ) when it detects that the
* master closed the IPC FD . If it ' s not a close , we just call the regular
* listener_accept ( ) function */
void mworker_accept_wrapper ( int fd )
{
char c ;
int ret ;
while ( 1 ) {
ret = recv ( fd , & c , 1 , MSG_PEEK ) ;
if ( ret = = - 1 ) {
if ( errno = = EINTR )
continue ;
if ( errno = = EAGAIN ) {
fd_cant_recv ( fd ) ;
return ;
}
break ;
} else if ( ret > 0 ) {
listener_accept ( fd ) ;
return ;
} else if ( ret = = 0 ) {
/* At this step the master is down before
* this worker perform a ' normal ' exit .
* So we want to exit with an error but
* other threads could currently process
* some stuff so we can ' t perform a clean
* deinit ( ) .
*/
exit ( EXIT_FAILURE ) ;
}
}
return ;
}
/*
2019-05-20 05:12:15 -04:00
* This function registers the accept wrapper for the sockpair of the master
* worker . It ' s only handled by worker thread # 0. Other threads and master do
* nothing here . It always returns 1 ( success ) .
2019-04-01 05:29:55 -04:00
*/
2019-05-20 05:12:15 -04:00
static int mworker_pipe_register_per_thread ( )
2019-04-01 05:29:55 -04:00
{
2019-05-20 05:12:15 -04:00
if ( ! ( global . mode & MODE_MWORKER ) | | master )
return 1 ;
if ( tid ! = 0 )
return 1 ;
2019-04-01 05:29:55 -04:00
fcntl ( proc_self - > ipc_fd [ 1 ] , F_SETFL , O_NONBLOCK ) ;
/* In multi-tread, we need only one thread to process
* events on the pipe with master
*/
2019-05-20 05:12:15 -04:00
fd_insert ( proc_self - > ipc_fd [ 1 ] , fdtab [ proc_self - > ipc_fd [ 1 ] ] . owner , mworker_accept_wrapper , tid_bit ) ;
2019-04-01 05:29:55 -04:00
fd_want_recv ( proc_self - > ipc_fd [ 1 ] ) ;
2019-05-20 05:12:15 -04:00
return 1 ;
2019-04-01 05:29:55 -04:00
}
2019-04-01 05:29:57 -04:00
2019-05-20 05:12:15 -04:00
REGISTER_PER_THREAD_INIT ( mworker_pipe_register_per_thread ) ;
2019-04-01 05:29:57 -04:00
/* ----- proxies ----- */
/*
* Upon a reload , the master worker needs to close all listeners FDs but the mworker_pipe
* fd , and the FD provided by fd @
*/
void mworker_cleanlisteners ( )
{
struct listener * l , * l_next ;
struct proxy * curproxy ;
struct peers * curpeers ;
/* we might have to unbind some peers sections from some processes */
for ( curpeers = cfg_peers ; curpeers ; curpeers = curpeers - > next ) {
if ( ! curpeers - > peers_fe )
continue ;
stop_proxy ( curpeers - > peers_fe ) ;
/* disable this peer section so that it kills itself */
signal_unregister_handler ( curpeers - > sighandler ) ;
2019-04-17 16:51:06 -04:00
task_destroy ( curpeers - > sync_task ) ;
2019-04-01 05:29:57 -04:00
curpeers - > sync_task = NULL ;
2019-04-17 16:51:06 -04:00
task_destroy ( curpeers - > peers_fe - > task ) ;
2019-04-01 05:29:57 -04:00
curpeers - > peers_fe - > task = NULL ;
curpeers - > peers_fe = NULL ;
}
for ( curproxy = proxies_list ; curproxy ; curproxy = curproxy - > next ) {
int listen_in_master = 0 ;
list_for_each_entry_safe ( l , l_next , & curproxy - > conf . listeners , by_fe ) {
/* remove the listener, but not those we need in the master... */
if ( ! ( l - > options & LI_O_MWORKER ) ) {
/* unbind the listener but does not close if
the FD is inherited with fd @ from the parent
process */
if ( l - > options & LI_O_INHERITED )
unbind_listener_no_close ( l ) ;
else
unbind_listener ( l ) ;
delete_listener ( l ) ;
} else {
listen_in_master = 1 ;
}
}
/* if the proxy shouldn't be in the master, we stop it */
if ( ! listen_in_master )
curproxy - > state = PR_STSTOPPED ;
}
}
2019-04-01 05:30:01 -04:00
/* Displays workers and processes */
static int cli_io_handler_show_proc ( struct appctx * appctx )
{
struct stream_interface * si = appctx - > owner ;
struct mworker_proc * child ;
int old = 0 ;
int up = now . tv_sec - proc_self - > timestamp ;
if ( unlikely ( si_ic ( si ) - > flags & ( CF_WRITE_ERROR | CF_SHUTW ) ) )
return 1 ;
chunk_reset ( & trash ) ;
chunk_printf ( & trash , " #%-14s %-15s %-15s %-15s %s \n " , " <PID> " , " <type> " , " <relative PID> " , " <reloads> " , " <uptime> " ) ;
chunk_appendf ( & trash , " %-15u %-15s %-15u %-15d %dd %02dh%02dm%02ds \n " , getpid ( ) , " master " , 0 , proc_self - > reloads , up / 86400 , ( up % 86400 ) / 3600 , ( up % 3600 ) / 60 , ( up % 60 ) ) ;
/* displays current processes */
chunk_appendf ( & trash , " # workers \n " ) ;
list_for_each_entry ( child , & proc_list , list ) {
up = now . tv_sec - child - > timestamp ;
2019-04-12 10:09:23 -04:00
if ( ! ( child - > options & PROC_O_TYPE_WORKER ) )
2019-04-01 05:30:01 -04:00
continue ;
2019-04-12 10:09:21 -04:00
if ( child - > options & PROC_O_LEAVING ) {
2019-04-01 05:30:01 -04:00
old + + ;
continue ;
}
chunk_appendf ( & trash , " %-15u %-15s %-15u %-15d %dd %02dh%02dm%02ds \n " , child - > pid , " worker " , child - > relative_pid , child - > reloads , up / 86400 , ( up % 86400 ) / 3600 , ( up % 3600 ) / 60 , ( up % 60 ) ) ;
}
/* displays old processes */
if ( old ) {
char * msg = NULL ;
chunk_appendf ( & trash , " # old workers \n " ) ;
list_for_each_entry ( child , & proc_list , list ) {
up = now . tv_sec - child - > timestamp ;
2019-04-12 10:09:23 -04:00
if ( ! ( child - > options & PROC_O_TYPE_WORKER ) )
2019-04-01 05:30:01 -04:00
continue ;
2019-04-12 10:09:21 -04:00
if ( child - > options & PROC_O_LEAVING ) {
2019-04-01 05:30:01 -04:00
memprintf ( & msg , " [was: %u] " , child - > relative_pid ) ;
chunk_appendf ( & trash , " %-15u %-15s %-15s %-15d %dd %02dh%02dm%02ds \n " , child - > pid , " worker " , msg , child - > reloads , up / 86400 , ( up % 86400 ) / 3600 , ( up % 3600 ) / 60 , ( up % 60 ) ) ;
}
}
free ( msg ) ;
}
2019-04-01 05:30:03 -04:00
/* displays external process */
chunk_appendf ( & trash , " # programs \n " ) ;
old = 0 ;
list_for_each_entry ( child , & proc_list , list ) {
up = now . tv_sec - child - > timestamp ;
2019-04-12 10:09:23 -04:00
if ( ! ( child - > options & PROC_O_TYPE_PROG ) )
2019-04-01 05:30:03 -04:00
continue ;
2019-04-12 10:09:21 -04:00
if ( child - > options & PROC_O_LEAVING ) {
2019-04-01 05:30:03 -04:00
old + + ;
continue ;
}
chunk_appendf ( & trash , " %-15u %-15s %-15s %-15d %dd %02dh%02dm%02ds \n " , child - > pid , child - > id , " - " , child - > reloads , up / 86400 , ( up % 86400 ) / 3600 , ( up % 3600 ) / 60 , ( up % 60 ) ) ;
}
if ( old ) {
chunk_appendf ( & trash , " # old programs \n " ) ;
list_for_each_entry ( child , & proc_list , list ) {
up = now . tv_sec - child - > timestamp ;
2019-04-12 10:09:23 -04:00
if ( ! ( child - > options & PROC_O_TYPE_PROG ) )
2019-04-01 05:30:03 -04:00
continue ;
2019-04-12 10:09:21 -04:00
if ( child - > options & PROC_O_LEAVING ) {
2019-04-01 05:30:03 -04:00
chunk_appendf ( & trash , " %-15u %-15s %-15s %-15d %dd %02dh%02dm%02ds \n " , child - > pid , child - > id , " - " , child - > reloads , up / 86400 , ( up % 86400 ) / 3600 , ( up % 3600 ) / 60 , ( up % 60 ) ) ;
}
}
}
2019-04-01 05:30:01 -04:00
if ( ci_putchk ( si_ic ( si ) , & trash ) = = - 1 ) {
si_rx_room_blk ( si ) ;
return 0 ;
}
/* dump complete */
return 1 ;
}
/* reload the master process */
static int cli_parse_reload ( char * * args , char * payload , struct appctx * appctx , void * private )
{
if ( ! cli_has_level ( appctx , ACCESS_LVL_OPER ) )
return 1 ;
mworker_reload ( ) ;
return 1 ;
}
2019-05-07 11:49:33 -04:00
static int mworker_parse_global_max_reloads ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int linenum , char * * err )
{
int err_code = 0 ;
if ( alertif_too_many_args ( 1 , file , linenum , args , & err_code ) )
goto out ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " %sparsing [%s:%d] : '%s' expects an integer argument. \n " , * err , file , linenum , args [ 0 ] ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
max_reloads = atol ( args [ 1 ] ) ;
if ( max_reloads < 0 ) {
memprintf ( err , " %sparsing [%s:%d] '%s' : invalid value %d, must be >= 0 " , * err , file , linenum , args [ 0 ] , max_reloads ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
out :
return err_code ;
}
2019-05-16 14:23:22 -04:00
void mworker_free_child ( struct mworker_proc * child )
{
if ( child = = NULL )
return ;
if ( child - > command ) {
int i ;
for ( i = 0 ; child - > command [ i ] ; i + + ) {
if ( child - > command [ i ] ) {
free ( child - > command [ i ] ) ;
child - > command [ i ] = NULL ;
}
}
free ( child - > command ) ;
child - > command = NULL ;
}
if ( child - > id ) {
free ( child - > id ) ;
child - > id = NULL ;
}
free ( child ) ;
}
2019-05-07 11:49:33 -04:00
static struct cfg_kw_list mworker_kws = { { } , {
{ CFG_GLOBAL , " mworker-max-reloads " , mworker_parse_global_max_reloads } ,
{ 0 , NULL , NULL } ,
} } ;
INITCALL1 ( STG_REGISTER , cfg_register_keywords , & mworker_kws ) ;
2019-04-01 05:30:01 -04:00
/* register cli keywords */
static struct cli_kw_list cli_kws = { { } , {
{ { " @<relative pid> " , NULL } , " @<relative pid> : send a command to the <relative pid> process " , NULL , cli_io_handler_show_proc , NULL , NULL , ACCESS_MASTER_ONLY } ,
{ { " @!<pid> " , NULL } , " @!<pid> : send a command to the <pid> process " , cli_parse_default , NULL , NULL , NULL , ACCESS_MASTER_ONLY } ,
{ { " @master " , NULL } , " @master : send a command to the master process " , cli_parse_default , NULL , NULL , NULL , ACCESS_MASTER_ONLY } ,
{ { " show " , " proc " , NULL } , " show proc : show processes status " , cli_parse_default , cli_io_handler_show_proc , NULL , NULL , ACCESS_MASTER_ONLY } ,
{ { " reload " , NULL } , " reload : reload haproxy " , cli_parse_reload , NULL , NULL , NULL , ACCESS_MASTER_ONLY } ,
{ { } , }
} } ;
INITCALL1 ( STG_REGISTER , cli_register_kw , & cli_kws ) ;