]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: ISC |
1bf9f027 DL |
2 | /* |
3 | * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. | |
1bf9f027 DL |
4 | */ |
5 | ||
6 | #ifndef _QOBJ_H | |
7 | #define _QOBJ_H | |
8 | ||
9 | #include <stdint.h> | |
10 | #include <stdlib.h> | |
11 | #include <stddef.h> | |
12 | ||
679b1649 DL |
13 | #include "typesafe.h" |
14 | ||
5e244469 RW |
15 | #ifdef __cplusplus |
16 | extern "C" { | |
17 | #endif | |
18 | ||
1bf9f027 DL |
19 | /* reserve a specific amount of bytes for a struct, which can grow up to |
20 | * that size (or be dummy'd out if not needed) | |
21 | * | |
22 | * note the padding's array size will be an error if it gets negative or zero; | |
23 | * this is intentional to prevent the struct from growing beyond the allocated | |
24 | * space. | |
25 | */ | |
f8cd615b | 26 | #ifndef __cplusplus |
d62a17ae | 27 | #define RESERVED_SPACE_STRUCT(name, fieldname, size) \ |
28 | struct { \ | |
29 | struct name fieldname; \ | |
30 | char padding##fieldname[size - sizeof(struct name)]; \ | |
1bf9f027 | 31 | }; |
f8cd615b DL |
32 | #else |
33 | #define RESERVED_SPACE_STRUCT(name, fieldname, size) \ | |
34 | struct name fieldname; \ | |
35 | char padding##fieldname[size - sizeof(struct name)]; | |
36 | #endif | |
1bf9f027 DL |
37 | |
38 | /* don't need struct definitions for these here. code actually using | |
39 | * these needs to define the struct *before* including this header. | |
40 | * HAVE_QOBJ_xxx should be defined to +1 in that case, like this: | |
41 | * | |
42 | * #if defined(HAVE_QOBJ_NODETYPE_CLI) && HAVE_QOBJ_NODETYPE_CLI < 0 | |
43 | * #error include files are in wrong order | |
44 | * #else | |
45 | * #define HAVE_QOBJ_NODETYPE_CLI 1 | |
46 | * struct qobj_nodetype_cli { ... } | |
47 | * #endif | |
48 | */ | |
49 | #ifndef HAVE_QOBJ_NODETYPE_CLI | |
50 | #define HAVE_QOBJ_NODETYPE_CLI -1 | |
d62a17ae | 51 | struct qobj_nodetype_cli { |
52 | int dummy; | |
53 | }; | |
1bf9f027 DL |
54 | #endif |
55 | ||
56 | #ifndef HAVE_QOBJ_NODETYPE_CAPNP | |
57 | #define HAVE_QOBJ_NODETYPE_CAPNP -1 | |
d62a17ae | 58 | struct qobj_nodetype_capnp { |
59 | int dummy; | |
60 | }; | |
1bf9f027 DL |
61 | #endif |
62 | ||
679b1649 DL |
63 | #include "typesafe.h" |
64 | ||
1bf9f027 DL |
65 | /* each different kind of object will have a global variable of this type, |
66 | * which can be used by various other pieces to store type-related bits. | |
67 | * type equality can be tested as pointer equality. (cf. QOBJ_GET_TYPESAFE) | |
68 | */ | |
69 | struct qobj_nodetype { | |
70 | ptrdiff_t node_member_offset; | |
71 | RESERVED_SPACE_STRUCT(qobj_nodetype_cli, cli, 256) | |
72 | RESERVED_SPACE_STRUCT(qobj_nodetype_capnp, capnp, 256) | |
73 | }; | |
74 | ||
960b9a53 | 75 | PREDECL_HASH(qobj_nodes); |
679b1649 | 76 | |
1bf9f027 DL |
77 | /* anchor to be embedded somewhere in the object's struct */ |
78 | struct qobj_node { | |
79 | uint64_t nid; | |
679b1649 | 80 | struct qobj_nodes_item nodehash; |
154e9ca1 | 81 | const struct qobj_nodetype *type; |
1bf9f027 DL |
82 | }; |
83 | ||
96244aca | 84 | #define QOBJ_FIELDS struct qobj_node qobj_node |
1bf9f027 DL |
85 | |
86 | /* call these at the end of any _create function (QOBJ_REG) | |
87 | * and beginning of any _destroy function (QOBJ_UNREG) */ | |
d62a17ae | 88 | #define QOBJ_REG(n, structname) qobj_reg(&n->qobj_node, &qobj_t_##structname) |
89 | #define QOBJ_UNREG(n) qobj_unreg(&n->qobj_node) | |
1bf9f027 | 90 | |
297c8f6a DL |
91 | /* internals - should not be directly used without a good reason |
92 | * | |
93 | * note: qobj_get is essentially never safe to use in MT context because | |
94 | * the object could be deleted by another thread -- and worse, it could be | |
95 | * of the "wrong" type and deleted. | |
96 | * | |
97 | * with qobj_get_typed, the type check is done under lock, which means that | |
98 | * it can be used as long as another lock prevents the deletion of objects | |
99 | * of the expected type. | |
100 | * | |
101 | * in the long this may need another touch, e.g. built-in per-object locking. | |
102 | */ | |
154e9ca1 | 103 | void qobj_reg(struct qobj_node *node, const struct qobj_nodetype *type); |
1bf9f027 DL |
104 | void qobj_unreg(struct qobj_node *node); |
105 | struct qobj_node *qobj_get(uint64_t id); | |
154e9ca1 | 106 | void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type); |
1bf9f027 DL |
107 | |
108 | /* type declarations */ | |
d62a17ae | 109 | #define DECLARE_QOBJ_TYPE(structname) \ |
96244aca DL |
110 | extern const struct qobj_nodetype qobj_t_##structname \ |
111 | /* end */ | |
d62a17ae | 112 | #define DEFINE_QOBJ_TYPE(structname) \ |
154e9ca1 | 113 | const struct qobj_nodetype qobj_t_##structname = { \ |
d62a17ae | 114 | .node_member_offset = \ |
96244aca DL |
115 | (ptrdiff_t)offsetof(struct structname, qobj_node)} \ |
116 | /* end */ | |
d62a17ae | 117 | #define DEFINE_QOBJ_TYPE_INIT(structname, ...) \ |
154e9ca1 | 118 | const struct qobj_nodetype qobj_t_##structname = { \ |
d62a17ae | 119 | .node_member_offset = \ |
120 | (ptrdiff_t)offsetof(struct structname, qobj_node), \ | |
96244aca DL |
121 | __VA_ARGS__} \ |
122 | /* end */ | |
1bf9f027 DL |
123 | |
124 | /* ID dereference with typecheck. | |
125 | * will return NULL if id not found or wrong type. */ | |
d62a17ae | 126 | #define QOBJ_GET_TYPESAFE(id, structname) \ |
127 | ((struct structname *)qobj_get_typed((id), &qobj_t_##structname)) | |
1bf9f027 | 128 | |
d62a17ae | 129 | #define QOBJ_ID(ptr) ((ptr)->qobj_node.nid) |
130 | #define QOBJ_ID_0SAFE(ptr) \ | |
131 | ({ \ | |
132 | typeof(ptr) _ptr = (ptr); \ | |
133 | _ptr ? _ptr->qobj_node.nid : 0ULL; \ | |
134 | }) | |
1bf9f027 DL |
135 | |
136 | void qobj_init(void); | |
137 | void qobj_finish(void); | |
138 | ||
5e244469 RW |
139 | #ifdef __cplusplus |
140 | } | |
141 | #endif | |
142 | ||
1bf9f027 | 143 | #endif /* _QOBJ_H */ |