macros.h: Introduce side_ptr macros
[libside.git] / include / side / macros.h
CommitLineData
f611d0c3
MD
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
67337c4a
MD
6#ifndef _SIDE_MACROS_H
7#define _SIDE_MACROS_H
f611d0c3 8
6e46f5e6 9#include <stddef.h>
8e87e437 10#include <limits.h>
6e46f5e6 11
f611d0c3
MD
12/* Helper macros */
13
67337c4a 14#define SIDE_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
f611d0c3
MD
15
16/*
67337c4a 17 * Compound literals with static storage are needed by SIDE
f611d0c3
MD
18 * instrumentation.
19 * Compound literals are part of the C99 and C11 standards, but not
20 * part of the C++ standards. They are supported by most C++ compilers
21 * though.
22 *
23 * Example use:
24 * static struct mystruct *var = LTTNG_UST_COMPOUND_LITERAL(struct mystruct, { 1, 2, 3 });
25 */
67337c4a 26#define SIDE_COMPOUND_LITERAL(type, ...) (type[]) { __VA_ARGS__ }
f611d0c3 27
67337c4a
MD
28#define side_likely(x) __builtin_expect(!!(x), 1)
29#define side_unlikely(x) __builtin_expect(!!(x), 0)
f611d0c3 30
67337c4a 31#define SIDE_PARAM(...) __VA_ARGS__
f611d0c3 32
d0ee69ff
MD
33/*
34 * SIDE_PARAM_SELECT_ARG1
35 *
36 * Select second argument. Use inside macros to implement optional last
37 * macro argument, such as:
38 *
39 * #define macro(_a, _b, _c, _optional...) \
40 * SIDE_PARAM_SELECT_ARG1(_, ##_optional, do_default_macro())
41 *
42 * This macro is far from pretty, but attempts to create a cleaner layer
43 * on top fails for various reasons:
44 *
45 * - The libside API needs to use the default argument selection as an
46 * argument to itself (recursively), e.g. for fields and for types, so
47 * using the argument selection within an extra layer of macro fails
48 * because the extra layer cannot expand recursively.
49 * - Attempts to make the extra layer of macro support recursion through
50 * another layer of macros which expands all arguments failed because
51 * the optional argument may contain commas, and is therefore expanded
52 * into multiple arguments before argument selection, which fails to
53 * select the optional argument content after its first comma.
54 */
55#define SIDE_PARAM_SELECT_ARG1(_arg0, _arg1, ...) _arg1
56
b59abc69 57/*
67337c4a 58 * side_container_of - Get the address of an object containing a field.
b59abc69
MD
59 *
60 * @ptr: pointer to the field.
61 * @type: type of the object.
62 * @member: name of the field within the object.
63 */
67337c4a 64#define side_container_of(ptr, type, member) \
b59abc69
MD
65 __extension__ \
66 ({ \
67 const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \
68 (type *)((char *)__ptr - offsetof(type, member)); \
69 })
70
67337c4a 71#define side_struct_field_sizeof(_struct, _field) \
88bab79c 72 sizeof(((_struct * )NULL)->_field)
8e87e437 73
f61301bb 74#if defined(__SIZEOF_LONG__)
d78c8f2d 75# define SIDE_BITS_PER_LONG (__SIZEOF_LONG__ * 8)
f61301bb 76#elif defined(_LP64)
d78c8f2d 77# define SIDE_BITS_PER_LONG 64
f61301bb 78#else
d78c8f2d 79# define SIDE_BITS_PER_LONG 32
f61301bb
MD
80#endif
81
67337c4a 82#define SIDE_PACKED __attribute__((packed))
de4ae6e8 83
326c676c
MD
84/*
85 * The side_ptr macros allow defining a pointer type which is suitable
86 * for use by 32-bit and 64-bit kernels without compatibility code,
87 * while preserving information about the pointer type.
88 *
89 * Those pointers are stored as 64-bit integers, and the type of the
90 * actual pointer is kept alongside with the 64-bit pointer value in a
91 * 0-len array within a union.
92 *
93 * uintptr_t will fit within a uint64_t except on architectures with
94 * 128-bit pointers. This provides fixed-size pointers on architectures
95 * with pointer size of 64-bit or less. Architectures with larger
96 * pointer size will have to handle the ABI offset specifics explicitly.
97 */
98#if (__SIZEOF_POINTER__ <= 8)
99# define side_ptr_t(_type) \
100 union { \
101 uint64_t v; \
102 _type *t[0]; \
103 }
104# define side_ptr_get(_field) \
105 ((__typeof__((_field).t[0]))(uintptr_t)(_field).v)
106# define side_ptr_set(_field, _ptr) \
107 do { \
108 (_field).v = (uint64_t)(uintptr_t)(_ptr); \
109 } while (0)
110#else
111# define side_ptr_t(_type) \
112 union { \
113 uintptr_t v; \
114 _type *t[0]; \
115 }
116# define side_ptr_get(_field) \
117 ((__typeof__((_field).t[0]))(_field).v)
118# define side_ptr_set(_field, _ptr) \
119 do { \
120 (_field).v = (uintptr_t)(_ptr); \
121 } while (0)
122#endif
123
67337c4a 124#endif /* _SIDE_MACROS_H */
This page took 0.028306 seconds and 4 git commands to generate.