Skip to content

Commit e1e2f49

Browse files
committed
Prepare for an uninitialized R thread
1 parent dcb1943 commit e1e2f49

File tree

1 file changed

+19
-3
lines changed

1 file changed

+19
-3
lines changed

crates/ark/src/r_task.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
//
66
//
77

8-
use std::sync::{Arc, Mutex};
8+
use std::{
9+
sync::{Arc, Mutex},
10+
time::Duration,
11+
};
912

1013
use libR_sys::R_interrupts_suspended;
1114

@@ -19,7 +22,7 @@ pub extern "C" fn r_polled_events_disabled() {}
1922
use crossbeam::channel::bounded;
2023
use log::info;
2124

22-
use crate::interface::R_MAIN;
25+
use crate::interface::{RMain, R_MAIN};
2326

2427
type SharedOption<T> = Arc<Mutex<Option<T>>>;
2528

@@ -29,10 +32,11 @@ where
2932
F: 'env + Send,
3033
T: 'env + Send,
3134
{
35+
let main = acquire_r_main();
36+
3237
// Recursive case: If we're on ark-r-main already, just run the
3338
// task and return. This allows `r_task(|| { r_task(|| {}) })`
3439
// to run without deadlocking.
35-
let main = unsafe { R_MAIN.as_mut().unwrap() }; // FIXME: Check init timings
3640
let thread_id = std::thread::current().id();
3741
if main.thread_id == thread_id {
3842
return f();
@@ -103,6 +107,18 @@ impl RTaskMain {
103107
}
104108
}
105109

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+
106122
// TODO: Should probably run in a toplevel-exec. Tasks also need a timeout.
107123
// This could be implemented with R interrupts but would require to
108124
// unsafely jump over the Rust stack, unless we wrapped all R API functions

0 commit comments

Comments
 (0)