]>
Commit | Line | Data |
---|---|---|
1bf9f027 DL |
1 | /* |
2 | * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. | |
3 | * | |
db2d8df6 DL |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
1bf9f027 | 7 | * |
db2d8df6 DL |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
1bf9f027 DL |
15 | */ |
16 | ||
17 | #ifndef _QOBJ_H | |
18 | #define _QOBJ_H | |
19 | ||
20 | #include <stdint.h> | |
21 | #include <stdlib.h> | |
22 | #include <stddef.h> | |
23 | ||
24 | /* reserve a specific amount of bytes for a struct, which can grow up to | |
25 | * that size (or be dummy'd out if not needed) | |
26 | * | |
27 | * note the padding's array size will be an error if it gets negative or zero; | |
28 | * this is intentional to prevent the struct from growing beyond the allocated | |
29 | * space. | |
30 | */ | |
d62a17ae | 31 | #define RESERVED_SPACE_STRUCT(name, fieldname, size) \ |
32 | struct { \ | |
33 | struct name fieldname; \ | |
34 | char padding##fieldname[size - sizeof(struct name)]; \ | |
1bf9f027 DL |
35 | }; |
36 | ||
37 | /* don't need struct definitions for these here. code actually using | |
38 | * these needs to define the struct *before* including this header. | |
39 | * HAVE_QOBJ_xxx should be defined to +1 in that case, like this: | |
40 | * | |
41 | * #if defined(HAVE_QOBJ_NODETYPE_CLI) && HAVE_QOBJ_NODETYPE_CLI < 0 | |
42 | * #error include files are in wrong order | |
43 | * #else | |
44 | * #define HAVE_QOBJ_NODETYPE_CLI 1 | |
45 | * struct qobj_nodetype_cli { ... } | |
46 | * #endif | |
47 | */ | |
48 | #ifndef HAVE_QOBJ_NODETYPE_CLI | |
49 | #define HAVE_QOBJ_NODETYPE_CLI -1 | |
d62a17ae | 50 | struct qobj_nodetype_cli { |
51 | int dummy; | |
52 | }; | |
1bf9f027 DL |
53 | #endif |
54 | ||
55 | #ifndef HAVE_QOBJ_NODETYPE_CAPNP | |
56 | #define HAVE_QOBJ_NODETYPE_CAPNP -1 | |
d62a17ae | 57 | struct qobj_nodetype_capnp { |
58 | int dummy; | |
59 | }; | |
1bf9f027 DL |
60 | #endif |
61 | ||
62 | /* each different kind of object will have a global variable of this type, | |
63 | * which can be used by various other pieces to store type-related bits. | |
64 | * type equality can be tested as pointer equality. (cf. QOBJ_GET_TYPESAFE) | |
65 | */ | |
66 | struct qobj_nodetype { | |
67 | ptrdiff_t node_member_offset; | |
68 | RESERVED_SPACE_STRUCT(qobj_nodetype_cli, cli, 256) | |
69 | RESERVED_SPACE_STRUCT(qobj_nodetype_capnp, capnp, 256) | |
70 | }; | |
71 | ||
72 | /* anchor to be embedded somewhere in the object's struct */ | |
73 | struct qobj_node { | |
74 | uint64_t nid; | |
75 | struct qobj_nodetype *type; | |
76 | }; | |
77 | ||
d62a17ae | 78 | #define QOBJ_FIELDS struct qobj_node qobj_node; |
1bf9f027 DL |
79 | |
80 | /* call these at the end of any _create function (QOBJ_REG) | |
81 | * and beginning of any _destroy function (QOBJ_UNREG) */ | |
d62a17ae | 82 | #define QOBJ_REG(n, structname) qobj_reg(&n->qobj_node, &qobj_t_##structname) |
83 | #define QOBJ_UNREG(n) qobj_unreg(&n->qobj_node) | |
1bf9f027 | 84 | |
297c8f6a DL |
85 | /* internals - should not be directly used without a good reason |
86 | * | |
87 | * note: qobj_get is essentially never safe to use in MT context because | |
88 | * the object could be deleted by another thread -- and worse, it could be | |
89 | * of the "wrong" type and deleted. | |
90 | * | |
91 | * with qobj_get_typed, the type check is done under lock, which means that | |
92 | * it can be used as long as another lock prevents the deletion of objects | |
93 | * of the expected type. | |
94 | * | |
95 | * in the long this may need another touch, e.g. built-in per-object locking. | |
96 | */ | |
1bf9f027 DL |
97 | void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type); |
98 | void qobj_unreg(struct qobj_node *node); | |
99 | struct qobj_node *qobj_get(uint64_t id); | |
100 | void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type); | |
101 | ||
102 | /* type declarations */ | |
d62a17ae | 103 | #define DECLARE_QOBJ_TYPE(structname) \ |
104 | extern struct qobj_nodetype qobj_t_##structname; | |
105 | #define DEFINE_QOBJ_TYPE(structname) \ | |
106 | struct qobj_nodetype qobj_t_##structname = { \ | |
107 | .node_member_offset = \ | |
108 | (ptrdiff_t)offsetof(struct structname, qobj_node)}; | |
109 | #define DEFINE_QOBJ_TYPE_INIT(structname, ...) \ | |
110 | struct qobj_nodetype qobj_t_##structname = { \ | |
111 | .node_member_offset = \ | |
112 | (ptrdiff_t)offsetof(struct structname, qobj_node), \ | |
113 | __VA_ARGS__}; | |
1bf9f027 DL |
114 | |
115 | /* ID dereference with typecheck. | |
116 | * will return NULL if id not found or wrong type. */ | |
d62a17ae | 117 | #define QOBJ_GET_TYPESAFE(id, structname) \ |
118 | ((struct structname *)qobj_get_typed((id), &qobj_t_##structname)) | |
1bf9f027 | 119 | |
d62a17ae | 120 | #define QOBJ_ID(ptr) ((ptr)->qobj_node.nid) |
121 | #define QOBJ_ID_0SAFE(ptr) \ | |
122 | ({ \ | |
123 | typeof(ptr) _ptr = (ptr); \ | |
124 | _ptr ? _ptr->qobj_node.nid : 0ULL; \ | |
125 | }) | |
1bf9f027 DL |
126 | |
127 | void qobj_init(void); | |
128 | void qobj_finish(void); | |
129 | ||
130 | #endif /* _QOBJ_H */ |