15
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
use core:: fmt;
17
17
use std:: collections:: HashSet ;
18
- use std:: fs;
19
18
use std:: io:: Read ;
19
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
20
20
use std:: sync:: mpsc:: { Receiver , RecvTimeoutError } ;
21
+ use std:: sync:: Arc ;
21
22
#[ cfg( test) ]
22
23
use std:: sync:: LazyLock ;
23
24
use std:: thread:: JoinHandle ;
24
25
use std:: time:: { Duration , Instant } ;
26
+ use std:: { fs, thread} ;
25
27
26
28
use rand:: { thread_rng, Rng } ;
27
29
use stacks:: burnchains:: { Burnchain , Txid } ;
@@ -40,6 +42,7 @@ use stacks::chainstate::stacks::db::StacksChainState;
40
42
use stacks:: chainstate:: stacks:: miner:: {
41
43
get_mining_spend_amount, signal_mining_blocked, signal_mining_ready,
42
44
} ;
45
+ use stacks:: chainstate:: stacks:: Error as ChainstateError ;
43
46
use stacks:: core:: mempool:: MemPoolDB ;
44
47
use stacks:: core:: STACKS_EPOCH_3_1_MARKER ;
45
48
use stacks:: monitoring:: increment_stx_blocks_mined_counter;
@@ -186,6 +189,101 @@ impl LastCommit {
186
189
}
187
190
}
188
191
192
+ pub type MinerThreadJoinHandle = JoinHandle < Result < ( ) , NakamotoNodeError > > ;
193
+
194
+ /// Miner thread join handle.
195
+ /// This can be a "bare" miner thread, or a "tenure-stop" miner thread which itself stops a "bare"
196
+ /// miner thread.
197
+ pub enum MinerStopHandle {
198
+ Miner ( MinerThreadJoinHandle , Arc < AtomicBool > ) ,
199
+ TenureStop ( MinerThreadJoinHandle , Arc < AtomicBool > ) ,
200
+ }
201
+
202
+ impl MinerStopHandle {
203
+ pub fn new_miner ( jh : MinerThreadJoinHandle , abort_flag : Arc < AtomicBool > ) -> Self {
204
+ Self :: Miner ( jh, abort_flag)
205
+ }
206
+
207
+ pub fn new_tenure_stop ( jh : MinerThreadJoinHandle , abort_flag : Arc < AtomicBool > ) -> Self {
208
+ Self :: TenureStop ( jh, abort_flag)
209
+ }
210
+
211
+ pub fn inner_thread ( & self ) -> & std:: thread:: Thread {
212
+ match self {
213
+ Self :: Miner ( jh, ..) => jh. thread ( ) ,
214
+ Self :: TenureStop ( jh, ..) => jh. thread ( ) ,
215
+ }
216
+ }
217
+
218
+ pub fn into_inner ( self ) -> MinerThreadJoinHandle {
219
+ match self {
220
+ Self :: Miner ( jh, ..) => jh,
221
+ Self :: TenureStop ( jh, ..) => jh,
222
+ }
223
+ }
224
+
225
+ pub fn is_tenure_stop ( & self ) -> bool {
226
+ match self {
227
+ Self :: TenureStop ( ..) => true ,
228
+ _ => false ,
229
+ }
230
+ }
231
+
232
+ pub fn is_miner ( & self ) -> bool {
233
+ match self {
234
+ Self :: Miner ( ..) => true ,
235
+ _ => false ,
236
+ }
237
+ }
238
+
239
+ pub fn set_abort_flag ( & self ) {
240
+ match self {
241
+ Self :: Miner ( _, abort_flag) => {
242
+ ( * abort_flag) . store ( true , Ordering :: SeqCst ) ;
243
+ }
244
+ Self :: TenureStop ( _, abort_flag) => {
245
+ ( * abort_flag) . store ( true , Ordering :: SeqCst ) ;
246
+ }
247
+ }
248
+ }
249
+
250
+ pub fn get_abort_flag ( & self ) -> Arc < AtomicBool > {
251
+ match self {
252
+ Self :: Miner ( _, abort_flag) => abort_flag. clone ( ) ,
253
+ Self :: TenureStop ( _, abort_flag) => abort_flag. clone ( ) ,
254
+ }
255
+ }
256
+
257
+ pub fn stop ( self , globals : & Globals ) -> Result < ( ) , NakamotoNodeError > {
258
+ let my_id = thread:: current ( ) . id ( ) ;
259
+ let prior_thread_id = self . inner_thread ( ) . id ( ) ;
260
+ debug ! (
261
+ "[Thread {:?}]: Stopping prior miner thread ID {:?}" ,
262
+ & my_id, & prior_thread_id
263
+ ) ;
264
+
265
+ self . set_abort_flag ( ) ;
266
+ globals. block_miner ( ) ;
267
+
268
+ let prior_miner = self . into_inner ( ) ;
269
+ let prior_miner_result = prior_miner. join ( ) . map_err ( |_| {
270
+ error ! ( "Miner: failed to join prior miner" ) ;
271
+ ChainstateError :: MinerAborted
272
+ } ) ?;
273
+ debug ! ( "Stopped prior miner thread ID {:?}" , & prior_thread_id) ;
274
+ if let Err ( e) = prior_miner_result {
275
+ // it's okay if the prior miner thread exited with an error.
276
+ // in many cases this is expected (i.e., a burnchain block occurred)
277
+ // if some error condition should be handled though, this is the place
278
+ // to do that handling.
279
+ debug ! ( "Prior mining thread exited with: {e:?}" ) ;
280
+ }
281
+
282
+ globals. unblock_miner ( ) ;
283
+ Ok ( ( ) )
284
+ }
285
+ }
286
+
189
287
/// Relayer thread
190
288
/// * accepts network results and stores blocks and microblocks
191
289
/// * forwards new blocks, microblocks, and transactions to the p2p thread
@@ -242,7 +340,7 @@ pub struct RelayerThread {
242
340
relayer : Relayer ,
243
341
244
342
/// handle to the subordinate miner thread
245
- miner_thread : Option < JoinHandle < Result < ( ) , NakamotoNodeError > > > ,
343
+ miner_thread : Option < MinerStopHandle > ,
246
344
/// miner thread's burn view
247
345
miner_thread_burn_view : Option < BlockSnapshot > ,
248
346
@@ -1053,6 +1151,7 @@ impl RelayerThread {
1053
1151
parent_tenure_start,
1054
1152
reason,
1055
1153
) ?;
1154
+ let miner_abort_flag = new_miner_state. get_abort_flag ( ) ;
1056
1155
1057
1156
debug ! ( "Relayer: starting new tenure thread" ) ;
1058
1157
@@ -1062,6 +1161,10 @@ impl RelayerThread {
1062
1161
. name ( format ! ( "miner.{parent_tenure_start}.{rand_id}" , ) )
1063
1162
. stack_size ( BLOCK_PROCESSOR_STACK_SIZE )
1064
1163
. spawn ( move || {
1164
+ debug ! (
1165
+ "New block miner thread ID is {:?}" ,
1166
+ std:: thread:: current( ) . id( )
1167
+ ) ;
1065
1168
Self :: fault_injection_stall_miner_thread_startup ( ) ;
1066
1169
if let Err ( e) = new_miner_state. run_miner ( prior_tenure_thread) {
1067
1170
info ! ( "Miner thread failed: {e:?}" ) ;
@@ -1078,7 +1181,10 @@ impl RelayerThread {
1078
1181
"Relayer: started tenure thread ID {:?}" ,
1079
1182
new_miner_handle. thread( ) . id( )
1080
1183
) ;
1081
- self . miner_thread . replace ( new_miner_handle) ;
1184
+ self . miner_thread . replace ( MinerStopHandle :: new_miner (
1185
+ new_miner_handle,
1186
+ miner_abort_flag,
1187
+ ) ) ;
1082
1188
self . miner_thread_burn_view . replace ( burn_tip) ;
1083
1189
Ok ( ( ) )
1084
1190
}
@@ -1092,18 +1198,23 @@ impl RelayerThread {
1092
1198
} ;
1093
1199
self . miner_thread_burn_view = None ;
1094
1200
1095
- let id = prior_tenure_thread. thread ( ) . id ( ) ;
1201
+ let id = prior_tenure_thread. inner_thread ( ) . id ( ) ;
1202
+ let abort_flag = prior_tenure_thread. get_abort_flag ( ) ;
1096
1203
let globals = self . globals . clone ( ) ;
1097
1204
1098
1205
let stop_handle = std:: thread:: Builder :: new ( )
1099
- . name ( format ! ( "tenure-stop-{}" , self . local_peer. data_url) )
1100
- . spawn ( move || BlockMinerThread :: stop_miner ( & globals, prior_tenure_thread) )
1206
+ . name ( format ! (
1207
+ "tenure-stop({:?})-{}" ,
1208
+ id, self . local_peer. data_url
1209
+ ) )
1210
+ . spawn ( move || prior_tenure_thread. stop ( & globals) )
1101
1211
. map_err ( |e| {
1102
1212
error ! ( "Relayer: Failed to spawn a stop-tenure thread: {e:?}" ) ;
1103
1213
NakamotoNodeError :: SpawnError ( e)
1104
1214
} ) ?;
1105
1215
1106
- self . miner_thread . replace ( stop_handle) ;
1216
+ self . miner_thread
1217
+ . replace ( MinerStopHandle :: new_tenure_stop ( stop_handle, abort_flag) ) ;
1107
1218
debug ! ( "Relayer: stopped tenure thread ID {id:?}" ) ;
1108
1219
Ok ( ( ) )
1109
1220
}
0 commit comments