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