2014-03-06 72 views
0

我有一个简单的守护进程,它可以归结为启动停止守护程序不发送SIGTERM

#include <unistd.h> 
#include <signal.h> 
#include <sys/stat.h> 

#include <fstream> 
#include <iostream> 

#include <boost/thread.hpp> 

bool running = true; 
std::ofstream log_output; 

void close_log_output() 
{ 
    log_output.close(); 
} 

void signal_handler(int) 
{ 
    running = false; 
} 

int detach_service() 
{ 
    if(pid_t pid = fork()) exit(pid < 0); 
    umask(0); 
    close(STDIN_FILENO); 
    close(STDOUT_FILENO); 
    close(STDERR_FILENO); 
    chdir("/"); 
    log_output.open("/var/log/mydaemon.log"); 
    std::cout.rdbuf(log_output.rdbuf()); 
    std::cerr.rdbuf(log_output.rdbuf()); 
    std::clog.rdbuf(log_output.rdbuf()); 
    atexit(&close_log_output); 
    signal(SIGTERM, &signal_handler); 
    return (setsid() < 0); 
} 

int main(int argc, char **argv) 
{ 
    if(int err = detach_service()) return err; 
    while(running) boost::this_thread::sleep(boost::posix_time::milliseconds(30)); 
    std::cout << "terminated\n"; 
    return 0; 
} 

和脚本init.d中这仅仅是原来的骨架$NAME$DAEMON$DAEMON_ARGS调整。如果我通过PID终止进程,它会收到一个SIGTERM并正确终止,但是如果我试图停止服务(默认设置为首先发送TERM),该命令会挂起并且进程终止而不会收到SIGTERM。

什么我必须做的/变化,使得该处理正常终止(或者在壳侧或在C++侧)

修饰的骨架(仅NAME和DAEMON_ARGS相比被改变为原来的Ubuntu的的init.d骨架):

#! /bin/sh 
### BEGIN INIT INFO 
# Provides:   skeleton 
# Required-Start: $remote_fs $syslog 
# Required-Stop:  $remote_fs $syslog 
# Default-Start:  2 3 4 5 
# Default-Stop:  0 1 6 
# Short-Description: Example initscript 
# Description:  This file should be used to construct scripts to be 
#     placed in /etc/init.d. 
### END INIT INFO 

# Author: Foo Bar <[email protected]> 
# 
# Please remove the "Author" lines above and replace them 
# with your own name if you copy and modify this script. 

# Do NOT "set -e" 

# PATH should only include /usr/* if it runs after the mountnfs.sh script 
PATH=/sbin:/usr/sbin:/bin:/usr/bin 
DESC="Description of the service" 
NAME=mydaemon 
DAEMON=/usr/sbin/$NAME 
DAEMON_ARGS="" 
PIDFILE=/var/run/$NAME.pid 
SCRIPTNAME=/etc/init.d/$NAME 

# Exit if the package is not installed 
[ -x "$DAEMON" ] || exit 0 

# Read configuration variable file if it is present 
[ -r /etc/default/$NAME ] && . /etc/default/$NAME 

# Load the VERBOSE setting and other rcS variables 
. /lib/init/vars.sh 

# Define LSB log_* functions. 
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present 
# and status_of_proc is working. 
. /lib/lsb/init-functions 

# 
# Function that starts the daemon/service 
# 
do_start() 
{ 
     # Return 
     # 0 if daemon has been started 
     # 1 if daemon was already running 
     # 2 if daemon could not be started 
     start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ 
       || return 1 
     start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 
       $DAEMON_ARGS \ 
       || return 2 
     # Add code here, if necessary, that waits for the process to be ready 
     # to handle requests from services started subsequently which depend 
     # on this one. As a last resort, sleep for some time. 
} 

# 
# Function that stops the daemon/service 
# 
do_stop() 
{ 
     # Return 
     # 0 if daemon has been stopped 
     # 1 if daemon was already stopped 
     # 2 if daemon could not be stopped 
     # other if a failure occurred 
     start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 
     RETVAL="$?" 
     [ "$RETVAL" = 2 ] && return 2 
     # Wait for children to finish too if this is a daemon that forks 
     # and if the daemon is only ever run from this initscript. 
     # If the above conditions are not satisfied then add some other code 
     # that waits for the process to drop all resources that could be 
     # needed by services started subsequently. A last resort is to 
     # sleep for some time. 
     start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON 
     [ "$?" = 2 ] && return 2 
     # Many daemons don't delete their pidfiles when they exit. 
     rm -f $PIDFILE 
     return "$RETVAL" 
} 

# 
# Function that sends a SIGHUP to the daemon/service 
# 
do_reload() { 
     # 
     # If the daemon can reload its configuration without 
     # restarting (for example, when it is sent a SIGHUP), 
     # then implement that here. 
     # 
     start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME 
     return 0 
} 

case "$1" in 
    start) 
     [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 
     do_start 
     case "$?" in 
       0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 
       2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 
     esac 
     ;; 
    stop) 
     [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 
     do_stop 
     case "$?" in 
       0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 
       2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 
     esac 
     ;; 
    status) 
     status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? 
     ;; 
    #reload|force-reload) 
     # 
     # If do_reload() is not implemented then leave this commented out 
     # and leave 'force-reload' as an alias for 'restart'. 
     # 
     #log_daemon_msg "Reloading $DESC" "$NAME" 
     #do_reload 
     #log_end_msg $? 
     #;; 
    restart|force-reload) 
     # 
     # If the "reload" option is implemented then remove the 
     # 'force-reload' alias 
     # 
     log_daemon_msg "Restarting $DESC" "$NAME" 
     do_stop 
     case "$?" in 
      0|1) 
       do_start 
       case "$?" in 
         0) log_end_msg 0 ;; 
         1) log_end_msg 1 ;; # Old process is still running 
         *) log_end_msg 1 ;; # Failed to start 
       esac 
       ;; 
      *) 
       # Failed to stop 
       log_end_msg 1 
       ;; 
     esac 
     ;; 
    *) 
     #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 
     echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 
     exit 3 
     ;; 
esac 

: 
+0

请提供您的骨架init脚本的相关部分。 – user2719058

+0

完成,虽然我已经说过原始问题中有什么变化。 – Joe

+1

尽管如此,并非所有的骨骼都是相同的。感谢您提供你的。 – user2719058

回答

1

您的守护进程不会创建一个pidfile进程文件,而且也不start-stop-daemon。我想第一线

start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 

什么也不做,因为--pidfile过程选择标准是永不满足,但第二线

start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON 

杀死与SIGKILL守护进程,因为这里不包括--pidfile选项。

你应该修复你的守护进程来创建一个pidfile。

+0

好吧,但我如何正确创建一个pidfile?将'--make-pidfile'添加到start-stop-daemon选项不起作用 – Joe

+0

'start-stop-daemon'的'--make-pidfile'选项只是破解守护程序的一种解决方法,并且正如手册页所述,这对分叉守护进程没有帮助。让守护进程自己创建它,这是正确的方法。 – user2719058

+0

显然。我宁愿意味着如何在守护进程中正确执行该操作?只是一个fopen,fprintf和fclose? – Joe