work queue - MarekBykowski/readme GitHub Wiki

A workqueue is a kernel mechanism that lets you:

  • Defer execution of code to run later in process context
  • It runs your function inside a kworker thread

Use it when:

  • You are in atomic context and cannot sleep
  • do_heavy_work(); queue_work(...); return immediately;
  • You need process context
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/delay.h>

struct my_object {
    int value;
    struct work_struct work;
};

static struct workqueue_struct *my_wq;
static struct my_object *global_obj;

/* Work handler */
static void my_work_handler(struct work_struct *work)
{
    struct my_object *obj =
        container_of(work, struct my_object, work);

    pr_info("Work running in PID %d, value=%d\n",
            current->pid, obj->value);

    msleep(1000);

    pr_info("Work finished\n");
}

static int __init my_init(void)
{
    pr_info("Module init\n");

    /* Create dedicated workqueue */
    my_wq = alloc_workqueue("my_wq",
                            WQ_UNBOUND | WQ_MEM_RECLAIM,
                            1);
    if (!my_wq)
        return -ENOMEM;

    global_obj = kmalloc(sizeof(*global_obj), GFP_KERNEL);
    if (!global_obj) {
        destroy_workqueue(my_wq);
        return -ENOMEM;
    }

    global_obj->value = 555;

    INIT_WORK(&global_obj->work, my_work_handler);

    /* Queue work on our custom workqueue */
    queue_work(my_wq, &global_obj->work);

    return 0;
}

static void __exit my_exit(void)
{
    pr_info("Module exit\n");

    /* Wait for this specific work to finish */
    cancel_work_sync(&global_obj->work);

    kfree(global_obj);

    destroy_workqueue(my_wq);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("You");
MODULE_DESCRIPTION("queue_work example with embedded struct");