1
- use crate :: RUNTIME ;
2
1
use crate :: argconv:: * ;
3
2
use crate :: cass_error:: CassError ;
4
3
use crate :: cass_error:: CassErrorMessage ;
@@ -68,6 +67,9 @@ enum FutureKind {
68
67
}
69
68
70
69
struct ResolvableFuture {
70
+ /// Runtime used to spawn and execute the future.
71
+ runtime : Arc < tokio:: runtime:: Runtime > ,
72
+
71
73
/// Mutable state of the future that requires synchronized exclusive access
72
74
/// in order to ensure thread safety of the future execution.
73
75
state : Mutex < CassFutureState > ,
@@ -111,12 +113,14 @@ impl CassFuture {
111
113
}
112
114
113
115
pub ( crate ) fn make_raw (
116
+ runtime : Arc < tokio:: runtime:: Runtime > ,
114
117
fut : impl Future < Output = CassFutureResult > + Send + ' static ,
115
118
#[ cfg( cpp_integration_testing) ] recording_listener : Option <
116
119
Arc < crate :: integration_testing:: RecordingHistoryListener > ,
117
120
> ,
118
121
) -> CassOwnedSharedPtr < CassFuture , CMut > {
119
122
Self :: new_from_future (
123
+ runtime,
120
124
fut,
121
125
#[ cfg( cpp_integration_testing) ]
122
126
recording_listener,
@@ -125,6 +129,7 @@ impl CassFuture {
125
129
}
126
130
127
131
pub ( crate ) fn new_from_future (
132
+ runtime : Arc < tokio:: runtime:: Runtime > ,
128
133
fut : impl Future < Output = CassFutureResult > + Send + ' static ,
129
134
#[ cfg( cpp_integration_testing) ] recording_listener : Option <
130
135
Arc < crate :: integration_testing:: RecordingHistoryListener > ,
@@ -133,6 +138,7 @@ impl CassFuture {
133
138
let cass_fut = Arc :: new ( CassFuture {
134
139
err_string : OnceLock :: new ( ) ,
135
140
kind : FutureKind :: Resolvable ( ResolvableFuture {
141
+ runtime : Arc :: clone ( & runtime) ,
136
142
state : Mutex :: new ( Default :: default ( ) ) ,
137
143
result : OnceLock :: new ( ) ,
138
144
wait_for_value : Condvar :: new ( ) ,
@@ -141,7 +147,7 @@ impl CassFuture {
141
147
} ) ,
142
148
} ) ;
143
149
let cass_fut_clone = Arc :: clone ( & cass_fut) ;
144
- let join_handle = RUNTIME . spawn ( async move {
150
+ let join_handle = runtime . spawn ( async move {
145
151
let resolvable_fut = match cass_fut_clone. kind {
146
152
FutureKind :: Resolvable ( ref resolvable) => resolvable,
147
153
_ => unreachable ! ( "CassFuture has been created as Resolvable" ) ,
@@ -223,7 +229,7 @@ impl CassFuture {
223
229
// the future.
224
230
mem:: drop ( guard) ;
225
231
// unwrap: JoinError appears only when future either panic'ed or canceled.
226
- RUNTIME . block_on ( handle) . unwrap ( ) ;
232
+ resolvable_fut . runtime . block_on ( handle) . unwrap ( ) ;
227
233
228
234
// Once we are here, the future is resolved.
229
235
// The result is guaranteed to be set.
@@ -313,7 +319,7 @@ impl CassFuture {
313
319
future:: Either :: Right ( ( _, handle) ) => Err ( JoinHandleTimeout ( handle) ) ,
314
320
}
315
321
} ;
316
- match RUNTIME . block_on ( timed) {
322
+ match resolvable_fut . runtime . block_on ( timed) {
317
323
Err ( JoinHandleTimeout ( returned_handle) ) => {
318
324
// We timed out. so we can't finish waiting for the future.
319
325
// The problem is that if current thread executor is used,
@@ -638,6 +644,15 @@ mod tests {
638
644
time:: Duration ,
639
645
} ;
640
646
647
+ fn runtime_for_test ( ) -> Arc < tokio:: runtime:: Runtime > {
648
+ Arc :: new (
649
+ tokio:: runtime:: Builder :: new_current_thread ( )
650
+ . enable_all ( )
651
+ . build ( )
652
+ . unwrap ( ) ,
653
+ )
654
+ }
655
+
641
656
// This is not a particularly smart test, but if some thread is granted access the value
642
657
// before it is truly computed, then weird things should happen, even a segfault.
643
658
// In the incorrect implementation that inspired this test to be written, this test
@@ -646,11 +661,13 @@ mod tests {
646
661
#[ ntest:: timeout( 100 ) ]
647
662
fn cass_future_thread_safety ( ) {
648
663
const ERROR_MSG : & str = "NOBODY EXPECTED SPANISH INQUISITION" ;
664
+ let runtime = runtime_for_test ( ) ;
649
665
let fut = async {
650
666
tokio:: time:: sleep ( Duration :: from_millis ( 10 ) ) . await ;
651
667
Err ( ( CassError :: CASS_OK , ERROR_MSG . into ( ) ) )
652
668
} ;
653
669
let cass_fut = CassFuture :: make_raw (
670
+ runtime,
654
671
fut,
655
672
#[ cfg( cpp_integration_testing) ]
656
673
None ,
@@ -685,11 +702,13 @@ mod tests {
685
702
fn cass_future_resolves_after_timeout ( ) {
686
703
const ERROR_MSG : & str = "NOBODY EXPECTED SPANISH INQUISITION" ;
687
704
const HUNDRED_MILLIS_IN_MICROS : u64 = 100 * 1000 ;
705
+ let runtime = runtime_for_test ( ) ;
688
706
let fut = async move {
689
707
tokio:: time:: sleep ( Duration :: from_micros ( HUNDRED_MILLIS_IN_MICROS ) ) . await ;
690
708
Err ( ( CassError :: CASS_OK , ERROR_MSG . into ( ) ) )
691
709
} ;
692
710
let cass_fut = CassFuture :: make_raw (
711
+ runtime,
693
712
fut,
694
713
#[ cfg( cpp_integration_testing) ]
695
714
None ,
@@ -725,6 +744,8 @@ mod tests {
725
744
const ERROR_MSG : & str = "NOBODY EXPECTED SPANISH INQUISITION" ;
726
745
const HUNDRED_MILLIS_IN_MICROS : u64 = 100 * 1000 ;
727
746
747
+ let runtime = runtime_for_test ( ) ;
748
+
728
749
let create_future_and_flag = || {
729
750
unsafe extern "C" fn mark_flag_cb (
730
751
_fut : CassBorrowedSharedPtr < CassFuture , CMut > ,
@@ -741,6 +762,7 @@ mod tests {
741
762
Err ( ( CassError :: CASS_OK , ERROR_MSG . into ( ) ) )
742
763
} ;
743
764
let cass_fut = CassFuture :: make_raw (
765
+ Arc :: clone ( & runtime) ,
744
766
fut,
745
767
#[ cfg( cpp_integration_testing) ]
746
768
None ,
@@ -816,7 +838,7 @@ mod tests {
816
838
{
817
839
let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
818
840
819
- RUNTIME . block_on ( async {
841
+ runtime . block_on ( async {
820
842
tokio:: time:: sleep ( Duration :: from_micros ( HUNDRED_MILLIS_IN_MICROS + 10 * 1000 ) )
821
843
. await
822
844
} ) ;
0 commit comments