SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

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

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

第4回

類似の機能について

 前回でも紹介している方法ですが、signalの受信をファイルディスクリプタを経由して知る方法として、現状ではpipe(2)を組み合わせる方法がお勧めできます。

 シグナルハンドラ内でpipe(2)write(2)し、メインプロセスでは多重I/O等でpipe(2)read(2)を待ちます。シグナルが発生するとハンドラが呼ばれ、ハンドラ内でpipe(2)write(2)することでメインプロセスが検知し、しかるべき処理を行う、という流れです。signalfd(2)とほぼ同じ機能を実装できます。

 サンプルでは、SIGTERMSIGINTSIGQUITについて汎用的なハンドラを用意し、ハンドラ内ではpipeを使ってシグナルイベントを書き込みます。本来のイベントハンドラでは、実際のシグナルハンドラでは使用できないメモリアロケートやprintfが使用できます。

signal_fd_sim.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

void  make_sigaction( int sig, void ( *signal_handle )( int sig ));
void  signal_handler     ( int sig );
void  signal_term_handler( int sig );
void  signal_int_handler ( int sig );
void  signal_quit_handler( int sig );
int    pipefd[2];
struct {
    int     sigid;
    void    ( *sig_handle )( int sig );
}   siginfo[] = {
{   SIGTERM, signal_term_handler, },
{   SIGINT,  signal_int_handler,  },
{   SIGQUIT, signal_quit_handler, },
};
#define array( a )  ( sizeof( a )/sizeof( a[0] ))

int main( ) {

    fd_set rset, org_rset;
    unsigned int i;
    int sig = 0;

    for( i = 0; i < array( siginfo ); i ++ ) {
	make_sigaction( siginfo[i].sigid, signal_handler );
    }

    pipe( pipefd );
    FD_ZERO( &org_rset );
    FD_SET( pipefd[0], &org_rset );

    while( 1 ) {
	rset = org_rset;
	int rtn = select( FD_SETSIZE, &rset, 0, 0, 0 );
	if( rtn < 0 && errno == EINTR ) {
	    continue;
	}
	read( pipefd[0], &sig, sizeof( int ));
	for( i = 0; i < array( siginfo ); i ++ ) {
	    if( siginfo[i].sigid == sig ) {
		siginfo[i].sig_handle( siginfo[i].sigid );
		break;
	    }
	}
    }
    return 0;
}

void  make_sigaction( int sig, void ( *signal_handle )( int sig )) {
    struct sigaction sa;
    sa.sa_handler = signal_handle;
    sa.sa_flags   = SA_RESTART;
    sigemptyset( &sa.sa_mask );
    sigaction( sig, &sa, 0 );
    return;
}

void signal_term_handler( int sig ) {
    static int cnt;
    cnt ++;
    printf( "inside %s Path ... [%d] [%d]\n", __FUNCTION__, sig, cnt );
}

void signal_int_handler( int sig ) {
    static int cnt;
    cnt ++;
    printf( "inside %s Path ... [%d] [%d]\n", __FUNCTION__, sig, cnt );
}

void signal_quit_handler( int sig ) {
    static int cnt;
    cnt ++;
    printf( "inside %s Path ... [%d] [%d]\n", __FUNCTION__, sig, cnt );
}

void  signal_handler( int sig ) {
    write( pipefd[1], &sig, sizeof( int ));
}

 ちなみにこのpipe(2)を使う方法はpthreadの管理にも使えます。現在、メインプロセスでpthreadが停止したことを知るのはpthread_join(3)pthread_kill(3)になります。どちらも一定の間隔で呼んで、その時の戻り値などで判定することになり、同期的に行うことはできません。よって他のファイルディスクリプタと同等に管理できません。この方法を使用することで、多重I/O等で一元管理化できます。

signalfdのメリットとデメリット

 今までのシグナルの実装は、シグナルハンドラという関数内で処理を行う方法が、ほぼ必須でした。その場合、シグナルのリエントラント問題など、使用できる関数に厳しい制限がありました。また、あまり一般的ではないようですが、シグナルハンドラではなくスレッドでシグナルを対処する方法もあります。スレッド内でシグナルを処理するのでハンドラと比較すると利点が大きいですが、それでもスレッドを使う場合はスレッドアンセーフな関数の存在を意識する必要があります。

 signalfd(2)を使用すると、多重I/Oを使用してシグナルの到着を待てるため、リエントラント問題は回避され、使用できる関数に制限がありません。これはとても大きなメリットだと思います。

 反面、デメリットですが・・・すいません、私の瑣末な知識では思い浮かばないです。ファイルディスクリプタを複数管理する場合、多重I/Oで管理するのが一般的ですが、多重I/Oならではの気をつけなくてはいけない点はあります。しかしそれはsignalfd(2)独自の問題ではなく、ファイルディスクリプタと多重I/Oにおける問題です。

 前述していますが、RedHat等のEnterprize向けディストリビューションでは、現時点ではsignalfd(2)が使えるほど新しいカーネルおよびglibがバンドルされていませんので、商用環境で使用することはまだまだできませんが、サポートされた暁は使用をお勧めします。

まとめ

 以上で、3つの新しいファイルディスクリプタ「eventfd」「timerfd」「signalfd」の紹介については終了となります。以降の連載では、複数のディスクリプタの管理方法について言及していきたいと思います。

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

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
ファイルディスクリプタについて連載記事一覧

もっと読む

この記事の著者

赤松 エイト(エイト)

(株)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」など、さまざまなカンファレンスを企画・運営しています。

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

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

メールバックナンバー