Linuxシステムコール、シグナルの使い方

UNIX / Linux システムコール・プログラミング

プロセス間通信(IPC)、シグナル

シグナルとは?


プロセスに対して非同期のイベント通知を行います。

プロセス側でシグナルハンドラを定義することで、非同期通知を受けることができます。

Ctrl+C で、動作中のコマンド(プロセス)を停止できますが、Ctrl+C は SIGINT というシグナルを発生させてプロセスの停止を行っています。

また、シグナルは SYSTEM V IPC です。


どのようにシグナルを使うか、下記にサンプルコードを示します。

このサンプルコードでは、 SIGINT と SIGTSTP の2つを受け取るシグナルハンドラを記述しています。

シグナルとシグナルハンドラは、sigaction()システムコールを使って設定されます。
同様のシステムコールとして、signal()が存在しますが、現代ではsigaction()の利用が推奨されています。

また、実装バージョンやアーキテクチャによっても動作や構造体が異なる場合がありますので注意してください。

実行した状態で、Ctrl + c(SIGINT) を押してもメッセージは表示されますがプログラムは停止しません。
Ctrl + z(SIGTSTP) を押すとプログラムが停止するようになっています。

$ ./signal
I'm working...
^CCatch SIGNAL[2]    <-- Ctrl + c key in.
Work harder!              <-- Signal handler message. Don’t stop.
I'm working...
I'm working...
^ZCatch SIGNAL[20]   <-- Ctrl + z key in.
We have a break.        <-- Signal handler message. It’s goiung stop.
I've had enough!
$

signal.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

static void signalHandler(int sig) ;

static int  doit;

int main(int argc, char** argv) {

    struct sigaction   act;

    act.sa_handler = &signalHandler;
    act.sa_flags = 0;
    sigfillset(&act.sa_mask);

    if (sigaction(SIGINT, &act, NULL)<0) {
        perror("SIGINT sigaction()");
        exit(-1);
    }
    if (sigaction(SIGTSTP, &act, NULL)<0) {
        perror("SIGTSTP sigaction()");
        exit(-1);
    }

    doit = 1;

    while(doit) {
        printf("I'm working...\n");
        sleep(1);
    }

    printf("I've had enough!\n");
    return(0);
}

static void signalHandler(int sig) {

    printf("Catch SIGNAL[%d]\n", sig);

    switch(sig) {
        case SIGINT:
            printf("Work harder!\n");
            break;
        case SIGTSTP:
            printf("We have a break.\n");
            doit = 0;         // Quit process working
            break;
        default:
            printf("I don't know.\n");
    }
}




今回のサンプルでは、SIGINTとSIGTSTPと、役割が決まっているシグナルを使って処理しています。
しかも、通常ではSIGINTは強制終了ですが終了せず、SIGTSTPは通常は一時停止ですが強制終了してしまうという変則的な動作を定義しています。

では、システム設計上自由にシグナルを使うことができないんじゃないか?
と、思われるかもしれませんが、SIGUSR1とSIGUSR2という2つのシグナルがあり、プログラムで自由に使うことができます。

実際に使われている例としては、ddコマンドに実装されています。
ddコマンドで、HDDのゼロクリアなどを行うとき、
  $ dd if=/dev/zero of=/dev/sda
のようにしますが、
容量が大きなHDDを初期化するときなど非常に時間がかかります。
このとき、killコマンドで動作中のddコマンドに SIGUSR1 を送ると、動作状況を表示するようになっています。

このように、プログラムで自由な目的に使いたい場合はこの SUGUSR1とSIGUSR2を利用するべきですね。


シグナルの定義:
実際にシグナルはドコに定義されているのか?
今回も、BeagleBoneの開発環境で説明します。

gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihfの環境では下記の場所に定義されています。

arm-linux-gnueabihf/libc/usr/include/bits/signum.h

/* Signal number definitions.  Linux version.
   Copyright (C) 1995-2017 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   .  */

#ifdef _SIGNAL_H

/* Fake signal functions.  */
#define SIG_ERR ((__sighandler_t) -1)  /* Error return.  */
#define SIG_DFL ((__sighandler_t) 0)  /* Default action.  */
#define SIG_IGN ((__sighandler_t) 1)  /* Ignore signal.  */

#ifdef __USE_UNIX98
# define SIG_HOLD ((__sighandler_t) 2) /* Add signal to hold mask.  */
#endif


/* Signals.  */
#define SIGHUP  1 /* Hangup (POSIX).  */
#define SIGINT  2 /* Interrupt (ANSI).  */
#define SIGQUIT  3 /* Quit (POSIX).  */
#define SIGILL  4 /* Illegal instruction (ANSI).  */
#define SIGTRAP  5 /* Trace trap (POSIX).  */
#define SIGABRT  6 /* Abort (ANSI).  */
#define SIGIOT  6 /* IOT trap (4.2 BSD).  */
#define SIGBUS  7 /* BUS error (4.2 BSD).  */
#define SIGFPE  8 /* Floating-point exception (ANSI).  */
#define SIGKILL  9 /* Kill, unblockable (POSIX).  */
#define SIGUSR1  10 /* User-defined signal 1 (POSIX).  */
#define SIGSEGV  11 /* Segmentation violation (ANSI).  */
#define SIGUSR2  12 /* User-defined signal 2 (POSIX).  */
#define SIGPIPE  13 /* Broken pipe (POSIX).  */
#define SIGALRM  14 /* Alarm clock (POSIX).  */
#define SIGTERM  15 /* Termination (ANSI).  */
#define SIGSTKFLT 16 /* Stack fault.  */
#define SIGCLD  SIGCHLD /* Same as SIGCHLD (System V).  */
#define SIGCHLD  17 /* Child status has changed (POSIX).  */
#define SIGCONT  18 /* Continue (POSIX).  */
#define SIGSTOP  19 /* Stop, unblockable (POSIX).  */
#define SIGTSTP  20 /* Keyboard stop (POSIX).  */
#define SIGTTIN  21 /* Background read from tty (POSIX).  */
#define SIGTTOU  22 /* Background write to tty (POSIX).  */
#define SIGURG  23 /* Urgent condition on socket (4.2 BSD).  */
#define SIGXCPU  24 /* CPU limit exceeded (4.2 BSD).  */
#define SIGXFSZ  25 /* File size limit exceeded (4.2 BSD).  */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD).  */
#define SIGPROF  27 /* Profiling alarm clock (4.2 BSD).  */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun).  */
#define SIGPOLL  SIGIO /* Pollable event occurred (System V).  */
#define SIGIO  29 /* I/O now possible (4.2 BSD).  */
#define SIGPWR  30 /* Power failure restart (System V).  */
#define SIGSYS  31 /* Bad system call.  */
#define SIGUNUSED 31

#define _NSIG  65 /* Biggest signal number + 1
       (including real-time signals).  */

#define SIGRTMIN        (__libc_current_sigrtmin ())
#define SIGRTMAX        (__libc_current_sigrtmax ())

/* These are the hard limits of the kernel.  These values should not be
   used directly at user level.  */
#define __SIGRTMIN 32
#define __SIGRTMAX (_NSIG - 1)

#endif /*  included.  */

Have a Happy Hucking!!



Lightning Brains

コメント

このブログの人気の投稿

Linuxシステムコール、共有メモリの使い方

Linuxシステムコール、メッセージキューの使い方

Linuxシステムコール、セマフォの使い方