SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

ファイルディスクリプタについて

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

第4回

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

 ファイルディスクリプタは、プログラムの外部との入出力を行う抽象的なインタフェースです。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と同じなので、こちらを参照ください。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
類似の機能について

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
ファイルディスクリプタについて連載記事一覧

もっと読む

この記事の著者

赤松 エイト(エイト)

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4803 2010/02/19 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング