Skip to content

Workqueue API Reference

Overview

Workqueues provide deferred execution by moving work from atomic contexts such as interrupt handlers into sleepable process contexts.

Work handlers execute in kernel worker threads (kworker) and may perform operations that are not allowed in Hard IRQ Context.

Common use cases:

  • Deferred interrupt processing
  • Retry mechanisms
  • Device recovery
  • Debounce handling
  • Delayed execution
  • Background jobs

Core Data Structures

struct work_struct

Represents a work item executed by a workqueue.

Example:

struct work_struct work;

struct delayed_work

Represents delayed execution using:

Timer
+
Workqueue

Example:

struct delayed_work retry_work;

Work Initialization

INIT_WORK()

Initialize a work item.

Prototype:

void INIT_WORK(struct work_struct *work,
               work_func_t func);

Example:

INIT_WORK(&dev->irq_work,
          my_work_handler);

INIT_DELAYED_WORK()

Initialize delayed work.

Prototype:

void INIT_DELAYED_WORK(
        struct delayed_work *work,
        work_func_t func);

Example:

INIT_DELAYED_WORK(
        &dev->retry_work,
        retry_handler);

Work Submission

schedule_work()

Queue work to the default global workqueue.

Prototype:

bool schedule_work(
        struct work_struct *work);

Example:

schedule_work(&dev->irq_work);

Equivalent:

queue_work(system_wq,
           &dev->irq_work);

queue_work()

Queue work to a specific workqueue.

Prototype:

bool queue_work(
        struct workqueue_struct *wq,
        struct work_struct *work);

Example:

queue_work(dev->wq,
           &dev->irq_work);

Delayed Work Submission

schedule_delayed_work()

Schedule delayed execution.

Prototype:

bool schedule_delayed_work(
        struct delayed_work *dwork,
        unsigned long delay);

Example:

schedule_delayed_work(
        &dev->retry_work,
        msecs_to_jiffies(100));

mod_delayed_work()

Modify or reschedule delayed work.

Prototype:

bool mod_delayed_work(
        struct workqueue_struct *wq,
        struct delayed_work *dwork,
        unsigned long delay);

Example:

mod_delayed_work(
        dev->wq,
        &dev->retry_work,
        msecs_to_jiffies(100));

Typical use cases:

  • Debounce
  • Retry timeout
  • Monitoring timer refresh

Workqueue Creation

alloc_workqueue()

Create a private workqueue.

Prototype:

struct workqueue_struct *
alloc_workqueue(
        const char *fmt,
        unsigned int flags,
        int max_active,
        ...);

Example:

dev->wq = alloc_workqueue(
                "my_driver_wq",
                WQ_UNBOUND,
                0);

alloc_ordered_workqueue()

Create a workqueue that executes work items sequentially.

Prototype:

struct workqueue_struct *
alloc_ordered_workqueue(
        const char *fmt,
        unsigned int flags,
        ...);

Example:

dev->wq =
    alloc_ordered_workqueue(
        "my_driver_wq",
        0);

Workqueue Cleanup

cancel_work_sync()

Cancel pending work and wait for running work to finish.

Prototype:

bool cancel_work_sync(
        struct work_struct *work);

Example:

cancel_work_sync(
        &dev->irq_work);

Notes:

May sleep.
Must not be called from IRQ context.

cancel_delayed_work_sync()

Cancel delayed work and wait for completion.

Prototype:

bool cancel_delayed_work_sync(
        struct delayed_work *dwork);

Example:

cancel_delayed_work_sync(
        &dev->retry_work);

flush_workqueue()

Wait until all queued work items finish.

Prototype:

void flush_workqueue(
        struct workqueue_struct *wq);

Example:

flush_workqueue(dev->wq);

Notes:

The workqueue remains usable.

destroy_workqueue()

Destroy a private workqueue.

Prototype:

void destroy_workqueue(
        struct workqueue_struct *wq);

Example:

destroy_workqueue(dev->wq);

Notes:

Flushes pending work before destruction.

Common Pitfalls

Scheduling The Same Work Multiple Times

The same work item may only be pending once.

Example:

schedule_work(&work);
schedule_work(&work);
schedule_work(&work);

Result:

Only one pending work item exists.

Calling Sync APIs From IRQ Context

Invalid:

cancel_work_sync(...);

inside:

irq_handler(...)

Reason:

Sync APIs may sleep.

Forgetting Cleanup During Driver Removal

Incorrect:

destroy_workqueue(dev->wq);

kfree(dev);

Correct:

cancel_work_sync(...);

cancel_delayed_work_sync(...);

destroy_workqueue(...);

kfree(dev);

Driver Removal Pattern

Recommended sequence:

disable_irq()
cancel_work_sync()
cancel_delayed_work_sync()
destroy_workqueue()
free_irq()
release resources

Related APIs

  • request_threaded_irq()
  • disable_irq()
  • enable_irq()
  • mutex_lock()
  • wait_event()
  • kthread_run()

Related Labs

  • Day35 - IIO IRQ Trigger Driver
  • Day50 - Pollable Character Driver
  • Day67 - Workqueue Fundamentals

Related Notes

  • Workqueue and Deferred Execution