Linux

關機時向正在執行的程序/腳本發送什麼信號?

  • February 10, 2019

現在我有以下內容:

# this function is meant for future script expansions
# its purpose is clear, i.e. to clean up some temp files
# now, it is doing nothing, just a special null command
cleanup_on_signal() { :; }

# define functions to handle signals
# treat them as errors with appropriate messages
# example calls:
#    kill -15   this_script_name    # POSIX, all shells compatible
#    kill -TERM this_script_name    # Bash and alike - newer shells
signal_handler_HUP()   {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGHUP (1).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";    }
signal_handler_INT()   {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGINT (2).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";    }
signal_handler_QUIT()  {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGQUIT (3).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";   }
signal_handler_ABRT()  {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGABRT (6).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";   }
signal_handler_TERM()  {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGTERM (15).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";  }

# use the above functions as signal handlers;
# note that the SIG* constants are undefined in POSIX,
# and numbers are to be used for the signals instead
trap 'signal_handler_HUP' 1; trap 'signal_handler_INT' 2; trap 'signal_handler_QUIT' 3; trap 'signal_handler_ABRT' 6; trap 'signal_handler_TERM' 15

我希望腳本在關機時整齊地終止,現在它確實如此。

但是我打開了一位同事的建議,在 CTRL+C 上提出問題,而不是退出 shell。

我不想關閉機器,反正我不經常這樣做:

關機時向正在執行的程序/腳本發送什麼信號?

在關閉時,首先由 init 告訴正在執行的程序停止(根據@JdeBP,來自舊實現的 sendigs)/systemd。

剩餘的程序(如果有的話)會被發送一個 SIGTERM。忽略 SIGTERM 或未按時完成的那些,很快就會由 init/systemd 發送一個 SIGKILL。

這些操作旨在保證穩定/乾淨的關閉(盡可能)。

出於好奇,請參閱相關(舊)systemd錯誤的報告:

錯誤 1352264 - systemd 在關機期間在 SIGTERM 之後立即發送 SIGKILL

systemd 在關閉期間在 SIGTERM 之後立即發送 SIGKILL,程序沒有機會終止

同樣來自shutdown.c/main():

    disable_coredumps();

    log_info("Sending SIGTERM to remaining processes...");
    broadcast_signal(SIGTERM, true, true, arg_timeout);

    log_info("Sending SIGKILL to remaining processes...");
    broadcast_signal(SIGKILL, true, false, arg_timeout);

同樣來自 sysvinit 2.94 sources/init.c,這裡是圍繞 SIGTERM 輪的程式碼。如果向任何程序發送了 SIGTERM,請在 5 秒內每秒測試一次,以查看是否有任何程序剩餘。如果在其中一項測試中未找到任何程序,請等待,或在 5 秒後向剩餘程序發送 SIGKILL。

       switch(round) { 
               case 0: /* Send TERM signal */
                       if (talk)
                               initlog(L_CO,
                                       "Sending processes configured via /etc/inittab the TERM signal");
                       kill(-(ch->pid), SIGTERM);
                       foundOne = 1;
                       break;
               case 1: /* Send KILL signal and collect status */
                       if (talk)
                               initlog(L_CO,
                                       "Sending processes configured via /etc/inittab the KILL signal");
                       kill(-(ch->pid), SIGKILL);
                       break;
       }
       talk = 0;

   }
   /*
    *  See if we have to wait 5 seconds
    */
   if (foundOne && round == 0) {
       /*
        *      Yup, but check every second if we still have children.
        */
       for(f = 0; f < sleep_time; f++) {
               for(ch = family; ch; ch = ch->next) {
                       if (!(ch->flags & KILLME)) continue;
                       if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))
                               break;
               }
               if (ch == NULL) {
                       /*
                        *      No running children, skip SIGKILL
                        */
                       round = 1;
                       foundOne = 0; /* Skip the sleep below. */
                       break;
               }
               do_sleep(1);
       }
   }
 }

 /*
  *    Now give all processes the chance to die and collect exit statuses.
  */
 if (foundOne) do_sleep(1)
 for(ch = family; ch; ch = ch->next)
       if (ch->flags & KILLME) {
               if (!(ch->flags & ZOMBIE))
                   initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
                               ch->id);
               else {
                   INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
                               ch->pid, ch->id);
                   ch->flags &= ~RUNNING;
                   if (ch->process[0] != '+')
                       write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
               }
       }

 /*
  *    Both rounds done; clean up the list.
  */

引用自:https://unix.stackexchange.com/questions/499761