1
1
use crate :: {
2
2
internal:: {
3
- epoch:: { EpochLock , ParkStatus , EPOCH_CLOCK } ,
4
- thread:: PinRw ,
3
+ epoch:: { EpochLock , ParkStatus , QuiesceEpoch , EPOCH_CLOCK } ,
4
+ thread:: { Logs , PinRw } ,
5
+ write_log:: { WriteEntry , WriteLog } ,
5
6
} ,
6
7
stats,
7
8
} ;
8
- use core:: ptr;
9
- use swym_htm:: HardwareTx ;
9
+ use core:: {
10
+ mem,
11
+ ptr:: { self , NonNull } ,
12
+ sync:: atomic:: { self , Ordering :: Release } ,
13
+ } ;
14
+ use swym_htm:: { BoundedHtxErr , HardwareTx } ;
15
+
16
+ const MAX_HTX_RETRIES : u8 = 3 ;
17
+
18
+ impl < ' tcell > Logs < ' tcell > {
19
+ #[ inline]
20
+ pub unsafe fn remove_writes_from_reads ( & mut self ) {
21
+ #[ allow( unused_mut) ]
22
+ let mut count = 0 ;
23
+
24
+ let write_log = & mut self . write_log ;
25
+ self . read_log . filter_in_place ( |src| {
26
+ if write_log. find ( src) . is_none ( ) {
27
+ true
28
+ } else {
29
+ count += 1 ;
30
+ false
31
+ }
32
+ } ) ;
33
+ stats:: write_after_logged_read ( count)
34
+ }
35
+ }
36
+
37
+ impl < ' tcell > dyn WriteEntry + ' tcell {
38
+ #[ inline]
39
+ fn try_lock_htm ( & self , htx : & HardwareTx , pin_epoch : QuiesceEpoch ) -> ParkStatus {
40
+ match self . tcell ( ) {
41
+ Some ( tcell) => tcell. current_epoch . try_lock_htm ( htx, pin_epoch) ,
42
+ None => ParkStatus :: NoParked ,
43
+ }
44
+ }
45
+
46
+ #[ inline]
47
+ unsafe fn perform_write ( & self ) {
48
+ match self . tcell ( ) {
49
+ Some ( tcell) => {
50
+ let size = mem:: size_of_val ( self ) ;
51
+ assume ! (
52
+ size % mem:: size_of:: <usize >( ) == 0 ,
53
+ "buggy alignment on `WriteEntry`"
54
+ ) ;
55
+ let len = size / mem:: size_of :: < usize > ( ) - 1 ;
56
+ assume ! (
57
+ len > 0 ,
58
+ "`WriteEntry` performing a write of size 0 unexpectedly"
59
+ ) ;
60
+ self . pending ( ) . as_ptr ( ) . copy_to_nonoverlapping (
61
+ NonNull :: from ( * tcell) . cast :: < usize > ( ) . as_ptr ( ) . sub ( len) ,
62
+ len,
63
+ ) ;
64
+ }
65
+ None => { }
66
+ }
67
+ }
68
+ }
69
+
70
+ impl < ' tcell > WriteLog < ' tcell > {
71
+ #[ inline]
72
+ unsafe fn publish ( & self , sync_epoch : QuiesceEpoch ) {
73
+ self . epoch_locks ( )
74
+ . for_each ( |epoch_lock| epoch_lock. unlock_publish ( sync_epoch) )
75
+ }
10
76
11
- const MAX_HTX_RETRIES : usize = 3 ;
77
+ #[ inline]
78
+ fn write_and_lock_htm ( & self , htx : & HardwareTx , pin_epoch : QuiesceEpoch ) -> ParkStatus {
79
+ let mut status = ParkStatus :: NoParked ;
80
+ for entry in self . write_entries ( ) {
81
+ unsafe { entry. perform_write ( ) } ;
82
+ status = status. merge ( entry. try_lock_htm ( htx, pin_epoch) ) ;
83
+ }
84
+ status
85
+ }
86
+
87
+ #[ inline]
88
+ unsafe fn perform_writes ( & self ) {
89
+ atomic:: fence ( Release ) ;
90
+ for entry in self . write_entries ( ) {
91
+ entry. perform_write ( ) ;
92
+ }
93
+ }
94
+ }
12
95
13
96
impl < ' tx , ' tcell > PinRw < ' tx , ' tcell > {
14
97
/// The commit algorithm, called after user code has finished running without returning an
@@ -42,42 +125,32 @@ impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
42
125
}
43
126
44
127
#[ inline]
45
- fn commit_slow ( self ) -> bool {
128
+ fn start_htx ( & self , retry_count : & mut u8 ) -> Result < HardwareTx , BoundedHtxErr > {
46
129
if swym_htm:: htm_supported ( ) && self . logs ( ) . write_log . word_len ( ) >= 9 {
47
- enum HtxRetry {
48
- SoftwareFallback ,
49
- FullRetry ,
130
+ HardwareTx :: bounded ( retry_count, MAX_HTX_RETRIES )
131
+ } else {
132
+ Err ( BoundedHtxErr :: SoftwareFallback )
133
+ }
134
+ }
135
+
136
+ #[ inline]
137
+ fn commit_slow ( self ) -> bool {
138
+ let mut retry_count = 0 ;
139
+ match self . start_htx ( & mut retry_count) {
140
+ Ok ( htx) => {
141
+ let success = self . commit_hard ( htx) ;
142
+ stats:: htm_conflicts ( retry_count as _ ) ;
143
+ success
50
144
}
51
- let mut retry_count = 0 ;
52
- let htx = unsafe {
53
- let retry_count = & mut retry_count;
54
- HardwareTx :: new ( move |code| {
55
- if code. is_explicit_abort ( ) || code. is_conflict ( ) && !code. is_retry ( ) {
56
- Err ( HtxRetry :: FullRetry )
57
- } else if code. is_retry ( ) && * retry_count < MAX_HTX_RETRIES {
58
- * retry_count += 1 ;
59
- Ok ( ( ) )
60
- } else {
61
- Err ( HtxRetry :: SoftwareFallback )
62
- }
63
- } )
64
- } ;
65
- match htx {
66
- Ok ( htx) => {
67
- let success = self . commit_hard ( htx) ;
68
- stats:: htm_conflicts ( retry_count) ;
69
- return success;
70
- }
71
- Err ( HtxRetry :: SoftwareFallback ) => {
72
- stats:: htm_conflicts ( retry_count) ;
73
- }
74
- Err ( HtxRetry :: FullRetry ) => {
75
- stats:: htm_conflicts ( retry_count) ;
76
- return false ;
77
- }
145
+ Err ( BoundedHtxErr :: SoftwareFallback ) => {
146
+ stats:: htm_conflicts ( retry_count as _ ) ;
147
+ self . commit_soft ( )
148
+ }
149
+ Err ( BoundedHtxErr :: AbortOrConflict ) => {
150
+ stats:: htm_conflicts ( retry_count as _ ) ;
151
+ false
78
152
}
79
153
}
80
- self . commit_soft ( )
81
154
}
82
155
83
156
#[ inline( never) ]
@@ -91,11 +164,7 @@ impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
91
164
drop ( htx) ;
92
165
93
166
let sync_epoch = EPOCH_CLOCK . fetch_and_tick ( ) ;
94
-
95
- // publish
96
- logs. write_log
97
- . epoch_locks ( )
98
- . for_each ( |epoch_lock| epoch_lock. unlock_publish ( sync_epoch. next ( ) ) ) ;
167
+ logs. write_log . publish ( sync_epoch. next ( ) ) ;
99
168
100
169
logs. read_log . clear ( ) ;
101
170
logs. write_log . clear_no_drop ( ) ;
@@ -178,9 +247,8 @@ impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
178
247
) ;
179
248
180
249
// unlocks everything in the write lock and sets the TCell epochs to sync_epoch.next()
181
- logs. write_log
182
- . epoch_locks ( )
183
- . for_each ( |epoch_lock| epoch_lock. unlock_publish ( sync_epoch. next ( ) ) ) ;
250
+ logs. write_log . publish ( sync_epoch. next ( ) ) ;
251
+
184
252
logs. read_log . clear ( ) ;
185
253
logs. write_log . clear_no_drop ( ) ;
186
254
if unlikely ! ( park_status == ParkStatus :: HasParked ) {
0 commit comments