#ifndef _LINUXKPI_LINUX_RCUPDATE_H_
#define _LINUXKPI_LINUX_RCUPDATE_H_
#include <sys/cdefs.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/cleanup.h>
#include <machine/atomic.h>
extern int linuxkpi_rcu_debug;
#define RCU_WARN_ONCE(c, ...) do { \
if (unlikely(linuxkpi_rcu_debug > 0)) \
WARN_ONCE((c), ##__VA_ARGS__); \
} while(0)
#define LINUX_KFREE_RCU_OFFSET_MAX 4096
#define RCU_TYPE_REGULAR 0
#define RCU_TYPE_SLEEPABLE 1
#define RCU_TYPE_MAX 2
#define RCU_INITIALIZER(v) \
((__typeof(*(v)) *)(v))
#define RCU_INIT_POINTER(p, v) do { \
(p) = (v); \
} while (0)
#define call_rcu(ptr, func) do { \
linux_call_rcu(RCU_TYPE_REGULAR, ptr, func); \
} while (0)
#define rcu_barrier(void) do { \
linux_rcu_barrier(RCU_TYPE_REGULAR); \
} while (0)
#define rcu_read_lock(void) do { \
linux_rcu_read_lock(RCU_TYPE_REGULAR); \
} while (0)
#define rcu_read_unlock(void) do { \
linux_rcu_read_unlock(RCU_TYPE_REGULAR);\
} while (0)
#define rcu_read_lock_held(void) \
linux_rcu_read_lock_held(RCU_TYPE_REGULAR)
#define synchronize_rcu(void) do { \
linux_synchronize_rcu(RCU_TYPE_REGULAR); \
} while (0)
#define synchronize_rcu_expedited(void) do { \
linux_synchronize_rcu(RCU_TYPE_REGULAR); \
} while (0)
#define kfree_rcu(ptr, rcu_head) do { \
CTASSERT(offsetof(__typeof(*(ptr)), rcu_head) < \
LINUX_KFREE_RCU_OFFSET_MAX); \
call_rcu(&(ptr)->rcu_head, (rcu_callback_t)(uintptr_t) \
offsetof(__typeof(*(ptr)), rcu_head)); \
} while (0)
#define rcu_access_pointer(p) \
((__typeof(*p) *)READ_ONCE(p))
#define rcu_dereference(p) \
((__typeof(*p) *)READ_ONCE(p))
#define __rcu_var_name(n, f, l) \
__CONCAT(__CONCAT(__CONCAT(rcu_, n), _), __COUNTER__)
#define __rcu_dereference_protected(p, c, n) \
({ \
RCU_WARN_ONCE(!(c), "%s:%d: condition for %s failed\n", \
__func__, __LINE__, __XSTRING(n)); \
rcu_dereference(p); \
})
#define rcu_dereference_protected(p, c) \
__rcu_dereference_protected((p), (c), \
__rcu_var_name(protected, __func__, __LINE__))
#define __rcu_dereference_check(p, c, n) \
({ \
__typeof(*p) *n = rcu_dereference(p); \
RCU_WARN_ONCE(!(c), "%s:%d: condition for %s failed\n", \
__func__, __LINE__, __XSTRING(n)); \
n; \
})
#define rcu_dereference_check(p, c) \
__rcu_dereference_check((p), (c) || rcu_read_lock_held(), \
__rcu_var_name(check, __func__, __LINE__))
#define rcu_dereference_raw(p) \
((__typeof(*p) *)READ_ONCE(p))
#define rcu_pointer_handoff(p) (p)
#define rcu_assign_pointer(p, v) do { \
atomic_store_rel_ptr((volatile uintptr_t *)&(p), \
(uintptr_t)(v)); \
} while (0)
#define rcu_replace_pointer(rcu, ptr, c) \
({ \
typeof(ptr) __tmp = rcu_dereference_protected(rcu, c); \
rcu_assign_pointer(rcu, ptr); \
__tmp; \
})
#define rcu_swap_protected(rcu, ptr, c) do { \
typeof(ptr) p = rcu_dereference_protected(rcu, c); \
rcu_assign_pointer(rcu, ptr); \
(ptr) = p; \
} while (0)
void linux_call_rcu(unsigned type, struct rcu_head *ptr, rcu_callback_t func);
void linux_rcu_barrier(unsigned type);
void linux_rcu_read_lock(unsigned type);
void linux_rcu_read_unlock(unsigned type);
bool linux_rcu_read_lock_held(unsigned);
void linux_synchronize_rcu(unsigned type);
#define init_rcu_head(...)
#define destroy_rcu_head(...)
#define init_rcu_head_on_stack(...)
#define destroy_rcu_head_on_stack(...)
DEFINE_LOCK_GUARD_0(rcu, rcu_read_lock(), rcu_read_unlock())
#endif