あとであれやこれやを処理したい的な実装を行う場合に使用する。何かしらのイベントの発生とイベントの実処理を分けるような構造をとることはよくあると思うが、そのようなシーンで利用するイメージ。

特徴

  • linux kernel 2.6 系では workqueue はカーネルスレッドとキューの組み合わせで構成されている。
  • 独自のカーネルスレッドとキューの組み合わせを使用することが可能
    • create_workqueue() で独自 workqueue を生成する。CPU数分のカーネルスレッドが生成される。
    • create_singlethread_workqueue() で独自 workqueue を生成する。1つだけカーネルスレッドが生成される。
    • queue_work() でキューへ遅延処理関数オブジェクト(work_struct)をプッシュ。
    • 削除は destroy_workqueue()。
  • システム共有のカーネルスレッドとキューを使用することが可能
    • schedule_work() でキューへ遅延処理関数オブジェクト(work_struct)をプッシュ。
  • workqueue のカーネルスレッドはキューに処理がプッシュされるまではスリープする。
  • delayed がつく関数(schedule_delayed_work() とか)をコールすると指定した時間が経過した後に遅延処理関数がコールされる。

実行結果

  • create_workqueue() を実行後、kthreadd の下にCPU数分のカーネルスレッドが生成される。
    • CPU数が2、かつ、引数 name が “hoge” の場合, “hoge/0”, “hoge/1” が存在する状態。
  • create_singlethread_workqueue() を実行後、kthreadd の下に1つのカーネルスレッドが生成される。
    • 引数 name が “hoge” の場合, “hoge” が存在する状態。
  • 遅延処理関数内で queue_work() するとdestroy_workqueue() でシステムがフリーズするようだ。そのように設計してはいけないぽい。

実装サンプル

独自のworkqueueを生成/破棄、生成時に queue_delayed_work() で一度だけ遅延処理します。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>

static void mykmod_work_handler(struct work_struct *w);

static struct workqueue_struct *wq = 0;
static DECLARE_DELAYED_WORK(mykmod_work, mykmod_work_handler);
static unsigned long onesec;

static void
mykmod_work_handler(struct work_struct *w)
{
        pr_info("mykmod work %u jiffies\n", (unsigned)onesec);
}


static int __devinit mykmod_init(void)
{
        onesec = msecs_to_jiffies(1000);
        pr_info("mykmod loaded %u jiffies\n", (unsigned)onesec);

        if (!wq)
                wq = create_singlethread_workqueue("mykmod");
        if (wq)
                queue_delayed_work(wq, &mykmod_work, onesec);

        return 0;
}

static void __devexit mykmod_exit(void)
{
        if (wq)
                destroy_workqueue(wq);
        pr_info("mykmod exit\n");
}

module_init(mykmod_init);
module_exit(mykmod_exit);

MODULE_DESCRIPTION("mykmod");
MODULE_LICENSE("GPL");