LOCALCOUNT(9)

NAME
localcount, localcount_init, localcount_fini, localcount_acquire, localcount_release, localcount_drain - reference-count primitives

SYNOPSIS
#include <sys/localcount.h>
void
localcount_init(struct localcount *lc);
void
localcount_fini(struct localcount *lc);
void
localcount_acquire(struct localcount *lc);
void
localcount_release(struct localcount *lc, struct kcondvar *cv, struct kmutex *mtx);
void
localcount_drain(struct localcount *lc, struct kcondvar *cv, struct kmutex *mtx);

DESCRIPTION
Localcounts are used in the kernel to implement a medium-weight reference counting mechanism. During normal operations, localcounts do not need the interprocessor synchronization associated with atomic_ops(3) atomic memory operations, and (unlike psref(9)) localcount references can be held across sleeps and can migrate between CPUs. Draining a localcount requires more expensive interprocessor synchronization than atomic_ops(3) (similar to psref(9)). And localcount references require eight bytes of memory per object per-CPU, significantly more than atomic_ops(3) and almost always more than psref(9).

As a rough heuristic, localcount should be used for classes of objects of which there are perhaps a few dozen instances (such as autoconf(9) devices) but not thousands of instances (such as network flows) and on which there may be a mixture of long-term I/O waits, such as xyzread for a device xyz(4), and short-term fast operations, such as xyzioctl(IOC_READ_A_CPU_REG).

FUNCTIONS

localcount_init(lc)
    Dynamically initialize localcount lc for use.

    No other operations can be performed on a localcount until it has been initialized.

localcount_fini(lc)
    Release resources used by localcount lc. The caller must have already called localcount_drain(). The localcount may not be used after localcount_fini() has been called until it has been re-initialized by localcount_init().

localcount_acquire(lc)
    Acquire a reference to the localcount lc.

    The caller must ensure by some other mechanism that the localcount will not be destroyed before the call to localcount_acquire(); typically this will be via a pserialize(9) read section.

localcount_release(lc, cv, mtx)
    Release a reference to the localcount lc. If the localcount is currently being drained, the mutex mtx will be used to synchronize updates to the global reference count (i.e., the total across all CPUs). If the reference count goes to zero, localcount_release() will broadcast availability of the condvar cv.

localcount_drain(lc, cv, mtx)
    Wait for all references to the localcount lc to be released. The caller must hold the mutex mtx; the mutex will be released during inter-CPU cross-calls (see xcall(9)) and while waiting on the condvar cv. The same cv and mtx must be used with localcount_release().

    The caller must guarantee that no new references can be acquired with localcount_acquire() before calling localcount_drain(). For example, any object that may be found in a list and acquired must be removed from the list before calling localcount_drain(); removal from the list would typically be protected by calling pserialize_perform(9) to wait for any pserialize(9) readers to complete.

    Once the localcount object lc is passed to localcount_drain(), it must be passed to localcount_fini() before any other re-use.

CODE REFERENCES
The core of the localcount implementation is located in sys/kern/subr_localcount.c.

The header file sys/sys/localcount.h describes the public interface, and interfaces that machine-dependent code must provide to support localcounts.

SEE ALSO
atomic_ops(3), condvar(9), mutex(9), psref(9)

HISTORY
The localcount primitives first appeared in NetBSD 8.0.

AUTHORS
localcount was designed by -nosplit Taylor R. Campbell, who also provided a draft implementation. The implementation was completed, tested, and integrated by Paul Goyette.

CAVEATS
The localcount facility does not provide any way to examine the reference count without actually waiting for the count to reach zero.

Waiting for a localcount reference count to drain (reach zero) is a one-shot operation. Once the localcount has been drained, no further operations are allowed until the localcount has been re-initialized.