Linux Audio

Check our new training course

Loading...
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2/*
  3 * A tagged pointer implementation
  4 *
  5 * Copyright (C) 2018 Gao Xiang <gaoxiang25@huawei.com>
  6 */
  7#ifndef __EROFS_FS_TAGPTR_H
  8#define __EROFS_FS_TAGPTR_H
  9
 10#include <linux/types.h>
 11#include <linux/build_bug.h>
 12
 13/*
 14 * the name of tagged pointer types are tagptr{1, 2, 3...}_t
 15 * avoid directly using the internal structs __tagptr{1, 2, 3...}
 16 */
 17#define __MAKE_TAGPTR(n) \
 18typedef struct __tagptr##n {	\
 19	uintptr_t v;	\
 20} tagptr##n##_t;
 21
 22__MAKE_TAGPTR(1)
 23__MAKE_TAGPTR(2)
 24__MAKE_TAGPTR(3)
 25__MAKE_TAGPTR(4)
 26
 27#undef __MAKE_TAGPTR
 28
 29extern void __compiletime_error("bad tagptr tags")
 30	__bad_tagptr_tags(void);
 31
 32extern void __compiletime_error("bad tagptr type")
 33	__bad_tagptr_type(void);
 34
 35/* fix the broken usage of "#define tagptr2_t tagptr3_t" by users */
 36#define __tagptr_mask_1(ptr, n)	\
 37	__builtin_types_compatible_p(typeof(ptr), struct __tagptr##n) ? \
 38		(1UL << (n)) - 1 :
 39
 40#define __tagptr_mask(ptr)	(\
 41	__tagptr_mask_1(ptr, 1) ( \
 42	__tagptr_mask_1(ptr, 2) ( \
 43	__tagptr_mask_1(ptr, 3) ( \
 44	__tagptr_mask_1(ptr, 4) ( \
 45	__bad_tagptr_type(), 0)))))
 46
 47/* generate a tagged pointer from a raw value */
 48#define tagptr_init(type, val) \
 49	((typeof(type)){ .v = (uintptr_t)(val) })
 50
 51/*
 52 * directly cast a tagged pointer to the native pointer type, which
 53 * could be used for backward compatibility of existing code.
 54 */
 55#define tagptr_cast_ptr(tptr) ((void *)(tptr).v)
 56
 57/* encode tagged pointers */
 58#define tagptr_fold(type, ptr, _tags) ({ \
 59	const typeof(_tags) tags = (_tags); \
 60	if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(type))) \
 61		__bad_tagptr_tags(); \
 62tagptr_init(type, (uintptr_t)(ptr) | tags); })
 63
 64/* decode tagged pointers */
 65#define tagptr_unfold_ptr(tptr) \
 66	((void *)((tptr).v & ~__tagptr_mask(tptr)))
 67
 68#define tagptr_unfold_tags(tptr) \
 69	((tptr).v & __tagptr_mask(tptr))
 70
 71/* operations for the tagger pointer */
 72#define tagptr_eq(_tptr1, _tptr2) ({ \
 73	typeof(_tptr1) tptr1 = (_tptr1); \
 74	typeof(_tptr2) tptr2 = (_tptr2); \
 75	(void)(&tptr1 == &tptr2); \
 76(tptr1).v == (tptr2).v; })
 77
 78/* lock-free CAS operation */
 79#define tagptr_cmpxchg(_ptptr, _o, _n) ({ \
 80	typeof(_ptptr) ptptr = (_ptptr); \
 81	typeof(_o) o = (_o); \
 82	typeof(_n) n = (_n); \
 83	(void)(&o == &n); \
 84	(void)(&o == ptptr); \
 85tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
 86
 87/* wrap WRITE_ONCE if atomic update is needed */
 88#define tagptr_replace_tags(_ptptr, tags) ({ \
 89	typeof(_ptptr) ptptr = (_ptptr); \
 90	*ptptr = tagptr_fold(*ptptr, tagptr_unfold_ptr(*ptptr), tags); \
 91*ptptr; })
 92
 93#define tagptr_set_tags(_ptptr, _tags) ({ \
 94	typeof(_ptptr) ptptr = (_ptptr); \
 95	const typeof(_tags) tags = (_tags); \
 96	if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
 97		__bad_tagptr_tags(); \
 98	ptptr->v |= tags; \
 99*ptptr; })
100
101#define tagptr_clear_tags(_ptptr, _tags) ({ \
102	typeof(_ptptr) ptptr = (_ptptr); \
103	const typeof(_tags) tags = (_tags); \
104	if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
105		__bad_tagptr_tags(); \
106	ptptr->v &= ~tags; \
107*ptptr; })
108
109#endif	/* __EROFS_FS_TAGPTR_H */
110