Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC for r_lock! enforcement on the R API #26

Closed
wants to merge 1 commit into from

Conversation

DavisVaughan
Copy link
Contributor

@DavisVaughan DavisVaughan commented Jun 9, 2023

"Fixed" just enough of the missing r_lock!s to get tests passing, but interactive usage could reveal more

Comment on lines 62 to 67
if let Err(err) = r_assert_type(env.sexp, &[ENVSXP]) {
warn!(
"Environment: Attempt to monitor or list non-environment object {:?} ({:?})",
env, err
);
r_lock! {
if let Err(err) = r_assert_type(env.sexp, &[ENVSXP]) {
warn!(
"Environment: Attempt to monitor or list non-environment object {:?} ({:?})",
env, err
);
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing r_lock! when starting the environment pane, one could argue whether or not TYPEOF() should require the lock

// Get necessary prompts
let (continue_prompt, default_prompt) =
r_lock! { (r_get_option::<String>("continue"), r_get_option::<String>("prompt")) };

// The request is incomplete if we see the continue prompt
let continue_prompt = unsafe { r_get_option::<String>("continue") };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing lock when accessing the prompt global options

Comment on lines -229 to 245
// Include HTML representation of data.frame
// TODO: Do we need to hold the R lock here?
let value = unsafe { Rf_findVarInFrame(R_GlobalEnv, r_symbol!(".Last.value")) };
if r_is_data_frame(value) {
match Kernel::to_html(value) {
Ok(html) => data.insert("text/html".to_string(), json!(html)),
Err(error) => {
error!("{:?}", error);
None
},
};
r_lock! {
let value = Rf_findVarInFrame(R_GlobalEnv, r_symbol!(".Last.value"));

// Include HTML representation of data.frame
if r_is_data_frame(value) {
match Kernel::to_html(value) {
Ok(html) => data.insert("text/html".to_string(), json!(html)),
Err(error) => {
error!("{:?}", error);
None
},
};
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing lock when finishing a code execution request

Comment on lines 167 to 177
let out = quote! {
#(#attrs)* #vis #sig {

#[cfg(debug_assertions)]
std::assert!(
crate::lock::R_RUNTIME_LOCKED.load(std::sync::atomic::Ordering::Acquire),
#message
);

#(#stmts)*
}
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General idea is to just smush in this debug assertion ahead of the other statements in the function body
https://stackoverflow.com/questions/66850967/procedural-attribute-macro-to-inject-code-at-the-beginning-of-a-function

//
//

use libR_sys::*;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually this should be the only place we import this

Comment on lines 33 to 37
// Debug only tracking of whether or not the thread holds the lock,
// used by the intermediate layer wrapping the R API
#[cfg(debug_assertions)]
pub static R_RUNTIME_LOCKED: std::sync::atomic::AtomicBool =
std::sync::atomic::AtomicBool::new(false);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An atomic boolean that gets set to true once we hold the lock and false right before we release it, so when the callback itself is executed it will see that this is true.

I'm not actually sure it needs to be atomic since we already have a mutex lock through guard? But someone else would have to weigh in here.

Comment on lines -109 to +121
let actual = unsafe { Rf_xlength(object) as usize };
let actual = r_length(object) as usize;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should allow us to remove some unsafes and begin to start using unsafe as it is intended in Rust

@DavisVaughan
Copy link
Contributor Author

We can come back to this in the future but there is no need to keep it open right now as it isn't super high priority for alpha and I doubt we use this exact approach, but it will be a useful reference

@DavisVaughan DavisVaughan deleted the feature/r-lock-enforcement branch June 26, 2024 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant