Skip to content

Commit

Permalink
Remove RMain::initializing flag
Browse files Browse the repository at this point in the history
And use `RMain::is_r_initialized()` instead
  • Loading branch information
lionel- committed Sep 27, 2024
1 parent fafbd8c commit 1f5753d
Showing 1 changed file with 48 additions and 47 deletions.
95 changes: 48 additions & 47 deletions crates/ark/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ static R_INIT: once_cell::sync::OnceCell<()> = once_cell::sync::OnceCell::new();
static mut R_MAIN: Option<RMain> = None;

pub struct RMain {
initializing: bool,
kernel_init_tx: Bus<KernelInfo>,

/// Whether we are running in Console, Notebook, or Background mode.
Expand Down Expand Up @@ -406,17 +405,15 @@ impl RMain {

// Set up the global error handler (after support function initialization)
errors::initialize();
}

// Now that R has started (emitting any startup messages), and now that we have set
// up all hooks and handlers, officially finish the R initialization process to
// unblock the kernel-info request and also allow the LSP to start.
RMain::with_mut(|main| {
log::info!(
"R has started and ark handlers have been registered, completing initialization."
);
main.complete_initialization();
});
// Now that R has started (emitting any startup messages), and now that we have set
// up all hooks and handlers, officially finish the R initialization process to
// unblock the kernel-info request and also allow the LSP to start.
RMain::with_mut(|main| {
log::info!("R has started and ark handlers have been registered, completing initialization.");
main.complete_initialization();
});
}

// Now that R has started and libr and ark have fully initialized, run site and user
// level R profiles, in that order
Expand All @@ -431,6 +428,34 @@ impl RMain {
crate::sys::interface::run_r();
}

/// Completes the kernel's initialization.
/// Unlike `RMain::start()`, this has access to `R_MAIN`'s state, such as
/// the kernel-info banner.
/// SAFETY: Can only be called from the R thread, and only once.
pub unsafe fn complete_initialization(&mut self) {
let version = unsafe {
let version = Rf_findVarInFrame(R_BaseNamespace, r_symbol!("R.version.string"));
RObject::new(version).to::<String>().unwrap()
};

// Initial input and continuation prompts
let input_prompt: String = harp::get_option("prompt").try_into().unwrap();
let continuation_prompt: String = harp::get_option("continue").try_into().unwrap();

let kernel_info = KernelInfo {
version: version.clone(),
banner: self.banner_output.clone(),
input_prompt: Some(input_prompt),
continuation_prompt: Some(continuation_prompt),
};

log::info!("Sending kernel info: {version}");
self.kernel_init_tx.broadcast(kernel_info);

// Thread-safe initialisation flag for R
R_INIT.set(()).expect("`R_INIT` can only be set once");
}

pub fn new(
kernel: Arc<Mutex<Kernel>>,
tasks_interrupt_rx: Receiver<RTask>,
Expand All @@ -445,7 +470,6 @@ impl RMain {
session_mode: SessionMode,
) -> Self {
Self {
initializing: true,
r_request_rx,
comm_manager_tx,
stdin_request_tx,
Expand Down Expand Up @@ -474,14 +498,23 @@ impl RMain {

/// Wait for complete R initialization
///
/// Wait for R being ready to take input (i.e. `ReadConsole` was called).
/// Resolves as the same time as the `Bus<KernelInfo>` init channel does.
/// Wait for R being ready to evaluate R code. Resolves as the same time as
/// the `Bus<KernelInfo>` init channel does.
///
/// Thread-safe.
pub fn wait_r_initialized() {
R_INIT.wait();
}

/// Has R completed initialization
///
/// I.e. is it ready to evaluate R code.
///
/// Thread-safe.
pub fn is_r_initialized() -> bool {
R_INIT.get().is_some()
}

/// Has the `RMain` singleton completed initialization.
///
/// This can return true when R might still not have finished starting up.
Expand Down Expand Up @@ -545,38 +578,6 @@ impl RMain {
thread.id() == unsafe { R_MAIN_THREAD_ID.unwrap() }
}

/// Completes the kernel's initialization
pub fn complete_initialization(&mut self) {
if self.initializing {
let version = unsafe {
let version = Rf_findVarInFrame(R_BaseNamespace, r_symbol!("R.version.string"));
RObject::new(version).to::<String>().unwrap()
};

// Initial input and continuation prompts
let input_prompt: String = harp::get_option("prompt").try_into().unwrap();
let continuation_prompt: String = harp::get_option("continue").try_into().unwrap();

let kernel_info = KernelInfo {
version: version.clone(),
banner: self.banner_output.clone(),
input_prompt: Some(input_prompt),
continuation_prompt: Some(continuation_prompt),
};

log::info!("Sending kernel info: {version}");
self.kernel_init_tx.broadcast(kernel_info);

// Internal initialisation flag, should only be used on the R thread
self.initializing = false;

// Used as thread-safe initialisation flag
R_INIT.set(()).unwrap();
} else {
log::warn!("Initialization already complete!");
}
}

/// Provides read-only access to `iopub_tx`
pub fn get_iopub_tx(&self) -> &Sender<IOPubMessage> {
&self.iopub_tx
Expand Down Expand Up @@ -1323,7 +1324,7 @@ This is a Positron limitation we plan to fix. In the meantime, you can:
Stream::Stderr
};

if self.initializing {
if !RMain::is_r_initialized() {
// During init, consider all output to be part of the startup banner
self.banner_output.push_str(&content);
return;
Expand Down

0 comments on commit 1f5753d

Please sign in to comment.