0%

kill pppd 之后串口不能正常工作

本文介绍 pppd 对信号 SIGTERM 的处理,以及错误方式关闭 pppd 带来的问题

现象

GPRS 模块正常工作之后需要关闭来使用串口 /dev/ttyS0,此时串口工作不正常

关闭方式为

kill -9 pppd call wcdma

解决方案

将关闭方式修改为 pppd 提供的 ppp-off

#!/bin/sh
######################################################################
#
# Determine the device to be terminated.
#
if [ "$1" = "" ]; then
    DEVICE=ppp0
else
    DEVICE=$1
fi

######################################################################
#
# If the ppp0 pid file is present then the program is running. Stop it.
if [ -r /var/run/$DEVICE.pid ]; then
        kill -INT `cat /var/run/$DEVICE.pid`
#
# If the kill did not work then there is no process running for this
# pid. It may also mean that the lock file will be left. You may wish
# to delete the lock file at the same time.
        if [ ! "$?" = "0" ]; then
                rm -f /var/run/$DEVICE.pid
                echo "ERROR: Removed stale pid file"
                exit 1
        fi
#
# Success. Let pppd clean up its own junk.
        echo "PPP link to $DEVICE terminated."
        exit 0
fi
#
# The ppp process is not running for ppp0
echo "ERROR: PPP link is not active on $DEVICE"
exit 1

分析

kill 发送的信号存在差异 SIGKILLSIGTERM

man pppd 得到如下信息:

SIGINT, SIGTERM
    These  signals  cause  pppd  to terminate the link (by closing LCP), restore the serial device settings, and exit.  If a connector or disconnector process is currently
    running, pppd will send the same signal to its process group, so as to terminate the connector or disconnector process.

因此需要使用 kill 来发送信号 SIGTERM 来完成回收操作

sourcecode

static void setup_signals()
{
    struct sigaction sa;

    /*
     * Compute mask of all interesting signals and install signal handlers
     * for each.  Only one signal handler may be active at a time.  Therefore,
     * all other signals should be masked when any handler is executing.
     */
    sigemptyset(&signals_handled);
    sigaddset(&signals_handled, SIGHUP);
    sigaddset(&signals_handled, SIGINT);
    sigaddset(&signals_handled, SIGTERM);
    sigaddset(&signals_handled, SIGCHLD);
    sigaddset(&signals_handled, SIGUSR2);

#define SIGNAL(s, handler)  do { \
    sa.sa_handler = handler; \
    if (sigaction(s, &sa, NULL) < 0) \
        fatal("Couldn't establish signal handler (%d): %m", s); \
    } while (0)

    sa.sa_mask = signals_handled;
    sa.sa_flags = 0;
    SIGNAL(SIGHUP, hup);        /* Hangup */
    SIGNAL(SIGINT, term);       /* Interrupt */
    SIGNAL(SIGTERM, term);      /* Terminate */
    SIGNAL(SIGCHLD, chld);

    SIGNAL(SIGUSR1, toggle_debug);  /* Toggle debug flag */
    SIGNAL(SIGUSR2, open_ccp);      /* Reopen CCP */

    ...
}
/*
 * term - Catch SIGTERM signal and SIGINT signal (^C/del).
 *
 * Indicates that we should initiate a graceful disconnect and exit.
 */
/*ARGSUSED*/
static void
term(sig)
    int sig;
{
    /* can't log a message here, it can deadlock */
    got_sigterm = sig;
    if (conn_running)
    /* Send the signal to the [dis]connector process(es) also */
    kill_my_pg(sig);
    notify(sigreceived, sig);
    if (waiting)
    siglongjmp(sigjmp, 1);
}

最终通过 asked_to_quit 完成

if (asked_to_quit) {
    bundle_terminating = 1;
    if (phase == PHASE_MASTER)
        mp_bundle_terminated();
}