1/* @title: Per-Topology level dynamic objects */
2#pragma once
3#include <atomic.h>
4#include <compiler/core.h>
5#include <global.h>
6#include <linker/symbols.h>
7#include <smp/core.h>
8#include <smp/topology.h>
9#include <stddef.h>
10#include <stdint.h>
11
12/* Core per-topology macros */
13struct pertopo_descriptor;
14typedef void (*pertopo_descriptor_constructor)(void *, size_t);
15
16struct pertopo_descriptor {
17 enum topology_level level;
18 const char *name;
19 size_t size;
20 size_t align;
21 void **pertopo_ptrs;
22 pertopo_descriptor_constructor constructor;
23 atomic_bool ready;
24};
25
26LINKER_SECTION_EXTERN(struct pertopo_descriptor, pertopo_desc);
27
28#define PERTOPO_DEFINE_4(type_, name_, level_, ctor_) \
29 static typeof(type_) __pertopo_##name_ cc_unused; \
30 static struct pertopo_descriptor __pertopo_desc_##name_; \
31 static void __pertopo_ctor_##name_(void *inst, size_t node_id) { \
32 void (*const __typed_ctor)(typeof(type_) *, size_t) = (ctor_); \
33 if (__typed_ctor != NULL) \
34 __typed_ctor((typeof(type_) *) inst, node_id); \
35 if (node_id == (size_t) (global.topology.count[level_] - 1)) \
36 atomic_store(&__pertopo_desc_##name_.ready, true); \
37 } \
38 static LINKER_SECTION_OBJECT(struct pertopo_descriptor, pertopo_desc) \
39 __pertopo_desc_##name_ = { \
40 .name = #name_, \
41 .size = sizeof(typeof(type_)), \
42 .align = cc_alignof(typeof(type_)), \
43 .pertopo_ptrs = NULL, \
44 .level = level_, \
45 .constructor = __pertopo_ctor_##name_, \
46 .ready = false, \
47 }; \
48 static struct pertopo_descriptor *const __pertopo_desc_ref_##name_ \
49 cc_unused = &__pertopo_desc_##name_
50
51#define PERTOPO_DEFINE_3(type_, name_, level_) \
52 PERTOPO_DEFINE_4(type_, name_, level_, NULL)
53#define PERTOPO_DEFINE(...) PP_CALL(PERTOPO_DEFINE, __VA_ARGS__)
54
55#define PERTOPO_EXPORT_AS(sym_name, name) \
56 extern struct pertopo_descriptor __pertopo_desc_sym_##sym_name \
57 cc_alias(__pertopo_desc_##name) cc_used
58
59#define PERTOPO_EXPORT(name) PERTOPO_EXPORT_AS(name, name)
60
61#define PERTOPO_EXTERN_AS(type, name, sym_name) \
62 extern struct pertopo_descriptor __pertopo_desc_sym_##sym_name; \
63 static typeof(type) __pertopo_##name cc_unused; \
64 static struct pertopo_descriptor *const __pertopo_desc_ref_##name \
65 cc_unused = &__pertopo_desc_sym_##sym_name
66
67#define PERTOPO_EXTERN(type, name) PERTOPO_EXTERN_AS(type, name, name)
68
69static inline
70 cc_pure bool pertopo_desc_ready(const struct pertopo_descriptor *desc) {
71 return atomic_load(&desc->ready);
72}
73
74#define PERTOPO(name) &(__pertopo_##name)
75#define PERTOPO_READY(name) (atomic_load(&(__pertopo_desc_ref_##name)->ready))
76
77#define PERTOPO_PTR_FOR(name, node) \
78 ({ \
79 assume(pertopo_desc_ready(__pertopo_desc_ref_##name)); \
80 ((typeof(__pertopo_##name) *) (__pertopo_desc_ref_##name) \
81 ->pertopo_ptrs[node]); \
82 })
83
84#define PERTOPO_READ_FOR(name, node) \
85 (*((typeof(__pertopo_##name) *) PERTOPO_PTR_FOR(name, node)))
86
87#define PERTOPO_PTR(clr, name) \
88 PERTOPO_PTR_FOR(name, pertopo_node_local(&__pertopo_desc_##name, clr))
89#define PERTOPO_READ(clr, name) \
90 (*((typeof(__pertopo_##name) *) PERTOPO_PTR(clr, name)))
91
92#define PERTOPO_WRITE(clr, name, val) (PERTOPO_READ(clr, name) = (val))
93
94#define pertopo_for_each_internal_3(var, node_id, name) \
95 for (node_id = 0; \
96 node_id < global.topology.count[__pertopo_desc_##name.level]; \
97 node_id++) \
98 for (var = PERTOPO_PTR_FOR(name, node_id); var != NULL; var = NULL)
99
100#define pertopo_for_each_internal_2(var, name) \
101 for (size_t __pertopo_idx = 0; \
102 __pertopo_idx < global.topology.count[__pertopo_desc_##name.level]; \
103 __pertopo_idx++) \
104 for (var = PERTOPO_PTR_FOR(name, __pertopo_idx); var != NULL; \
105 var = NULL)
106
107#define pertopo_for_each(...) PP_CALL(pertopo_for_each_internal, __VA_ARGS__)
108
109size_t pertopo_node_local(struct pertopo_descriptor *desc,
110 enum topology_caller c);
111void pertopo_obj_init(void);
112