Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

ファイルディスクリプタについて(4)
~シグナル用ディスクリプタ「signalfd」の特徴

第4回

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2010/02/19 14:00

 ファイルディスクリプタは、プログラムの外部との入出力を行う抽象的なインタフェースです。Unix/Linuxのファイルディスクリプタは、一般的なファイルだけでなくデバイスやソケットやパイプも対象としています。当連載は、ファイルディスクリプタの機能や管理方法などを提示します。第4回は、シグナルイベントを補足するディスクリプタ「signalfd」を紹介します。

目次

はじめに

 前回は、タイマー用ディスクリプタ「timerfd」の使用法や特徴を説明しました。今回は、プログラムの内外部から発行されたシグナルイベントを補足し、通知するためのシグナル用ディスクリプタ「signalfd」について解説していきたいと思います。

連載概要

 この連載は、次のような内容について述べていく予定です。

連載目次

 サンプルプログラムは100行前後程度までは画面に記載します。全プログラムは圧縮してページ上部よりダウンロード可能にしています。makeコマンドでコンパイルできます。i386/x86_64環境で動作確認済みです。

 プログラムのボリューム上、エラー処理や引数チェックなどを省いているので、あらかじめご了解ください。また使用法を誤るとシステムに重大な影響を与える可能性があります。利用する場合は責任のとれる環境において実行するよう、お願いします。

 当トピックでは、実際にプログラムを通して動作確認や性能測定を行うことで、個人的な見解を述べさせていただきます。あくまで個人的な感想に基づいているので、反論や指摘などあるかと思います。指摘や質問などは大歓迎なので、その際はぜひご連絡ください。可能な限りの対応に努めます。

signalfdについて

 signalfd(2)は、プログラムの内外部から発行されたシグナルイベントを補足し通知するためのディスクリプタを生成します。

 今までシグナルイベントを補足するには、signal(2)およびsigaction(2)によってハンドラを生成し、その中で処理していたため、使えない関数があったり予期しない動作をしたりなど、制約も多かったです。ディスクリプタ経由でイベントを補足できるようになると、このような制約から解放されることになります。

 signalfd(2)を使用する場合の大まかな流れは、補足対象のシグナルイベントをsigaddset(3)で指定し、sigprocmask(2)でブロック指定した後に、signalfd(2)を使ってファイルディスクリプタを生成します。

 サンプルプログラムは下記のとおりです。SIGINTを4秒間隔で発行させ、SIGINTSIGQUITを補足します。詳細はリファレンスを参照ください。

サンプルプログラム

signalfd_sample.c
#include <sys/signalfd.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>

int  signal_fd( );
void timer_set( );

int main( ) {

    struct signalfd_siginfo si;

    int fd = signal_fd( );
    timer_set( );

    while( 1 ) {
	read( fd, &si, sizeof( struct signalfd_siginfo ));

	if( si.ssi_signo == SIGINT )
	    printf("Got SIGINT" );
	else if( si.ssi_signo == SIGQUIT )
	    printf("Got SIGQUIT" );
	else
	    printf( "Read unexpected signal" );

	if( si.ssi_code == SI_USER )
	    printf( " by USER ... perhaps kill command.\n" );
	else if( si.ssi_code == SI_KERNEL )
	    printf( " by KERNEL ... perhaps terminal.\n" );
	else if( si.ssi_code == SI_TIMER )
	    printf( " by TIMEUP.\n" );
	else
	    printf( " ssi_code:unexpected code : %d\n", si.ssi_code );
    }
    return 0;
}

int  signal_fd( ) {
    sigset_t mask;

    sigemptyset( &mask );
    sigaddset( &mask, SIGINT );
    sigaddset( &mask, SIGQUIT );
    sigprocmask( SIG_BLOCK, &mask, 0 );
    return signalfd( -1, &mask, 0 );
}

void timer_set( ) {
    struct sigevent ev;
    ev.sigev_notify = SIGEV_SIGNAL;
    ev.sigev_signo  = SIGINT;

    struct itimerspec ts;
    ts.it_value.tv_sec = 4;
    ts.it_value.tv_nsec = 0;
    ts.it_interval.tv_sec = 4;
    ts.it_interval.tv_nsec = 0;

    timer_t timer_id;
    timer_create( CLOCK_MONOTONIC,&ev, &timer_id );
    timer_settime( timer_id, 0, &ts, 0 );
}

 read(2)で得られるのはsignalfd_siginfo構造体です。詳細は少々長いので、リファレンスを参照して欲しいですが、特にssi_signossi_codeは押さえた方がよいでしょう。

  • ssi_signo
    シグナルイベントが設定されます。
  • ssi_code
    シグナルイベントの発行経緯が分かります。
    詳細は、siginfo_t構造体のsi_codeと同じなので、こちらを参照ください。

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 赤松 エイト(エイト)

    (株)DTSに勤てます。 WebアプリやJavaやLL等の上位アプリ環境を密かに憧れつつも、ず~っとLinuxとかHP-UXばかり、ここ数年はカーネル以上アプリ未満のあたりを行ったり来たりしています。 mixiもやってまして、こちらは子育てとか日々の日記メインです。

バックナンバー

連載:ファイルディスクリプタについて
All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5