|
NAMEepoch , epoch_context ,
epoch_alloc , epoch_free ,
epoch_enter , epoch_exit ,
epoch_wait ,
epoch_enter_preempt ,
epoch_exit_preempt ,
epoch_wait_preempt ,
epoch_call ,
epoch_drain_callbacks ,
in_epoch , in_epoch_verbose ,
—
kernel epoch based reclamation
SYNOPSIS#include <sys/param.h>
#include <sys/proc.h>
#include <sys/epoch.h>
struct epoch; /* Opaque */ typedef struct epoch *epoch_t; struct epoch_context { void *data[2]; }; typedef struct epoch_context *epoch_context_t; typedef void epoch_callback_t(epoch_context_t); struct epoch_tracker; /* Opaque */ typedef struct epoch_tracker *epoch_tracker_t; epoch_t
void
void
void
void
void
void
void
void
void
int
int
DESCRIPTIONEpochs are used to guarantee liveness and immutability of data by deferring reclamation and mutation until a grace period has elapsed. Epochs do not have any lock ordering issues. Entering and leaving an epoch section will never block.Epochs are allocated with
epochs are freed with
Threads indicate the start of an epoch critical section by calling
Threads can defer work until a grace period has expired since any
thread has entered the epoch either synchronously or asynchronously.
Default, non-preemptible epoch wait
( INVARIANTS can assert that a thread is in an epoch by using
The epoch API currently does not support sleeping in epoch_preempt
sections. A caller should never call The RETURN VALUESin_epoch (curepoch) will return 1
if curthread is in curepoch, 0 otherwise.
EXAMPLESAsync free example: Thread 1:int in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_laddr *laddr, struct ucred *cred) { /* ... */ epoch_enter(net_epoch); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { sa = ifa->ifa_addr; if (sa->sa_family != AF_INET) continue; sin = (struct sockaddr_in *)sa; if (prison_check_ip4(cred, &sin->sin_addr) == 0) { ia = (struct in_ifaddr *)ifa; break; } } epoch_exit(net_epoch); /* ... */ } void ifa_free(struct ifaddr *ifa) { if (refcount_release(&ifa->ifa_refcnt)) epoch_call(net_epoch, ifa_destroy, &ifa->ifa_epoch_ctx); } void if_purgeaddrs(struct ifnet *ifp) { /* .... * IF_ADDR_WLOCK(ifp); CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(ifa); } Thread 1 traverses the ifaddr list in an epoch. Thread 2 unlinks
with the corresponding epoch safe macro, marks as logically free, and then
defers deletion. More general mutation or a synchronous free would have to
follow a call to NOTESTheepoch kernel programming interface is under
development and is subject to change.
SEE ALSOlocking(9), mtx_pool(9), mutex(9), rwlock(9), sema(9), sleep(9), sx(9), timeout(9)HISTORYTheepoch framework first appeared in
FreeBSD 11.0.
CAVEATSOne must be cautious when usingepoch_wait_preempt ().
Threads are pinned during epoch sections, so if a thread in a section is then
preempted by a higher priority compute bound thread on that CPU, it can be
prevented from leaving the section indefinitely.
Epochs are not a straight replacement for read locks. Callers must use safe list and tailq traversal routines in an epoch (see ck_queue). When modifying a list referenced from an epoch section safe removal routines must be used and the caller can no longer modify a list entry in place. An item to be modified must be handled with copy on write and frees must be deferred until after a grace period has elapsed.
Visit the GSP FreeBSD Man Page Interface. |