2014年7月18日金曜日

シグナルハンドラを実行するスレッドとスタック

気になったので、実際にコードを動かして振る舞いを見てみました。
結論としては、今回使用した環境では、シグナルを受け取ったスレッドが、そのスレッドのスタック上でシグナルハンドラを実行するようです。この振る舞いがPOSIX標準などで決まっているのかどうかは私にはわかりませんでした。
調べる前は、シグナルハンドラ用のスタックが別にあるのだろうか、などと想像していました。処理系によるんでしょうか(?)。

使用した環境

Xubuntu 12.04
gcc 4.6.3

使用したコード

#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
#include <pthread.h>

static void signalHandler_(
        int signum,
        siginfo_t* info,
        void* ucontext
        )
{
        printf("--- signal handler ---\n");
        printf("thread id:          [0x%08x]\n", (unsigned int)pthread_self());
        printf("signum:             [%d]\n", signum);
        printf("siginfo_t.si_signo: [%d]\n", info->si_signo);
        printf("siginfo_t.si_errno: [%d]\n", info->si_errno);
        printf("siginfo_t.si_code:  [%d]\n", info->si_code);
        printf("&signum:            [%p]\n", &signum);
        printf("&info:              [%p]\n", &info);
        printf("&ucontext:          [%p]\n", &ucontext);
        printf("\n");
}
static void* run_(
        void* arg
        )
{
        pthread_mutex_t* mutex = (pthread_mutex_t*)arg;
        pthread_attr_t attr;
        void* stack_addr;
        size_t stack_size;

        pthread_getattr_np(pthread_self(), &attr);
        pthread_attr_getstack(&attr, &stack_addr, &stack_size);

        pthread_mutex_lock(mutex);

        printf("--- pthread ---\n");
        printf("thread id:          [0x%08x]\n", (unsigned int)pthread_self());
        printf("stack addr:         [%p]\n", stack_addr);
        printf("stack size:         [0x%08x]\n", stack_size);
        printf("&arg:               [%p]\n", &arg);
        printf("\n");
        raise(SIGINT);
        raise(SIGINT);

        pthread_mutex_unlock(mutex);

        return NULL;
}

int main(void)
{
        struct sigaction action;
        pthread_t thread1;
        pthread_t thread2;
        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

        action.sa_sigaction = signalHandler_;
        sigfillset(&(action.sa_mask));
        action.sa_flags = SA_SIGINFO;
        sigaction(SIGINT, &action, NULL);

        printf("--- main ---\n");
        printf("thread id:          [0x%08x]\n", (unsigned int)pthread_self());
        printf("&action:            [%p]\n", &action);
        printf("&thread1:           [%p]\n", &thread1);
        printf("&thread2:           [%p]\n", &thread2);
        printf("\n");

        raise(SIGINT);
        raise(SIGINT);

        pthread_mutex_lock(&mutex);
        pthread_create(&thread1, NULL, run_, &mutex);
        pthread_create(&thread2, NULL, run_, &mutex);
        pthread_mutex_unlock(&mutex);
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);

        return 0;
}

コードの実行結果

--- main ---
thread id:          [0x401f9d00]
&action:            [0xbfb5be00]
&thread1:           [0xbfb5be8c]
&thread2:           [0xbfb5be90]

--- signal handler ---
thread id:          [0x401f9d00]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0xbfb5bcd0]
&info:              [0xbfb5bcd4]
&ucontext:          [0xbfb5bcd8] ← &thread2のアドレス 0xbfb5be90よりも小さいアドレス。

--- signal handler ---
thread id:          [0x401f9d00]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0xbfb5bcd0]
&info:              [0xbfb5bcd4]
&ucontext:          [0xbfb5bcd8]

--- pthread ---
thread id:          [0x403fbb40]
stack addr:         [0x401fb000]
stack size:         [0x00201000]
&arg:               [0x403fb31c]

--- signal handler ---
thread id:          [0x403fbb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x403fb1e0]
&info:              [0x403fb1e4]
&ucontext:          [0x403fb1e8] ← &argのアドレス 0x403fb31cよりも小さいアドレス

--- signal handler ---
thread id:          [0x403fbb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x403fb1e0]
&info:              [0x403fb1e4]
&ucontext:          [0x403fb1e8]

--- pthread ---
thread id:          [0x405fcb40]
stack addr:         [0x403fc000]
stack size:         [0x00201000]
&arg:               [0x405fc31c]

--- signal handler ---
thread id:          [0x405fcb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x405fc1e0]
&info:              [0x405fc1e4]
&ucontext:          [0x405fc1e8] ← &argのアドレス 0x405fb31cよりも小さいアドレス

--- signal handler ---
thread id:          [0x405fcb40]
signum:             [2]
siginfo_t.si_signo: [2]
siginfo_t.si_errno: [0]
siginfo_t.si_code:  [-6]
&signum:            [0x405fc1e0]
&info:              [0x405fc1e4]
&ucontext:          [0x405fc1e8]

printfで表示させたスレッドIDとスタックのアドレスから判断するに、シグナルを受け取ったスレッドが、そのスレッドのスタック上でシグナルハンドラを実行していることがわかります。


最後に、上記とは直接関係ないですが、シグナルに関して参考にしたページ。
http://www.nminoru.jp/~nminoru/programming/stackoverflow_handling.html
http://codezine.jp/article/detail/4700
http://www.jpcert.or.jp/sc-rules/c-sig30-c.html

0 件のコメント:

コメントを投稿