2012-05-03 05:42:41 +04:00
/*
functions to track and manage processes
Copyright ( C ) Ronnie Sahlberg 2012
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 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
2012-05-03 05:42:41 +04:00
# include "system/wait.h"
2015-10-26 08:50:46 +03:00
# include "system/network.h"
# include <talloc.h>
# include <tevent.h>
# include "lib/util/debug.h"
2016-09-15 09:10:49 +03:00
# include "lib/util/time.h"
2015-10-26 08:50:46 +03:00
# include "ctdb_private.h"
# include "ctdb_client.h"
# include "common/rb_tree.h"
2015-10-23 06:11:53 +03:00
# include "common/system.h"
2015-10-23 06:17:34 +03:00
# include "common/common.h"
2015-11-11 07:41:10 +03:00
# include "common/logging.h"
2012-05-03 05:42:41 +04:00
2013-11-19 09:13:20 +04:00
void ctdb_track_child ( struct ctdb_context * ctdb , pid_t pid )
{
char * process ;
/* Only CTDB main daemon should track child processes */
if ( getpid ( ) ! = ctdb - > ctdbd_pid ) {
return ;
}
process = talloc_asprintf ( ctdb - > child_processes , " process:%d " , ( int ) pid ) ;
trbt_insert32 ( ctdb - > child_processes , pid , process ) ;
}
2012-05-03 05:42:41 +04:00
/*
* This function forks a child process and drops the realtime
* scheduler for the child process .
*/
2014-08-08 06:51:03 +04:00
pid_t ctdb_fork ( struct ctdb_context * ctdb )
2012-05-03 05:42:41 +04:00
{
pid_t pid ;
2016-09-15 09:10:49 +03:00
struct timeval before ;
double delta_t ;
before = timeval_current ( ) ;
2012-05-03 05:42:41 +04:00
pid = fork ( ) ;
if ( pid = = - 1 ) {
2016-04-01 12:01:51 +03:00
DEBUG ( DEBUG_ERR ,
( __location__ " fork() failed (%s) \n " , strerror ( errno ) ) ) ;
2012-05-03 05:42:41 +04:00
return - 1 ;
}
if ( pid = = 0 ) {
2012-10-02 05:51:24 +04:00
/* Close the Unix Domain socket and the TCP socket.
* This ensures that none of the child processes will
* look like the main daemon when it is not running .
* tevent needs to be stopped before closing sockets .
*/
if ( ctdb - > ev ! = NULL ) {
talloc_free ( ctdb - > ev ) ;
ctdb - > ev = NULL ;
}
if ( ctdb - > daemon . sd ! = - 1 ) {
close ( ctdb - > daemon . sd ) ;
ctdb - > daemon . sd = - 1 ;
}
2016-06-27 11:00:49 +03:00
if ( ctdb - > methods ! = NULL & & ctdb - > methods - > shutdown ! = NULL ) {
2012-10-02 05:51:24 +04:00
ctdb - > methods - > shutdown ( ctdb ) ;
}
/* The child does not need to be realtime */
2012-05-03 05:42:41 +04:00
if ( ctdb - > do_setsched ) {
2014-06-10 10:48:03 +04:00
reset_scheduler ( ) ;
2012-05-03 05:42:41 +04:00
}
ctdb - > can_send_controls = false ;
2013-02-05 05:09:36 +04:00
2012-05-03 05:42:41 +04:00
return 0 ;
}
2016-09-15 09:10:49 +03:00
delta_t = timeval_elapsed ( & before ) ;
if ( delta_t > 3.0 ) {
DEBUG ( DEBUG_WARNING , ( " fork() took %lf seconds \n " , delta_t ) ) ;
}
2013-11-19 09:13:20 +04:00
ctdb_track_child ( ctdb , pid ) ;
2012-05-03 05:42:41 +04:00
return pid ;
}
2016-11-30 04:15:11 +03:00
/*
* vfork + exec
*/
pid_t ctdb_vfork_exec ( TALLOC_CTX * mem_ctx , struct ctdb_context * ctdb ,
const char * helper , int helper_argc ,
const char * * helper_argv )
{
pid_t pid ;
struct timeval before ;
double delta_t ;
char * * argv ;
int i ;
argv = talloc_array ( mem_ctx , char * , helper_argc + 1 ) ;
if ( argv = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Memory allocation error \n " ) ) ;
return - 1 ;
}
argv [ 0 ] = discard_const ( helper ) ;
for ( i = 0 ; i < helper_argc ; i + + ) {
argv [ i + 1 ] = discard_const ( helper_argv [ i ] ) ;
}
before = timeval_current ( ) ;
pid = vfork ( ) ;
if ( pid = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " vfork() failed (%s) \n " , strerror ( errno ) ) ) ;
return - 1 ;
}
if ( pid = = 0 ) {
execv ( helper , argv ) ;
_exit ( 1 ) ;
}
delta_t = timeval_elapsed ( & before ) ;
if ( delta_t > 3.0 ) {
DEBUG ( DEBUG_WARNING , ( " vfork() took %lf seconds \n " , delta_t ) ) ;
}
ctdb_track_child ( ctdb , pid ) ;
return pid ;
}
2012-05-03 05:42:41 +04:00
static void ctdb_sigchld_handler ( struct tevent_context * ev ,
struct tevent_signal * te , int signum , int count ,
void * dont_care ,
void * private_data )
{
struct ctdb_context * ctdb = talloc_get_type ( private_data , struct ctdb_context ) ;
int status ;
pid_t pid = - 1 ;
while ( pid ! = 0 ) {
pid = waitpid ( - 1 , & status , WNOHANG ) ;
if ( pid = = - 1 ) {
DEBUG ( DEBUG_ERR , ( __location__ " waitpid() returned error. errno:%d \n " , errno ) ) ;
return ;
}
if ( pid > 0 ) {
char * process ;
if ( getpid ( ) ! = ctdb - > ctdbd_pid ) {
continue ;
}
process = trbt_lookup32 ( ctdb - > child_processes , pid ) ;
if ( process = = NULL ) {
DEBUG ( DEBUG_ERR , ( " Got SIGCHLD from pid:%d we didn not spawn with ctdb_fork \n " , pid ) ) ;
}
DEBUG ( DEBUG_DEBUG , ( " SIGCHLD from %d %s \n " , ( int ) pid , process ) ) ;
talloc_free ( process ) ;
}
}
}
struct tevent_signal *
ctdb_init_sigchld ( struct ctdb_context * ctdb )
{
struct tevent_signal * se ;
ctdb - > child_processes = trbt_create ( ctdb , 0 ) ;
se = tevent_add_signal ( ctdb - > ev , ctdb , SIGCHLD , 0 , ctdb_sigchld_handler , ctdb ) ;
return se ;
}
int
ctdb_kill ( struct ctdb_context * ctdb , pid_t pid , int signum )
{
char * process ;
if ( signum = = 0 ) {
return kill ( pid , signum ) ;
}
if ( getpid ( ) ! = ctdb - > ctdbd_pid ) {
return kill ( pid , signum ) ;
}
process = trbt_lookup32 ( ctdb - > child_processes , pid ) ;
if ( process = = NULL ) {
DEBUG ( DEBUG_ERR , ( " ctdb_kill: trying to kill(%d, %d) a process that does not exist \n " , pid , signum ) ) ;
return 0 ;
}
return kill ( pid , signum ) ;
}