Skip to content

Commit 72fa9d0

Browse files
committed
Rename sys/interface to sys/console
1 parent f0f4e27 commit 72fa9d0

File tree

8 files changed

+364
-387
lines changed

8 files changed

+364
-387
lines changed

crates/ark/src/console.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ impl Console {
630630
let libraries = RLibraries::from_r_home_path(&r_home);
631631
libraries.initialize_pre_setup_r();
632632

633-
crate::sys::interface::setup_r(&r_args);
633+
crate::sys::console::setup_r(&r_args);
634634

635635
libraries.initialize_post_setup_r();
636636

@@ -718,7 +718,7 @@ impl Console {
718718
}
719719

720720
// Start the REPL. Does not return!
721-
crate::sys::interface::run_r();
721+
crate::sys::console::run_r();
722722
}
723723

724724
/// Build the argument list from the command line arguments. The default
@@ -2324,7 +2324,7 @@ impl Console {
23242324
// this.
23252325
unsafe { R_ProcessEvents() };
23262326

2327-
crate::sys::interface::run_activity_handlers();
2327+
crate::sys::console::run_activity_handlers();
23282328

23292329
// Run pending finalizers. We need to do this eagerly as otherwise finalizers
23302330
// might end up being executed on the LSP thread.

crates/ark/src/fixtures/dummy_frontend.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl DummyArkFrontend {
6969
pub fn wait_for_cleanup() {
7070
use std::time::Duration;
7171

72-
use crate::sys::interface::CLEANUP_SIGNAL;
72+
use crate::sys::console::CLEANUP_SIGNAL;
7373

7474
let (lock, cvar) = &CLEANUP_SIGNAL;
7575
let result = cvar

crates/ark/src/sys/unix.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
pub mod console;
99
pub mod control;
10-
pub mod interface;
1110
pub mod path;
1211
pub mod signals;
1312
pub mod traps;

crates/ark/src/sys/unix/console.rs

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,158 @@
11
/*
22
* console.rs
33
*
4-
* Copyright (C) 2023 Posit Software, PBC. All rights reserved.
4+
* Copyright (C) 2023-2026 Posit Software, PBC. All rights reserved.
55
*
66
*/
77

88
use std::ffi::c_char;
99
use std::ffi::CStr;
10+
use std::sync::Condvar;
11+
use std::sync::Mutex;
1012

13+
use libr::ptr_R_Busy;
14+
use libr::ptr_R_ReadConsole;
15+
use libr::ptr_R_ShowMessage;
16+
use libr::ptr_R_Suicide;
17+
use libr::ptr_R_WriteConsole;
18+
use libr::ptr_R_WriteConsoleEx;
19+
use libr::run_Rmainloop;
20+
use libr::setup_Rmainloop;
21+
use libr::R_Consolefile;
22+
use libr::R_HomeDir;
23+
use libr::R_InputHandlers;
24+
use libr::R_Interactive;
25+
use libr::R_Outputfile;
26+
use libr::R_PolledEvents;
27+
use libr::R_SignalHandlers;
28+
use libr::R_checkActivity;
29+
use libr::R_runHandlers;
30+
use libr::R_running_as_main_program;
31+
use libr::R_wait_usec;
32+
use libr::Rf_initialize_R;
33+
34+
use crate::console::r_busy;
35+
use crate::console::r_polled_events;
36+
use crate::console::r_read_console;
37+
use crate::console::r_show_message;
38+
use crate::console::r_suicide;
39+
use crate::console::r_write_console;
40+
use crate::console::Console;
41+
use crate::signals::initialize_signal_handlers;
42+
43+
// For shutdown signal in integration tests
44+
pub static CLEANUP_SIGNAL: (Mutex<bool>, Condvar) = (Mutex::new(false), Condvar::new());
45+
46+
pub fn setup_r(args: &Vec<String>) {
47+
unsafe {
48+
// Before `Rf_initialize_R()`
49+
libr::set(R_running_as_main_program, 1);
50+
51+
libr::set(R_SignalHandlers, 0);
52+
53+
let mut c_args = Console::build_ark_c_args(args);
54+
Rf_initialize_R(c_args.len() as i32, c_args.as_mut_ptr() as *mut *mut c_char);
55+
56+
// Initialize the signal blocks and handlers (like interrupts).
57+
// Don't do that in tests because that makes them uninterruptible.
58+
if !stdext::IS_TESTING {
59+
initialize_signal_handlers();
60+
}
61+
62+
// Mark R session as interactive
63+
// (Should have also been set by call to `Rf_initialize_R()`)
64+
libr::set(R_Interactive, 1);
65+
66+
// Log the value of R_HOME, so we can know if something hairy is afoot
67+
let home = CStr::from_ptr(R_HomeDir());
68+
log::trace!("R_HOME: {:?}", home);
69+
70+
// Redirect console
71+
libr::set(R_Consolefile, std::ptr::null_mut());
72+
libr::set(R_Outputfile, std::ptr::null_mut());
73+
74+
libr::set(ptr_R_WriteConsole, None);
75+
libr::set(ptr_R_WriteConsoleEx, Some(r_write_console));
76+
libr::set(ptr_R_ReadConsole, Some(r_read_console));
77+
libr::set(ptr_R_ShowMessage, Some(r_show_message));
78+
libr::set(ptr_R_Busy, Some(r_busy));
79+
libr::set(ptr_R_Suicide, Some(r_suicide));
80+
81+
// Install a CleanUp hook for integration tests that test the shutdown process.
82+
// We confirm that shutdown occurs by waiting in the test until `CLEANUP_SIGNAL`'s
83+
// condition variable sends a notification, which occurs in this cleanup method
84+
// that is called during R's shutdown process.
85+
if stdext::IS_TESTING {
86+
libr::set(libr::ptr_R_CleanUp, Some(r_cleanup_for_tests));
87+
}
88+
89+
// In tests R may be run from various threads. This confuses R's stack
90+
// overflow checks so we disable those. This should not make it in
91+
// production builds as it causes stack overflows to crash R instead of
92+
// throwing an R error.
93+
//
94+
// This must be called _after_ `Rf_initialize_R()`, since that's where R
95+
// detects the stack size and sets the default limit.
96+
if stdext::IS_TESTING {
97+
libr::set(libr::R_CStackLimit, usize::MAX);
98+
}
99+
100+
// Set up main loop
101+
setup_Rmainloop();
102+
}
103+
}
104+
105+
pub fn run_r() {
106+
unsafe {
107+
// Listen for polled events
108+
libr::set(R_wait_usec, 10000);
109+
libr::set(R_PolledEvents, Some(r_polled_events));
110+
111+
run_Rmainloop();
112+
}
113+
}
114+
115+
pub fn run_activity_handlers() {
116+
unsafe {
117+
// Run handlers if we have data available. This is necessary
118+
// for things like the HTML help server, which will listen
119+
// for requests on an open socket() which would then normally
120+
// be handled in a select() call when reading input from stdin.
121+
//
122+
// https://github.com/wch/r-source/blob/4ca6439c1ffc76958592455c44d83f95d5854b2a/src/unix/sys-std.c#L1084-L1086
123+
//
124+
// We run this in a loop just to make sure the R help server can
125+
// be as responsive as possible when rendering help pages.
126+
//
127+
// Note that the later package also adds an input handler to `R_InputHandlers`
128+
// which runs the later event loop, so it's also important that we are fairly
129+
// responsive for that as well (posit-dev/positron#7235).
130+
let mut fdset = R_checkActivity(0, 1);
131+
132+
while fdset != std::ptr::null_mut() {
133+
R_runHandlers(libr::get(R_InputHandlers), fdset);
134+
fdset = R_checkActivity(0, 1);
135+
}
136+
}
137+
}
138+
139+
#[no_mangle]
140+
pub extern "C-unwind" fn r_cleanup_for_tests(_save_act: i32, _status: i32, _run_last: i32) {
141+
// Signal that cleanup has started
142+
let (lock, cvar) = &CLEANUP_SIGNAL;
143+
144+
let mut started = lock.lock().unwrap();
145+
*started = true;
146+
147+
cvar.notify_all();
148+
drop(started);
149+
150+
// Sleep to give tests time to complete before we panic
151+
std::thread::sleep(std::time::Duration::from_secs(5));
152+
153+
// Fallthrough to R which will call `exit()`. Note that panicking from here
154+
// would be UB, we can't panic over a C stack.
155+
}
11156
/// On Unix, we assume that the buffer to write to the console is
12157
/// already in UTF-8
13158
pub fn console_to_utf8(x: *const c_char) -> anyhow::Result<String> {

crates/ark/src/sys/unix/interface.rs

Lines changed: 0 additions & 155 deletions
This file was deleted.

crates/ark/src/sys/windows.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
pub mod console;
99
pub mod control;
10-
pub mod interface;
1110
mod locale;
1211
pub mod parent_monitor;
1312
pub mod path;

0 commit comments

Comments
 (0)