Re: [PATCH 2/2] hazptr: Introduce CONFIG_HAZPTR_DEBUG misuse detection

From: Paul E. McKenney

Date: Sat Jul 11 2026 - 19:55:13 EST


On Sat, Jul 11, 2026 at 09:48:18AM -0400, Mathieu Desnoyers wrote:
> On 2026-07-10 15:07, Paul E. McKenney wrote:
> > >
> > > We should really rename this given that it detaches the hazptr ctx from
> > > the execution _context_ (irq handler or thread). Not sure how to name it
> > > though.
> >
> > hazptr_detach_from_context()?
> >
> > I am leaving this alone for the moment, easy to change later.
>
> I just wonder if that name brings confusion. Is "context" the
> execution context or the "hazptr ctx" context ? I fear this is
> really a good opportunity to confuse everyone.
>
> [...]
>
> >
> > > Maybe just call it hazptr_detach() ?
> >
> > That would be your choice, not mine. ;-)
>
> I find that hazptr_detach is probably better here. It does not
> state it detaches "what", but at least there is no shortcut
> confusion with the overloaded "context" wording.

Fair enough.

Would you like me to make this change?

> [...]
>
> > +/**
> > + * hazptr_detach_from_task - Allow a hazard pointer to be released by some other task
> > + *
> > + * @ctx: The hazard-pointer context to be migrated.
> > + *
> > + * By default, a given hazptr_acquire() and the corresponding
> > + * hazptr_release() must run in a single execution context, for example,
> > + * the context of a single task or a single interrupt handler. When you
> > + * have acquired a hazard pointer in one context and need to release it
> > + * in another, you must invoke hazptr_detach_from_task() on that hazard
> > + * pointer's context. It is permissible to invoke hazptr_detach_from_task()
> > + * multiple times on the same @ctx while it is protecting the same pointer,
> > + * however, the first invocation absolutely must be in the same context
> > + * that did the hazptr_acquire(), and must take place after the return
> > + * from that hazptr_acquire().
> > + *
> > + * For example, if a hazard pointer is acquired by a task and
> > + * released by a timer handler, that task would need to pass the hazard
> > + * pointer's context to hazptr_detach_from_task() after return from the
> > + * hazptr_acquire() and before arming the timer (or at least before the
> > + * handler had a chance to access that hazard-pointer context).
>
> good.
>
> > + */
> > static inline
> > void hazptr_detach_from_task(struct hazptr_ctx *ctx)
> > {
> > @@ -160,12 +182,26 @@ void hazptr_note_context_switch(void)
> > }
> > }
> > -/*
> > - * hazptr_acquire: Load pointer at address and protect with hazard pointer.
> > +/**
> > + * hazptr_acquire - Load pointer at address and protect with hazard pointer.
> > + *
> > + * @ctx: The hazard-pointer context to be passed to hazptr_release().
> > + * @addr_p: Pointer to the pointer that is to be hazard-pointer protected.
> > *
> > * Load @addr_p, and protect the loaded pointer with hazard pointer.
> > - * When using hazptr_acquire from interrupt handlers, the acquired slots
> > - * need to be released before returning from the interrupt handler.
> > + * This protection is roughly similar to that of a reference counter, and
> > + * ends with a later call to hazptr_release().
>
> Perhaps worthwhile to hint at the vast performance/scalability/memory
> footprint/cache line footprint difference between hazptr and refcount
> to justify why both exist here ?

Like this?

* Load @addr_p, and protect the loaded pointer with hazard pointer.
* This protection is roughly similar to (but way faster than) that of a
* reference counter, and ends with a later call to hazptr_release()

> AFAIU there is partial overlap between refcount, hazptr, and RCU, each
> with their own strengths and weaknesses. We should prepare a summary
> table for the end users wondering which is the right tool for their
> use-case.

We have lots of such tables of varying sizes and levels of detail in
numerous C++ Working Papers, to say nothing of Section 9.6 of perfbook. ;-)

One short text distinguishing them is: "RCU is a fast and scalable
replacement for many reader-writer locking use cases, hazard pointers is
a fast and scalable replacement for many reference-counting use cases,
reader-writer locking provides mutual exclusion, and reference counting
provides instant notice when the counter reaches zero."

> > + *
> > + * By default, the call to hazptr_release() must be running in the same
> > + * execution context as the corresponding hazptr_acquire(), for example,
> > + * within the same task or interrupt handler. When it is necessary
> > + * to instead call hazptr_release() from some other context, pass @ctx
> > + * to hazptr_detach_from_task() in the original context after invoking
> > + * hazptr_acquire() but before making the hazard pointer available to that
> > + * other context.
> > + *
> > + * It is not permissible to invoke hazptr_acquire() twice on the same @ctx
> > + * without an intervening hazptr_release().
>
> good
>
> > *
> > * Returns a non-NULL protected address if the loaded pointer is non-NULL.
> > * Returns NULL if the loaded pointer is NULL.
> > @@ -233,7 +269,23 @@ void hazptr_release_debug(struct hazptr_ctx *ctx, void *addr)
> > static inline void hazptr_release_debug(struct hazptr_ctx *ctx, void *addr) { }
> > #endif
> > -/* Release the protected hazard pointer from @slot. */
> > +/**
> > + * hazptr_release - Release the specified hazard pointer
> > + *
> > + * @ctx: The hazard-pointer context that was passed to hazptr_acquire().
> > + * @addr_p: The pointer that is to be hazard-pointer unprotected.
> > + *
> > + * Release the protected hazard pointer recorded in @ctx.
> > + *
> > + * By default, hazptr_release() must execute in the same execution context
> > + * that invoked the corresponding hazptr_acquire(), for example, within the
> > + * same task or the same interrupt handler. However, if this restriction
> > + * is problematic for your use case, please see hazptr_detach_from_task().
> > + *
> > + * It is permissible (though unwise from a maintainability viewpoint)
> > + * to invoke hazptr_release() twice on the same @ctx without an intervening
> > + * hazptr_acquire().
>
> Good!

We might actually be converging! ;-)

Thanx, Paul