5
5
//
6
6
//
7
7
8
- use std:: sync:: { Arc , Mutex } ;
8
+ use std:: {
9
+ sync:: { Arc , Mutex } ,
10
+ time:: Duration ,
11
+ } ;
9
12
10
13
use libR_sys:: R_interrupts_suspended ;
11
14
@@ -19,7 +22,7 @@ pub extern "C" fn r_polled_events_disabled() {}
19
22
use crossbeam:: channel:: bounded;
20
23
use log:: info;
21
24
22
- use crate :: interface:: R_MAIN ;
25
+ use crate :: interface:: { RMain , R_MAIN } ;
23
26
24
27
type SharedOption < T > = Arc < Mutex < Option < T > > > ;
25
28
@@ -29,10 +32,11 @@ where
29
32
F : ' env + Send ,
30
33
T : ' env + Send ,
31
34
{
35
+ let main = acquire_r_main ( ) ;
36
+
32
37
// Recursive case: If we're on ark-r-main already, just run the
33
38
// task and return. This allows `r_task(|| { r_task(|| {}) })`
34
39
// to run without deadlocking.
35
- let main = unsafe { R_MAIN . as_mut ( ) . unwrap ( ) } ; // FIXME: Check init timings
36
40
let thread_id = std:: thread:: current ( ) . id ( ) ;
37
41
if main. thread_id == thread_id {
38
42
return f ( ) ;
@@ -103,6 +107,18 @@ impl RTaskMain {
103
107
}
104
108
}
105
109
110
+ // Be defensive for the case an auxiliary thread runs a task before R is initialized
111
+ fn acquire_r_main ( ) -> & ' static mut RMain {
112
+ unsafe {
113
+ loop {
114
+ if !R_MAIN . is_none ( ) {
115
+ return R_MAIN . as_mut ( ) . unwrap ( ) ;
116
+ }
117
+ std:: thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
118
+ }
119
+ }
120
+ }
121
+
106
122
// TODO: Should probably run in a toplevel-exec. Tasks also need a timeout.
107
123
// This could be implemented with R interrupts but would require to
108
124
// unsafely jump over the Rust stack, unless we wrapped all R API functions
0 commit comments