If you want to pass data to your work queue function, just embed the work_struct structure inside your own data structure and use container_of inside your work function to retrieve it.

As for a simple example, the kernel is full of it - just git grep work_struct. You can look at drivers/cpufreq/cpufreq.c (handle_update function) for a simple example. The article below also embeds an example at the end, but it does not use container_of and instead relies on the fact that the first member of a structure has the same address as its parent:

http://www.ibm.com/developerworks/linux/library/l-tasklets/index.html

Answer from Gnurou on Stack Overflow
🌐
Linux Kernel
docs.kernel.org › core-api › workqueue.html
Workqueue — The Linux Kernel documentation
Some users depend on strict execution ordering where only one work item is in flight at any given time and the work items are processed in queueing order. While the combination of @max_active of 1 and WQ_UNBOUND used to achieve this behavior, this is no longer the case. Use alloc_ordered_workqueue() instead. The following example execution scenarios try to illustrate how cmwq behave under different configurations.
🌐
EmbeTronicX
embetronicx.com › tutorials › linux › device-drivers › workqueue-in-linux-kernel
Workqueue in Linux Kernel Part 1 – Linux Device Driver Tutorial Part 14
September 24, 2023 - Most importantly, work queues are schedulable and can therefore sleep. Normally, it is easy to decide between using workqueue and softirq/tasklet: If the deferred work needs to sleep, then workqueue is used. If the deferred work needs not sleep, then softirq or tasklet are used. There are two ways to implement Workqueue in the Linux kernel.
🌐
O'Reilly
oreilly.com › library › view › understanding-the-linux › 0596005652 › ch04s08.html
4.8. Work Queues - Understanding the Linux Kernel, 3rd Edition [Book]
November 17, 2005 - A.2.1. Booting Linux from a Disk · B.1.1. Module Licenses · B.2.1. Module Usage CountersB.2.2. Exporting SymbolsB.2.3. Module Dependency · B.4.1. The modprobe ProgramB.4.2. The request_module( ) Function ... The work queues have been introduced in Linux 2.6 and replace a similar construct called “task queue” used in Linux 2.4.
Authors   Daniel P. BovetMarco Cesati
Published   2005
Pages   942
🌐
GitHub
gist.github.com › itrobotics › b4f5597585b74525e00e
a simple example of work_queue in Linux kernel · GitHub
a simple example of work_queue in Linux kernel. GitHub Gist: instantly share code, notes, and snippets.
🌐
Linux Kernel
kernel.org › doc › html › v4.19 › core-api › workqueue.html
Concurrency Managed Workqueue (cmwq) — The Linux Kernel documentation
Work items on such wq were always queued to the unbound worker-pools and only one work item could be active at any given time thus achieving the same ordering property as ST wq. In the current implementation the above configuration only guarantees ST behavior within a given NUMA node. Instead alloc_ordered_queue() should be used to achieve system-wide ST behavior. The following example execution scenarios try to illustrate how cmwq behave under different configurations.
🌐
GitHub
gist.github.com › yagihiro › 309746
workqueue sample on linux kernel · GitHub
Don't forget to cancel the possible work in the queue (cancel_delayed_work_sync) when you close the workqueue, otherwise your kernel will crash. ... You are a lifesaver, arxchruncher, I had spent an hour trying to figure out why my kernel crashed. ... Here is a minimal working example using cancel_work_sync https://github.com/cirosantilli/linux-kernel-module-cheat/blob/ad077d3943f79c0f6481dab929970613c33c31a7/kernel_module/workqueue_cheat.c
🌐
Lastweek
lastweek.io › notes › linux › linux-workqueue
Linux workqueue - Yizhou Shan's Home Page
My simple testing code is here: https://github.com/lastweek/linux-sample-modules/tree/master/workqueue. Work queue is a generic async execution with shared worker pool in linux kernel. It does what is designed to do, it runs “your function” across a set of worker threads.
Find elsewhere
🌐
Linux Kernel Labs
linux-kernel-labs.github.io › refs › heads › master › labs › deferred_work.html
Deferred work — The Linux Kernel documentation
Schedule the work from the timer handler using schedule_work(). Schedule the timer handler aften N seconds from the ioctl. Implement a simple module that creates a kernel thread that shows the current process identifier. Generate the skeleton for the task named 6-kthread and follow the TODOs from the skeleton. ... Review the Kernel Threads section if needed. ... For synchronization use two wait queues and two flags.
🌐
EmbeTronicX
embetronicx.com › tutorials › linux › device-drivers › work-queue-in-linux-own-workqueue
Workqueue in Linux Kernel Part 3 – Linux Device Driver Tutorial Part 16
October 5, 2022 - At that time you need to put work on your workqueue by using queue_work function. If you don’t want to create any own workqueue, you can use kernel global workqueue. In that condition, you can use schedule_work function to put your work to global workqueue. In our next tutorial, we will discuss the linked list in the Linux device driver.
🌐
Paper Checker
hub.paper-checker.com › blog › multitasking-in-the-linux-kernel-an-in-depth-guide-to-workqueues
Multitasking in Linux Kernel: Exploring Workqueues
January 16, 2025 - Task Definition: struct work_struct encapsulates the task to be executed. Task Enqueuing: queue_work() adds the task to the workqueue.
🌐
discoversdk
discoversdk.com › knowledge-base › workqueue-example
Workqueue Example | DiscoverSDK Code Examples
May 16, 2016 - Code Examples Blog Product Analysis Product Comparisons Code Examples Spotlight Developers · Rss Feed · By liran bh | 5/16/2016 | Linux Kernel & Internals · #include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ #include <linux/sched.h> #include <linux/workqueue.h> #include <linux/interrupt.h> /* We want an interrupt */ #include <asm/io.h> #define MY_WORK_QUEUE_NAME "WQsched.c" static struct workqueue_struct *my_workqueue; /* * This will get called by the kernel as soon as it's safe * to do everything normally allowed by kernel modules.
🌐
Wordpress
jlmedina123.wordpress.com › 2016 › 05 › 18 › workqueue
Workqueue - Learning C by example - WordPress.com
May 18, 2016 - #include <linux/init.h> #include <linux/module.h> #include <linux/workqueue.h> #include <linux/slab.h> MODULE_LICENSE("Dual BSD/GPL"); #define printd() \ printk(KERN_ALERT "workqueue_test: %s %d\n", __FUNCTION__, __LINE__); struct workqueue_struct *wq; struct work_data { struct work_struct work; int data; }; static void work_handler(struct work_struct *work) { struct work_data * data = (struct work_data *)work; printd(); kfree(data); } static int wq_init(void) { struct work_data * data; printd(); wq = create_workqueue("wq_test"); data = kmalloc(sizeof(struct work_data), GFP_KERNEL); INIT_WORK(&data->work, work_handler); queue_work(wq, &data->work); return 0; } static void wq_exit(void) { printd(); flush_workqueue(wq); destroy_workqueue(wq); printd(); } module_init(wq_init); module_exit(wq_exit);
🌐
LWN.net
lwn.net › Articles › 11360
Details of the workqueue interface [LWN.net]
PREPARE_WORK(work_t *work, void (*function)(void *), void *data); INIT_WORK(work_t *work, void (*function)(void *), void *data); The difference between the two is that INIT_WORK initializes the linked list pointers within the work_t structure, while PREPARE_WORK changes only the function and ...
🌐
GitHub
github.com › torvalds › linux › blob › master › include › linux › workqueue.h
linux/include/linux/workqueue.h at master · torvalds/linux
#include <linux/workqueue_types.h> · /* * The first word is the work queue pointer and the flags rolled into · * one · */ #define work_data_bits(work) ((unsigned long *)(&(work)->data)) ·
Author   torvalds
🌐
HackMD
hackmd.io › @TomasZheng › B1hxDlA57
[Note] A glimpse of Workqueue in Linux - HackMD
Now, let's look at the API functions that can be found for work queues. ## Synopsis[^ref3][^ref4][^ref5] | API | description | |:------ |:----------- | |<tr><td colspan="2"><b>Specific workqueues operation</td></tr> |[**create_workqueue**](https://elixir.bootlin.com/linux/latest/source/include/linux/workqueue.h#L448)|allocate a workqueue| |[**INIT_WORK**<br/>**INIT_DELAYED_WORK**](https://elixir.bootlin.com/linux/latest/source/include/linux/workqueue.h#L222)</br>|initialize all of a work item in one go |[**queue_work**](https://www.fsl.cs.sunysb.edu/kernel-api/re54.html)|queue work on a workqu
🌐
Kernel-internals
kernel-internals.org › interrupts › workqueues
Workqueues - Linux Kernel Internals
/* alloc_workqueue(name, flags, max_active) */ /* Bound: one worker per CPU, max 1 concurrent item */ wq = alloc_workqueue("my-driver", WQ_MEM_RECLAIM, 1); /* Unbound: not tied to specific CPUs, good for CPU-intensive work */ wq = alloc_workqueue("my-driver-unbound", WQ_UNBOUND, 0); /* High priority, unbound */ wq = alloc_workqueue("my-driver-hp", WQ_UNBOUND | WQ_HIGHPRI, 0); /* Queue on private workqueue */ queue_work(wq, &dev->work); /* Flush: wait for all pending work to complete */ flush_workqueue(wq); drain_workqueue(wq); /* Destroy */ destroy_workqueue(wq); Since Linux 2.6.36, the kernel uses concurrency-managed workqueues (cmwq), introduced by Tejun Heo (LWN).
🌐
LWN.net
lwn.net › Articles › 23634
Driver porting: the workqueue interface. [LWN.net]
February 24, 2003 - void flush_workqueue(struct workqueue_struct *queue); This would be a good thing to do, for example, in a device driver shutdown routine. Note that if the queue contains work with long delays this call could take a long time to complete.