1/* @title: Per-Domain dynamic objects */
2#pragma once
3#include <compiler/core.h>
4#include <global.h>
5#include <linker/symbols.h>
6#include <smp/domain.h>
7#include <stddef.h>
8#include <stdint.h>
9
10struct perdomain_descriptor;
11typedef void (*perdomain_descriptor_constructor)(void *, size_t);
12
13struct perdomain_descriptor {
14 const char *name;
15 size_t size;
16 size_t align;
17 void **perdomain_ptrs;
18 perdomain_descriptor_constructor constructor;
19 atomic_bool ready;
20};
21
22LINKER_SECTION_EXTERN(struct perdomain_descriptor, perdomain_desc);
23
24#define PERDOMAIN_DEFINE_3(type_, name_, ctor_) \
25 static typeof(type_) __perdomain_##name_ cc_unused; \
26 static struct perdomain_descriptor __perdomain_desc_##name_; \
27 static void __perdomain_ctor_##name_(void *inst, size_t domain) { \
28 void (*const __typed_ctor)(typeof(type_) *, size_t) = (ctor_); \
29 if (__typed_ctor != NULL) \
30 __typed_ctor((typeof(type_) *) inst, domain); \
31 if (domain == global.domain_count - 1) \
32 atomic_store(&__perdomain_desc_##name_.ready, true); \
33 } \
34 static LINKER_SECTION_OBJECT(struct perdomain_descriptor, perdomain_desc) \
35 __perdomain_desc_##name_ = { \
36 .name = #name_, \
37 .size = sizeof(typeof(type_)), \
38 .align = cc_alignof(typeof(type_)), \
39 .perdomain_ptrs = NULL, \
40 .constructor = __perdomain_ctor_##name_, \
41 .ready = false, \
42 }; \
43 static struct perdomain_descriptor *const __perdomain_desc_ref_##name_ \
44 cc_unused = &__perdomain_desc_##name_
45
46#define PERDOMAIN_DEFINE_2(type_, name_) PERDOMAIN_DEFINE_3(type_, name_, NULL)
47#define PERDOMAIN_DEFINE(...) PP_CALL(PERDOMAIN_DEFINE, __VA_ARGS__)
48
49#define PERDOMAIN_EXPORT_AS(sym_name, name) \
50 extern struct perdomain_descriptor __perdomain_desc_sym_##sym_name \
51 cc_alias(__perdomain_desc_##name) cc_used
52
53#define PERDOMAIN_EXPORT(name) PERDOMAIN_EXPORT_AS(name, name)
54
55#define PERDOMAIN_EXTERN_AS(type, name, sym_name) \
56 extern struct perdomain_descriptor __perdomain_desc_sym_##sym_name; \
57 static typeof(type) __perdomain_##name cc_unused; \
58 static struct perdomain_descriptor *const __perdomain_desc_ref_##name \
59 cc_unused = &__perdomain_desc_sym_##sym_name
60
61#define PERDOMAIN_EXTERN(type, name) PERDOMAIN_EXTERN_AS(type, name, name)
62
63static inline
64 cc_pure bool perdomain_desc_ready(const struct perdomain_descriptor *desc) {
65 return atomic_load(&desc->ready);
66}
67
68#define PERDOMAIN(name) &(__perdomain_##name)
69#define PERDOMAIN_READY(name) \
70 (atomic_load(&(__perdomain_desc_ref_##name)->ready))
71
72#define PERDOMAIN_PTR_FOR(name, d) \
73 ({ \
74 assume(perdomain_desc_ready(__perdomain_desc_ref_##name)); \
75 ((typeof(__perdomain_##name) *) (__perdomain_desc_ref_##name) \
76 ->perdomain_ptrs[d]); \
77 })
78
79#define PERDOMAIN_READ_FOR(name, d) \
80 (*((typeof(__perdomain_##name) *) PERDOMAIN_PTR_FOR(name, d)))
81
82#define PERDOMAIN_PTR(clr, name) PERDOMAIN_PTR_FOR(name, domain_local_id(clr))
83#define PERDOMAIN_READ(clr, name) \
84 (*((typeof(__perdomain_##name) *) PERDOMAIN_PTR(clr, name)))
85
86#define PERDOMAIN_WRITE(clr, name, val) (PERDOMAIN_READ(clr, name) = (val))
87
88#define perdomain_for_each_internal_3(var, domain, name) \
89 for (domain = 0; domain < global.domain_count; domain++) \
90 for (var = PERDOMAIN_PTR_FOR(name, domain); var != NULL; var = NULL)
91
92#define perdomain_for_each_internal_2(var, name) \
93 for (domain_id_t __perdomain_idx = 0; \
94 __perdomain_idx < global.domain_count; __perdomain_idx++) \
95 for (var = PERDOMAIN_PTR_FOR(name, __perdomain_idx); var != NULL; \
96 var = NULL)
97
98#define perdomain_for_each(...) \
99 PP_CALL(perdomain_for_each_internal, __VA_ARGS__)
100
101void perdomain_obj_init(void);
102void **perdomain_alloc_array(size_t size);
103