seqc: add a sleepable variant and convert some routines to macros

This temporarily duplicates some code.

Macro conversion convinces clang to carry predicts into consumers.
This commit is contained in:
Mateusz Guzik 2020-07-25 10:29:48 +00:00
parent 62ad310c93
commit 82dc812235
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=363516
2 changed files with 47 additions and 15 deletions

11
sys/sys/_seqc.h Normal file
View File

@ -0,0 +1,11 @@
/*-
* This file is in the public domain.
*/
/* $FreeBSD$ */
#ifndef _SYS__SEQC_H_
#define _SYS__SEQC_H_
typedef uint32_t seqc_t;
#endif /* _SYS__SEQC_H */

View File

@ -36,7 +36,7 @@
/*
* seqc_t may be included in structs visible to userspace
*/
typedef uint32_t seqc_t;
#include <sys/_seqc.h>
#ifdef _KERNEL
@ -45,12 +45,14 @@ typedef uint32_t seqc_t;
#include <machine/cpu.h>
static __inline bool
seqc_in_modify(seqc_t seqcp)
{
return (seqcp & 1);
}
/*
* Predicts from inline functions are not honored by clang.
*/
#define seqc_in_modify(seqc) ({ \
seqc_t __seqc = (seqc); \
\
__predict_false(__seqc & 1); \
})
static __inline void
seqc_write_begin(seqc_t *seqcp)
@ -86,7 +88,7 @@ seqc_read(const seqc_t *seqcp)
for (;;) {
ret = seqc_read_any(seqcp);
if (__predict_false(seqc_in_modify(ret))) {
if (seqc_in_modify(ret)) {
cpu_spinwait();
continue;
}
@ -96,19 +98,38 @@ seqc_read(const seqc_t *seqcp)
return (ret);
}
static __inline bool
seqc_consistent_nomb(const seqc_t *seqcp, seqc_t oldseqc)
#define seqc_consistent_nomb(seqcp, oldseqc) ({ \
const seqc_t *__seqcp = (seqcp); \
seqc_t __oldseqc = (oldseqc); \
\
MPASS(!(seqc_in_modify(__oldseqc))); \
__predict_true(*__seqcp == __oldseqc); \
})
#define seqc_consistent(seqcp, oldseqc) ({ \
atomic_thread_fence_acq(); \
seqc_consistent_nomb(seqcp, oldseqc); \
})
/*
* Variant which does not critical enter/exit.
*/
static __inline void
seqc_sleepable_write_begin(seqc_t *seqcp)
{
return (*seqcp == oldseqc);
MPASS(!seqc_in_modify(*seqcp));
*seqcp += 1;
atomic_thread_fence_rel();
}
static __inline bool
seqc_consistent(const seqc_t *seqcp, seqc_t oldseqc)
static __inline void
seqc_sleepable_write_end(seqc_t *seqcp)
{
atomic_thread_fence_acq();
return (seqc_consistent_nomb(seqcp, oldseqc));
atomic_thread_fence_rel();
*seqcp += 1;
MPASS(!seqc_in_modify(*seqcp));
}
#endif /* _KERNEL */