aboutsummaryrefslogtreecommitdiff
path: root/share/man/man9
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2019-12-28 01:35:32 +0000
committerConrad Meyer <cem@FreeBSD.org>2019-12-28 01:35:32 +0000
commit2c1962aba6e73dd0c430636082145f92d636ff13 (patch)
treecf8e7e104bdc9a2bbf5414835d875cc032e8baa2 /share/man/man9
parent5541eb27d6bff23d907cdc5d3b2591c1c71c317a (diff)
downloadsrc-2c1962aba6e73dd0c430636082145f92d636ff13.tar.gz
src-2c1962aba6e73dd0c430636082145f92d636ff13.zip
epoch.9: Add missing functions, clean up documentation
Various rototilling.
Notes
Notes: svn path=/head/; revision=356140
Diffstat (limited to 'share/man/man9')
-rw-r--r--share/man/man9/epoch.9191
1 files changed, 133 insertions, 58 deletions
diff --git a/share/man/man9/epoch.9 b/share/man/man9/epoch.9
index 48ad09d2e249..ca3886c9860c 100644
--- a/share/man/man9/epoch.9
+++ b/share/man/man9/epoch.9
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 28, 2019
+.Dd December 27, 2019
.Dt EPOCH 9
.Os
.Sh NAME
@@ -37,34 +37,58 @@
.Nm epoch_enter ,
.Nm epoch_exit ,
.Nm epoch_wait ,
+.Nm epoch_enter_preempt ,
+.Nm epoch_exit_preempt ,
+.Nm epoch_wait_preempt ,
.Nm epoch_call ,
.Nm epoch_drain_callbacks ,
.Nm in_epoch ,
+.Nm in_epoch_verbose ,
.Nd kernel epoch based reclamation
.Sh SYNOPSIS
.In sys/param.h
.In sys/proc.h
.In sys/epoch.h
+.\" Types
+.Bd -literal
+struct epoch; /* Opaque */
+.Ed
+.Vt typedef "struct epoch *epoch_t" ;
+.Bd -literal
+struct epoch_context {
+ void *data[2];
+};
+.Ed
+.Vt typedef "struct epoch_context *epoch_context_t" ;
+.Bd -literal
+struct epoch_tracker; /* Opaque */
+.Ed
+.Vt typedef "struct epoch_tracker *epoch_tracker_t" ;
+.\" Declarations
.Ft epoch_t
-.Fn epoch_alloc "int flags"
+.Fn epoch_alloc "const char *name" "int flags"
.Ft void
-.Fn epoch_enter "epoch_t epoch"
+.Fn epoch_free "epoch_t epoch"
.Ft void
-.Fn epoch_enter_preempt "epoch_t epoch" "epoch_tracker_t et"
+.Fn epoch_enter "epoch_t epoch"
.Ft void
.Fn epoch_exit "epoch_t epoch"
.Ft void
-.Fn epoch_exit_preempt "epoch_t epoch" "epoch_tracker_t et"
-.Ft void
.Fn epoch_wait "epoch_t epoch"
.Ft void
+.Fn epoch_enter_preempt "epoch_t epoch" "epoch_tracker_t et"
+.Ft void
+.Fn epoch_exit_preempt "epoch_t epoch" "epoch_tracker_t et"
+.Ft void
.Fn epoch_wait_preempt "epoch_t epoch"
.Ft void
-.Fn epoch_call "epoch_t epoch" "epoch_context_t ctx" "void (*callback) (epoch_context_t)"
+.Fn epoch_call "epoch_t epoch" "epoch_context_t ctx" "void (*callback)(epoch_context_t)"
.Ft void
.Fn epoch_drain_callbacks "epoch_t epoch"
.Ft int
.Fn in_epoch "epoch_t epoch"
+.Ft int
+.Fn in_epoch_verbose "epoch_t epoch" "int dump_onfail"
.Sh DESCRIPTION
Epochs are used to guarantee liveness and immutability of data by
deferring reclamation and mutation until a grace period has elapsed.
@@ -72,58 +96,105 @@ Epochs do not have any lock ordering issues.
Entering and leaving an epoch section will never block.
.Pp
Epochs are allocated with
-.Fn epoch_alloc
-and freed with
+.Fn epoch_alloc .
+The
+.Fa name
+argument is used for debugging convenience when the
+.Cd EPOCH_TRACE
+kernel option is configured.
+By default, epochs do not allow preemption during sections.
+By default mutexes cannot be held across
+.Fn epoch_wait_preempt .
+The
+.Fa flags
+specified are formed by
+.Em OR Ns 'ing
+the following values:
+.Bl -tag -offset indent -width Ds
+.It Dv EPOCH_LOCKED
+Permit holding mutexes across
+.Fn epoch_wait_preempt
+(requires
+.Dv EPOCH_PREEMPT ) .
+When doing this one must be cautious of creating a situation where a deadlock
+is possible.
+.It Dv EPOCH_PREEMPT
+The
+.Vt epoch
+will allow preemption during sections.
+Only non-sleepable locks may be acquired during a preemptible epoch.
+The functions
+.Fn epoch_enter_preempt ,
+.Fn epoch_exit_preempt ,
+and
+.Fn epoch_wait_preempt
+must be used in place of
+.Fn epoch_enter ,
+.Fn epoch_exit ,
+and
+.Fn epoch_wait ,
+respectively.
+.El
+.Pp
+.Vt epoch Ns s
+are freed with
.Fn epoch_free .
-The flags passed to epoch_alloc determine whether preemption is
-allowed during a section or not (the default), as specified by
-EPOCH_PREEMPT.
+.Pp
Threads indicate the start of an epoch critical section by calling
-.Fn epoch_enter .
-The end of a critical section is indicated by calling
-.Fn epoch_exit .
-The _preempt variants can be used around code which requires preemption.
-A thread can wait until a grace period has elapsed
-since any threads have entered
-the epoch by calling
-.Fn epoch_wait
-or
-.Fn epoch_wait_preempt ,
-depending on the epoch_type.
-The use of a default epoch type allows one to use
-.Fn epoch_wait
-which is guaranteed to have much shorter completion times since
-we know that none of the threads in an epoch section will be preempted
-before completing its section.
-If the thread can't sleep or is otherwise in a performance sensitive
-path it can ensure that a grace period has elapsed by calling
-.Fn epoch_call
-with a callback with any work that needs to wait for an epoch to elapse.
-Only non-sleepable locks can be acquired during a section protected by
+.Fn epoch_enter
+(or
+.Fn epoch_enter_preempt
+for preemptible epochs).
+Threads call
+.Fn epoch_exit
+(or
+.Fn epoch_exit_preempt
+for preemptible epochs)
+to indicate the end of a critical section.
+.Vt struct epoch_tracker Ns s
+are stack objects whose pointers are passed to
.Fn epoch_enter_preempt
and
-.Fn epoch_exit_preempt .
+.Fn epoch_exit_preempt
+(much like
+.Vt struct rm_priotracker ) .
+.Pp
+Threads can defer work until a grace period has expired since any thread has
+entered the epoch either synchronously or asynchronously.
+.Fn epoch_call
+defers work asynchronously by invoking the provided
+.Fa callback
+at a later time.
+.Fn epoch_wait
+(or
+.Fn epoch_wait_preempt )
+blocks the current thread until the grace period has expired and the work can be
+done safely.
+.Pp
+Default, non-preemptible epoch wait
+.Fn ( epoch_wait )
+is guaranteed to have much shorter completion times relative to
+preemptible epoch wait
+.Fn ( epoch_wait_preempt ) .
+(In the default type, none of the threads in an epoch section will be preempted
+before completing its section.)
+.Pp
INVARIANTS can assert that a thread is in an epoch by using
.Fn in_epoch .
+.Fn in_epoch "epoch"
+is equivalent to invoking
+.Fn in_epoch_verbose "epoch" "0" .
+If
+.Cd EPOCH_TRACE
+is enabled,
+.Fn in_epoch_verbose "epoch" "1"
+provides additional verbose debugging information.
.Pp
The epoch API currently does not support sleeping in epoch_preempt sections.
A caller should never call
.Fn epoch_wait
in the middle of an epoch section for the same epoch as this will lead to a deadlock.
.Pp
-By default mutexes cannot be held across
-.Fn epoch_wait_preempt .
-To permit this the epoch must be allocated with
-EPOCH_LOCKED.
-When doing this one must be cautious of creating a situation where a deadlock is
-possible. Note that 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.
-.Pp
The
.Fn epoch_drain_callbacks
function is used to drain all pending callbacks which have been invoked by prior
@@ -140,12 +211,18 @@ This function can sleep and is not optimized for performance.
will return 1 if curthread is in curepoch, 0 otherwise.
.Sh CAVEATS
One must be cautious when using
-.Fn epoch_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.
-Thus the wait time for the waiter is
-potentially unbounded.
+.Fn epoch_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.
+.Pp
+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.
.Sh EXAMPLES
Async free example:
Thread 1:
@@ -154,8 +231,8 @@ int
in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_laddr *laddr,
struct ucred *cred)
{
- /* ... */
- epoch_enter(net_epoch);
+ /* ... */
+ epoch_enter(net_epoch);
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
sa = ifa->ifa_addr;
if (sa->sa_family != AF_INET)
@@ -167,7 +244,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_laddr *laddr,
}
}
epoch_exit(net_epoch);
- /* ... */
+ /* ... */
}
.Ed
Thread 2:
@@ -198,8 +275,6 @@ and then defers deletion.
More general mutation or a synchronous
free would have to follow a call to
.Fn epoch_wait .
-.Sh ERRORS
-None.
.Sh NOTES
The
.Nm