MQ_NOTIFY(3)

名前
mq_notify - メッセージ到着時に通知を行うよう登録する

書式
#include <mqueue.h>

int mq_notify(mqd_t mqdes, const struct sigevent *notification);

-lrt でリンクする。

説明
mq_notify() を使うと、メッセージキューディスクリプター mqdes で参照される空のメッセージキューに新しくメッセージが到着した時に 非同期の通知 (notification) の配送が行われるように登録したり、 その解除を行ったりできる。

sevp 引数は sigevent 構造体へのポインターである。 この構造体の定義と一般的な詳細については sigevent(7) を参照。

sevp が NULL でないポインターであれば、 mq_notify() はメッセージ通知を受け取るように呼び出し元のプロセスを登録する。 sevp が指す sigevent 構造体の sigev_notify フィールドは、どのような通知を行うのかを指定する。 このフィールドは以下の値のいずれかを持つ。

SIGEV_NONE
    「空の (null)」の通知: 呼び出し元のプロセスを通知の宛先として登録するが、 実際にはメッセージが到着した時に通知は送られない。

SIGEV_SIGNAL
    sigev_signo で指定されたシグナルを送って、プロセスに通知する。 一般的な詳細については sigevent(7) を参照。 siginfo_t 構造体の si_code フィールドには SI_MESGQ が設定される。 さらに、 si_pid にはメッセージを送信したプロセスの PID が、 si_uid には送信プロセスの実ユーザー ID が設定される。

SIGEV_THREAD
    メッセージの配送時には、 sigev_notify_function があたかも新しいスレッドの開始関数であるかのように起動される。 詳細は sigevent(7) を参照。

一つのメッセージキューから通知を受信するように登録できるプロセスは 一つだけである。

sevp が NULL で、かつ呼び出し元のプロセスがこのメッセージキューからの 通知を受信するに現在登録している場合、登録を削除する。 これ以降、別のプロセスがこのメッセージキューから通知を受信するように 登録できるようになる。

メッセージ通知は、それまで空のキューに新しいメッセージが到着した 場合にのみ行われる。 mq_notify() が呼び出された時にそのキューが空でない場合、 そのキューが空になり、その後新しいメッセージが到着した時に 初めて通知が行われることになる。

別のプロセスやスレッドが mq_receive(3) を使って、空のキューからメッセージの読み出しを待っている場合、 メッセージ通知の登録は全て無視される。 メッセージは mq_receive(3) を呼び出しているプロセスやスレッドに配送され、 メッセージ通知の登録は効力を持ったままとなる。

通知は一度だけ行われる。通知が送られた後は、通知要求の登録は削除され、 別のプロセスがメッセージ通知を受信するように登録できるようになる。 通知を受けたプロセスが次の通知も受信したい場合は、 mq_notify() を使ってその後の通知も受けるように要求することができる。 mq_notify() を再度呼び出すのは、読み出していないメッセージを全部読み出して キューが空になる前にすべきである (キューからのメッセージ読み出しをキューが空になった時に 停止 (block) せずに行うには、キューを非停止モード (non-blocking mode) に設定しておくとよい)。

返り値
成功すると、 mq_notify() は 0 を返す。エラーの場合、-1 を返し、 errno をエラーを示す値に設定する。

エラー

EBADF
    mqdes に指定されたメッセージキュー記述子が不正である。

EBUSY
    別のプロセスがすでに このメッセージキューに対する通知を受信するように登録している。

EINVAL
    sevp->sigev_notify が許可された値のいずれでもない。もしくは sevp->sigev_notify が SIGEV_SIGNAL だが sevp->sigev_signo が有効なシグナル番号ではない。

ENOMEM
    十分なメモリーがない。

POSIX.1-2008 では、 sevp が NULL で、呼び出し元のプロセスがキュー mqdes に関する通知を受信するように登録されていない場合、エラー EINVAL を生成するような実装を行っても「よい」ことになっている。

属性
この節で使用されている用語の説明については、 attributes(7) を参照。
インターフェース | 属性 | 値
mq_notify() | Thread safety | MT-Safe

準拠
POSIX.1-2001.

注意

  C ライブラリとカーネルの違い
In the glibc implementation, the mq_notify() library function is implemented on top of the system call of the same name. When sevp is NULL, or specifies a notification mechanism other than SIGEV_THREAD, the library function directly invokes the system call. For SIGEV_THREAD, much of the implementation resides within the library, rather than the kernel. (This is necessarily so, since the thread involved in handling the notification is one that must be managed by the C library POSIX threads implementation.) The implementation involves the use of a raw netlink(7) socket and creates a new thread for each notification that is delivered to the process.

例
以下のプログラムは、 コマンドライン引数で指定された名前のメッセージキューへの 通知要求を登録し、通知はスレッドの作成によって行われる。 そのスレッドは、そのキューからメッセージを一つ読み出してから、 プロセスを終了する関数を実行する。

  プログラムのソース
    #include <pthread.h>
    #include <mqueue.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    #define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

    static void                     /* スレッド開始関数 */
    tfunc(union sigval sv)
    {
        struct mq_attr attr;
        ssize_t nr;
        void *buf;
        mqd_t mqdes = *((mqd_t *) sv.sival_ptr);

        /* 最大メッセージサイズを決定し、
           メッセージ受信用のバッファーを確保する */

        if (mq_getattr(mqdes, &attr) == -1)
            handle_error("mq_getattr");
        buf = malloc(attr.mq_msgsize);
        if (buf == NULL)
            handle_error("malloc");

        nr = mq_receive(mqdes, buf, attr.mq_msgsize, NULL);
        if (nr == -1)
            handle_error("mq_receive");

        printf("Read %zd bytes from MQ\n", nr);
        free(buf);
        exit(EXIT_SUCCESS);         /* プロセスを終了する */
    }

    int
    main(int argc, char *argv[])
    {
        mqd_t mqdes;
        struct sigevent sev;

        if (argc != 2) {
            fprintf(stderr, "Usage: %s <mq-name>\n", argv[0]);
            exit(EXIT_FAILURE);
        }

        mqdes = mq_open(argv[1], O_RDONLY);
        if (mqdes == (mqd_t) -1)
            handle_error("mq_open");

        sev.sigev_notify = SIGEV_THREAD;
        sev.sigev_notify_function = tfunc;
        sev.sigev_notify_attributes = NULL;
        sev.sigev_value.sival_ptr = &mqdes;   /* スレッド関数に渡す引数 */
        if (mq_notify(mqdes, &sev) == -1)
            handle_error("mq_notify");

        pause();    /* プロセスはスレッド関数により終了される */
    }

関連項目
mq_close(3), mq_getattr(3), mq_open(3), mq_receive(3), mq_send(3), mq_unlink(3), mq_overview(7), sigevent(7)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。