Skip to content

Day 69 - Completion Synchronization

Objective

Learn the Linux kernel completion synchronization mechanism and understand how it differs from wait queues.

Topics covered:

  • struct completion
  • init_completion()
  • reinit_completion()
  • complete()
  • complete_all()
  • wait_for_completion()
  • wait_for_completion_timeout()
  • Completion vs Wait Queue
  • One-shot synchronization pattern

What I Learned

Completion Synchronization

Completion is a lightweight synchronization primitive designed for one-shot events.

Unlike wait queues, completion directly represents:

Wait until an operation has finished.

A completion object maintains an internal completion state and allows one or more waiters to block until another execution context signals completion.

Typical kernel usage includes:

  • Hardware initialization
  • Firmware loading
  • DMA transfer completion
  • Worker startup synchronization
  • Probe and subsystem initialization

Completion Lifecycle

Basic workflow:

init_completion()
wait_for_completion()
complete()

The waiter blocks until another thread signals completion.


Completion Timeout

To prevent indefinite blocking:

wait_for_completion_timeout()

can be used.

This is commonly used when waiting for hardware or firmware responses.

If timeout occurs:

  • Cleanup is required
  • Worker lifetime must still be handled correctly
  • Timeout does not imply worker termination

complete() vs complete_all()

A single completion object may have multiple waiters.

complete()

complete(&done);

Wake a single waiter.

complete_all()

complete_all(&done);

Wake all waiters.


Completion State Persistence

Completion state remains completed after:

complete()

Subsequent:

wait_for_completion()

returns immediately.

To reuse a completion object:

reinit_completion()

must be called.


Completion vs Wait Queue

Feature Completion Wait Queue
One-shot event Yes Possible
Repeated event No Yes
Multiple conditions No Yes
State machine No Yes
Driver initialization Excellent Acceptable
Event-driven workflow Limited Excellent

Completion is optimized for:

Wait until a specific operation finishes.

Wait queues are more suitable for:

Wait until a condition becomes true.


Labs Completed

Lab 1 - Basic Completion

Implemented:

  • init_completion()
  • wait_for_completion()
  • complete()

Verified:

  • Worker thread signals completion
  • Module initialization resumes after completion

Lab 2 - Completion Timeout

Implemented:

  • wait_for_completion_timeout()
  • kthread_stop()

Verified:

  • Timeout handling
  • Worker cleanup path
  • Safe resource release after timeout

Important observation:

Timeout does not mean the worker has exited.

Worker lifetime must still be synchronized before releasing resources.


Lab 3 - complete() vs complete_all()

Implemented:

  • Multiple waiter threads
  • Single signaler thread

Verified:

complete()

Only one waiter wakes up.

complete_all()

All waiters wake up simultaneously.


Lab 4 - reinit_completion()

Verified:

  • Completion state persists after completion
  • New waiters immediately return
  • reinit_completion() resets completion state
  • Completion object becomes reusable

Key Takeaways

  • Completion is a one-shot synchronization primitive.
  • Completion is commonly used for initialization and operation completion.
  • Timeout handling must include worker cleanup.
  • complete() wakes one waiter.
  • complete_all() wakes all waiters.
  • reinit_completion() resets completion state.
  • Completion is built on top of wait queues internally.
  • Completion expresses operation completion, while wait queues express condition waiting.

Next Step

Day 70:

  • Notifier Chain
  • Event notification framework
  • Subsystem callback registration
  • Notification propagation mechanisms