@@ -36,20 +36,64 @@ pub struct FixedCpuLocal {
36
36
pub size : usize ,
37
37
pub align : usize ,
38
38
}
39
+
39
40
// NOTE: These fields must be kept in sync with `cpu_local::FixedCpuLocal`.
40
- impl FixedCpuLocal {
41
- pub const CPU_ID : Self = Self { offset : 8 , size : 4 , align : 4 } ;
42
- pub const PREEMPTION_COUNT : Self = Self { offset : 12 , size : 1 , align : 1 } ;
43
- pub const TASK_SWITCH_PREEMPTION_GUARD : Self = Self { offset : 16 , size : 8 , align : 4 } ;
44
- pub const DROP_AFTER_TASK_SWITCH : Self = Self { offset : 24 , size : 8 , align : 8 } ;
41
+ pub enum CpuLocalField {
42
+ CpuId ,
43
+ PreemptionCount ,
44
+ TaskSwitchPreemptionGuard ,
45
+ DropAfterTaskSwitch ,
46
+ }
47
+
48
+ impl CpuLocalField {
49
+ pub const fn offset ( & self ) -> usize {
50
+ match self {
51
+ Self :: CpuId => 8 ,
52
+ Self :: PreemptionCount => 12 ,
53
+ Self :: TaskSwitchPreemptionGuard => 16 ,
54
+ Self :: DropAfterTaskSwitch => 24 ,
55
+ }
56
+ }
57
+
58
+ // TODO: Do we even need to know the size and alignment?
59
+
60
+ // pub const fn size(&self) -> usize {
61
+ // match self {
62
+ // Self::CpuId => 4,
63
+ // Self::PreemptionCount => 1,
64
+ // Self::TaskSwitchPreemptionGuard => 8,
65
+ // Self::DropAfterTaskSwitch => 8,
66
+ // }
67
+ // }
68
+
69
+ // pub const fn align(&self) -> usize {
70
+ // match self {
71
+ // Self::CpuId => 4,
72
+ // Self::PreemptionCount => 1,
73
+ // Self::TaskSwitchPreemptionGuard => 4,
74
+ // Self::DropAfterTaskSwitch => 8,
75
+ // }
76
+ // }
77
+ }
78
+
79
+ // TODO: Could come up with a more imaginative name.
80
+ pub unsafe trait Field : Sized {
81
+ const FIELD : CpuLocalField ;
82
+
83
+ // const SIZE_CHECK: () = assert!(Self::FIELD.size() == size_of::<Self>());
84
+ // const ALIGN_CHECK: () = assert!(Self::FIELD.align() == align_of::<Self>());
45
85
}
46
86
47
87
/// A reference to a CPU-local variable.
48
88
///
49
89
/// Note that this struct doesn't contain an instance of the type `T`,
50
90
/// and dropping it has no effect.
51
- pub struct CpuLocal < const OFFSET : usize , T > ( PhantomData < * mut T > ) ;
52
- impl < const OFFSET : usize , T > CpuLocal < OFFSET , T > {
91
+ pub struct CpuLocal < T : Field > ( PhantomData < * mut T > ) ;
92
+
93
+ impl < T > CpuLocal < T >
94
+ where
95
+ T : Field ,
96
+ {
53
97
/// Creates a new reference to a predefined CPU-local variable.
54
98
///
55
99
/// # Arguments
@@ -63,12 +107,8 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
63
107
///
64
108
/// Thus, the caller must guarantee that the type `T` is correct for the
65
109
/// given `FixedCpuLocal`.
66
- pub const unsafe fn new_fixed (
67
- fixed : FixedCpuLocal ,
68
- ) -> Self {
69
- assert ! ( OFFSET == fixed. offset) ;
70
- assert ! ( size_of:: <T >( ) == fixed. size) ;
71
- assert ! ( align_of:: <T >( ) == fixed. align) ;
110
+ pub const unsafe fn new_fixed ( ) -> Self {
111
+ // FIXME: Should this still be unsafe?
72
112
Self ( PhantomData )
73
113
}
74
114
@@ -97,7 +137,7 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
97
137
where
98
138
F : FnOnce ( & T ) -> R ,
99
139
{
100
- let ptr_to_cpu_local = self . self_ptr ( ) + OFFSET ;
140
+ let ptr_to_cpu_local = self . self_ptr ( ) + T :: FIELD . offset ( ) ;
101
141
let local_ref = unsafe { & * ( ptr_to_cpu_local as * const T ) } ;
102
142
func ( local_ref)
103
143
}
@@ -111,7 +151,7 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
111
151
F : FnOnce ( & mut T ) -> R ,
112
152
{
113
153
let _held_interrupts = irq_safety:: hold_interrupts ( ) ;
114
- let ptr_to_cpu_local = self . self_ptr ( ) + OFFSET ;
154
+ let ptr_to_cpu_local = self . self_ptr ( ) + T :: FIELD . offset ( ) ;
115
155
let local_ref_mut = unsafe { & mut * ( ptr_to_cpu_local as * mut T ) } ;
116
156
func ( local_ref_mut)
117
157
}
@@ -134,7 +174,10 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
134
174
}
135
175
}
136
176
137
- impl < const OFFSET : usize , T : Copy > CpuLocal < OFFSET , T > {
177
+ impl < T > CpuLocal < T >
178
+ where
179
+ T : Copy + Field ,
180
+ {
138
181
/// Returns a copy of this `CpuLocal`'s inner value of type `T`.
139
182
///
140
183
/// This is a convenience function only available for types where `T: Copy`.
@@ -209,18 +252,23 @@ pub fn init<P>(
209
252
210
253
// TODO Remove, temp tests
211
254
if true {
212
- let test_value = CpuLocal :: < 32 , u64 > ( PhantomData ) ;
213
- test_value. with ( |tv| log:: warn!( "Got test_value: {:#X}" , * tv) ) ;
214
- log:: warn!( "Setting test_value to 0x12345678..." ) ;
215
- test_value. with_mut ( |tv| { * tv = 0x12345678 ; } ) ;
216
- test_value. with ( |tv| log:: warn!( "Got test_value: {:#X}" , * tv) ) ;
217
-
218
- let test_string = CpuLocal :: < 40 , alloc:: string:: String > ( PhantomData ) ;
219
- test_string. with ( |s| log:: warn!( "Got test_string: {:?}" , s) ) ;
220
- let new_str = ", world!" ;
221
- log:: warn!( "Appending {:?} to test_string..." , new_str) ;
222
- test_string. with_mut ( |s| s. push_str ( new_str) ) ;
223
- test_string. with ( |s| log:: warn!( "Got test_string: {:?}" , s) ) ;
255
+ // NOTE: The fact that this previously compiled in `cpu_local` is
256
+ // indicative of an unsafe API, as the offsets (and types) are
257
+ // completely arbitrary. There's nothing stopping us from trying to
258
+ // access CpuLocal::<16, String> which would be undefined behaviour.
259
+
260
+ // let test_value = CpuLocal::<32, u64>(PhantomData);
261
+ // test_value.with(|tv| log::warn!("Got test_value: {:#X}", *tv));
262
+ // log::warn!("Setting test_value to 0x12345678...");
263
+ // test_value.with_mut(|tv| { *tv = 0x12345678; });
264
+ // test_value.with(|tv| log::warn!("Got test_value: {:#X}", *tv));
265
+
266
+ // let test_string = CpuLocal::<40, alloc::string::String>(PhantomData);
267
+ // test_string.with(|s| log::warn!("Got test_string: {:?}", s));
268
+ // let new_str = ", world!";
269
+ // log::warn!("Appending {:?} to test_string...", new_str);
270
+ // test_string.with_mut(|s| s.push_str(new_str));
271
+ // test_string.with(|s| log::warn!("Got test_string: {:?}", s));
224
272
}
225
273
Ok ( ( ) )
226
274
}
0 commit comments