]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/per_cpu_data.cpp
41f41e9f7e170dea30a98301934244778793fb7d
[l4.git] / kernel / fiasco / src / kern / per_cpu_data.cpp
1 INTERFACE:
2
3 #include "static_init.h"
4
5 #define DEFINE_PER_CPU_P(p) __attribute__((section(".per_cpu.data"),init_priority(0xfffe - p)))
6 #define DEFINE_PER_CPU      DEFINE_PER_CPU_P(9)
7
8 class Mapped_allocator;
9
10 class Per_cpu_data
11 {
12 public:
13   static void init_ctors(Mapped_allocator *a);
14   static void run_ctors(unsigned cpu);
15   static bool valid(unsigned cpu);
16 };
17
18 template< typename T >
19 class Per_cpu : private Per_cpu_data
20 {
21 public:
22   T const &cpu(unsigned) const;
23   T &cpu(unsigned);
24
25   Per_cpu();
26   explicit Per_cpu(bool);
27
28 };
29
30
31 //---------------------------------------------------------------------------
32 INTERFACE [!mp]:
33
34 EXTENSION
35 class Per_cpu
36 {
37 private:
38   T _d;
39 };
40
41
42 //---------------------------------------------------------------------------
43 IMPLEMENTATION [!mp]:
44
45 IMPLEMENT inline
46 bool
47 Per_cpu_data::valid(unsigned cpu)
48 {
49 #if defined NDEBUG
50   (void)cpu;
51   return 1;
52 #else
53   return cpu == 0;
54 #endif
55 }
56
57 IMPLEMENT inline
58 template< typename T >
59 T const &Per_cpu<T>::cpu(unsigned) const { return _d; }
60
61 IMPLEMENT inline
62 template< typename T >
63 T &Per_cpu<T>::cpu(unsigned) { return _d; }
64
65 IMPLEMENT
66 template< typename T >
67 Per_cpu<T>::Per_cpu()
68 {}
69
70 IMPLEMENT
71 template< typename T >
72 Per_cpu<T>::Per_cpu(bool) : _d(0)
73 {}
74
75 IMPLEMENT
76 void
77 Per_cpu_data::init_ctors(Mapped_allocator *)
78 {
79   typedef void (*ctor)(void);
80   extern ctor __PER_CPU_CTORS_LIST__[];
81   extern ctor __PER_CPU_CTORS_END__[];
82   for (unsigned i = __PER_CPU_CTORS_LIST__ - __PER_CPU_CTORS_END__; i > 0; --i)
83     {
84       //printf("Per_cpu: init ctor %u (%p)\n", i-1, &__PER_CPU_CTORS_END__[i-1]);
85       __PER_CPU_CTORS_END__[i-1]();
86     }
87 }
88
89 IMPLEMENT inline
90 void
91 Per_cpu_data::run_ctors(unsigned)
92 {}
93
94
95 //---------------------------------------------------------------------------
96 INTERFACE [mp]:
97
98 #include <cstddef>
99 #include "config.h"
100
101 EXTENSION
102 class Per_cpu
103 {
104 private:
105   T _d; // __attribute__((aligned(__alignof__(T))));
106 };
107
108 EXTENSION
109 class Per_cpu_data
110 {
111 private:
112   struct Ctor
113   {
114     void (*func)(void *, unsigned);
115     void *base;
116   };
117
118   class Ctor_vector
119   {
120   public:
121     Ctor_vector() : _len(0), _capacity(10), _v(0) {}
122     void push_back(void (*func)(void*,unsigned), void *base, Mapped_allocator *a);
123     unsigned len() const { return _len; }
124     Ctor const &operator [] (unsigned idx) const { return _v[idx]; }
125
126   private:
127     unsigned _len;
128     unsigned _capacity;
129     Ctor *_v;
130   };
131 protected:
132   static long _offsets[Config::Max_num_cpus] asm ("PER_CPU_OFFSETS");
133   static Ctor_vector ctors;
134   static Mapped_allocator *alloc;
135 };
136
137 //#include <cstdio>
138 //---------------------------------------------------------------------------
139 IMPLEMENTATION [mp]:
140
141 #include "mapped_alloc.h"
142 #include <cstring>
143
144 long Per_cpu_data::_offsets[Config::Max_num_cpus];
145 Per_cpu_data::Ctor_vector Per_cpu_data::ctors INIT_PRIORITY(EARLY_INIT_PRIO);
146 Mapped_allocator *Per_cpu_data::alloc;
147
148 IMPLEMENT
149 void
150 Per_cpu_data::Ctor_vector::push_back(void (*func)(void*,unsigned),
151                                      void *base, Mapped_allocator *a)
152 {
153   if (!_v)
154     _v = (Ctor*)a->unaligned_alloc(1 << _capacity);
155
156   if (_len >= ((1 << _capacity) / sizeof(Ctor)))
157     {
158       void *b = a->unaligned_alloc(1 << (_capacity+1));
159       memcpy(b, _v, 1 << _capacity);
160       a->unaligned_free(1 << _capacity, _v);
161       _v = (Ctor*)b;
162       ++_capacity;
163     }
164
165   Ctor &c = _v[_len++];
166   c.func = func;
167   c.base = base;
168 }
169
170 // the third argument is just there to not have the same type as the normal
171 // new operator used in standard environments which would clash with these
172 // (this file is implicitly in unit tests)
173 inline void *operator new (size_t, void *p, bool) { return p; }
174 inline void *operator new [] (size_t, void *p, bool) { return p; }
175
176 IMPLEMENT inline
177 bool
178 Per_cpu_data::valid(unsigned cpu)
179 { return cpu < Config::Max_num_cpus && _offsets[cpu] != -1; }
180
181 IMPLEMENT inline template< typename T >
182 T const &Per_cpu<T>::cpu(unsigned cpu) const
183 { return *reinterpret_cast<T const *>((char  const *)&_d + _offsets[cpu]); }
184
185 IMPLEMENT inline template< typename T >
186 T &Per_cpu<T>::cpu(unsigned cpu)
187 { return *reinterpret_cast<T*>((char *)&_d + _offsets[cpu]); }
188
189 IMPLEMENT
190 template< typename T >
191 Per_cpu<T>::Per_cpu()
192 {
193   //printf("  Per_cpu<T>() [this=%p])\n", this);
194   ctors.push_back(&ctor_wo_arg, this, alloc);
195 }
196
197 IMPLEMENT
198 template< typename T >
199 Per_cpu<T>::Per_cpu(bool) : _d(0)
200 {
201   //printf("  Per_cpu<T>(bool) [this=%p])\n", this);
202   ctors.push_back(&ctor_w_arg, this, alloc);
203 }
204
205 PRIVATE static
206 template< typename T >
207 void Per_cpu<T>::ctor_wo_arg(void *obj, unsigned cpu)
208 {
209   //printf("Per_cpu<T>::ctor_wo_arg(obj=%p, cpu=%u -> %p)\n", obj, cpu, &(reinterpret_cast<Per_cpu<T>*>(obj)->cpu(cpu)));
210   new (&reinterpret_cast<Per_cpu<T>*>(obj)->cpu(cpu), true) T();
211 }
212
213 PRIVATE static
214 template< typename T >
215 void Per_cpu<T>::ctor_w_arg(void *obj, unsigned cpu)
216 {
217   //printf("Per_cpu<T>::ctor_w_arg(obj=%p, cpu=%u -> %p)\n", obj, cpu, &reinterpret_cast<Per_cpu<T>*>(obj)->cpu(cpu));
218   new (&reinterpret_cast<Per_cpu<T>*>(obj)->cpu(cpu), true) T(cpu);
219 }
220
221 IMPLEMENT
222 void
223 Per_cpu_data::init_ctors(Mapped_allocator *a)
224 {
225   typedef void (*ctor)(void);
226   extern ctor __PER_CPU_CTORS_LIST__[];
227   extern ctor __PER_CPU_CTORS_END__[];
228   alloc = a;
229   for (unsigned i = __PER_CPU_CTORS_LIST__ - __PER_CPU_CTORS_END__; i > 0; --i)
230     {
231       //printf("Per_cpu: init ctor %u (%p)\n", i-1, &__PER_CPU_CTORS_END__[i-1]);
232       __PER_CPU_CTORS_END__[i-1]();
233     }
234
235   for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
236     _offsets[i] = -1;
237 }
238
239 IMPLEMENT inline
240 void
241 Per_cpu_data::run_ctors(unsigned cpu)
242 {
243   if (cpu == 0)
244     return;
245
246   unsigned c = ctors.len();
247   for (unsigned i = 0; i < c; ++i)
248     ctors[i].func(ctors[i].base, cpu);
249 }
250