訊號在android原始碼/external/dnsmasq 原始碼專案中的應用解讀分析
阿新 • • 發佈:2019-01-26
直接上原始碼,這裡面的signal比較簡單,主要學會sigaction的用法
struct sigaction sigact; sigact.sa_handler = sig_handler; sigact.sa_flags = 0; sigemptyset(&sigact.sa_mask); sigaction(SIGUSR1, &sigact, NULL); sigaction(SIGUSR2, &sigact, NULL); sigaction(SIGHUP, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGALRM, &sigact, NULL); sigaction(SIGCHLD, &sigact, NULL); /* ignore SIGPIPE */ sigact.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigact, NULL);
直接進入到訊號handler函式
static void sig_handler(int sig) { if (pid == 0) { /* ignore anything other than TERM during startup and in helper proc. (helper ignore TERM too) */ if (sig == SIGTERM) exit(EC_MISC); } else if (pid != getpid()) { /* alarm is used to kill TCP children after a fixed time. */ if (sig == SIGALRM) _exit(0); } else { /* master process */ int event, errsave = errno; if (sig == SIGHUP) event = EVENT_RELOAD; else if (sig == SIGCHLD) event = EVENT_CHILD; else if (sig == SIGALRM) event = EVENT_ALARM; else if (sig == SIGTERM) event = EVENT_TERM; else if (sig == SIGUSR1) event = EVENT_DUMP; else if (sig == SIGUSR2) event = EVENT_REOPEN; else return; send_event(pipewrite, event, 0); errno = errsave; } }
收到訊號之後,往pipe寫資料,
繼續看
void send_event(int fd, int event, int data) { struct event_desc ev; ev.event = event; ev.data = data; /* error pipe, debug mode. */ if (fd == -1) fatal_event(&ev); else /* pipe is non-blocking and struct event_desc is smaller than PIPE_BUF, so this either fails or writes everything */ while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR); }
接著看pipe讀資料,signal都是和pipe互動,經典的用法
if (FD_ISSET(piperead, &rset))
async_event(piperead, now);
static void async_event(int pipe, time_t now)
{
pid_t p;
struct event_desc ev;
int i;
if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
switch (ev.event)
{
case EVENT_RELOAD:
clear_cache_and_reload(now);
if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
{
reload_servers(daemon->resolv_files->name);
check_servers();
}
#ifdef HAVE_DHCP
rerun_scripts();
#endif
break;
case EVENT_DUMP:
if (daemon->port != 0)
dump_cache(now);
break;
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp)
{
lease_prune(NULL, now);
lease_update_file(now);
}
#endif
break;
case EVENT_CHILD:
/* See Stevens 5.10 */
while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
if (p == -1)
{
if (errno != EINTR)
break;
}
else
for (i = 0 ; i < MAX_PROCS; i++)
if (daemon->tcp_pids[i] == p)
daemon->tcp_pids[i] = 0;
break;
case EVENT_KILLED:
my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
break;
case EVENT_EXITED:
my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
break;
case EVENT_EXEC_ERR:
my_syslog(LOG_ERR, _("failed to execute %s: %s"),
daemon->lease_change_command, strerror(ev.data));
break;
/* necessary for fatal errors in helper */
case EVENT_HUSER_ERR:
case EVENT_DIE:
fatal_event(&ev);
break;
case EVENT_REOPEN:
/* Note: this may leave TCP-handling processes with the old file still open.
Since any such process will die in CHILD_LIFETIME or probably much sooner,
we leave them logging to the old file. */
if (daemon->log_file != NULL)
log_reopen(daemon->log_file);
break;
case EVENT_TERM:
/* Knock all our children on the head. */
for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pids[i] != 0)
kill(daemon->tcp_pids[i], SIGALRM);
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
/* handle pending lease transitions */
if (daemon->helperfd != -1)
{
/* block in writes until all done */
if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
do {
helper_write();
} while (!helper_buf_empty() || do_script_run(now));
close(daemon->helperfd);
}
#endif
if (daemon->lease_stream)
fclose(daemon->lease_stream);
if (daemon->runfile)
unlink(daemon->runfile);
my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
flush_log();
exit(EC_GOOD);
}
}
對訊號的處理裡面夾雜了event機制,可以很方便的同步。