Skip to content

Commit 27f3116

Browse files
committed
Added timeout to locate issue
1 parent 8f0af5b commit 27f3116

File tree

6 files changed

+250
-159
lines changed

6 files changed

+250
-159
lines changed

common/src/constants.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ pub const DEFAULT_BASIC_BLOCK_NAME: &str = "entry";
88

99
/// Default name for modules.
1010
pub const DEFAULT_MODULE_NAME: &str = "main";
11+
12+
/// Default timeout.
13+
pub const DEFAULT_TIMEOUT: u64 = 60;

common/src/pointer.rs

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl LLVMRef {
105105

106106
/// Thread-safe pointer type for managing raw C pointers in a synchronized context.
107107
pub struct SafeLLVMPointer {
108-
ptr: Arc<RwLock<NonNull<c_void>>>,
108+
ptr: Arc<RwLock<*mut c_void>>,
109109
kind: LLVMRefType
110110
}
111111

@@ -119,10 +119,14 @@ impl SafeLLVMPointer {
119119
/// An `Option` wrapped `SafeLLVMPointer` if the pointer is non-null, `None` otherwise.
120120
pub fn new(llvm_ref: LLVMRef, kind: LLVMRefType) -> Option<Self> {
121121
let raw_ptr = llvm_ref.to_raw();
122-
NonNull::new(raw_ptr).map(|nn_ptr| SafeLLVMPointer {
123-
ptr: Arc::new(RwLock::new(nn_ptr)),
124-
kind,
125-
})
122+
if raw_ptr.is_null() {
123+
None
124+
} else {
125+
Some(SafeLLVMPointer {
126+
ptr: Arc::new(RwLock::new(raw_ptr)),
127+
kind,
128+
})
129+
}
126130
}
127131

128132
/// Provides read-only access to the pointed-to value.
@@ -147,7 +151,7 @@ impl SafeLLVMPointer {
147151
Closure: FnOnce(&LLVMRef) -> ReturnType,
148152
{
149153
let lock = self.ptr.read().expect("RwLock has been poisoned");
150-
let ref_to_value = unsafe { LLVMRef::from_raw(lock.as_ptr(), kind) };
154+
let ref_to_value = unsafe { LLVMRef::from_raw(*lock, kind) };
151155
closure(&ref_to_value)
152156
}
153157

@@ -167,27 +171,10 @@ impl SafeLLVMPointer {
167171
Closure: FnOnce(&mut LLVMRef) -> ReturnType,
168172
{
169173
let lock = self.ptr.write().expect("RwLock has been poisoned");
170-
let mut ref_to_mut_value = unsafe { LLVMRef::from_raw(lock.as_ptr(), kind) };
174+
let mut ref_to_mut_value = unsafe { LLVMRef::from_raw(*lock, kind) };
171175
closure(&mut ref_to_mut_value)
172176
}
173177
}
174178

175-
// impl Drop for SafeLLVMPointer {
176-
// fn drop(&mut self) {
177-
// let ptr = self.ptr.write().expect("Lock poisoned on drop.");
178-
// let raw_ptr = ptr.as_ptr();
179-
180-
// unsafe {
181-
// match self.kind {
182-
// // LLVMRefType::Context => core::LLVMContextDispose(raw_ptr as LLVMContextRef),
183-
// // LLVMRefType::Module => core::LLVMDisposeModule(raw_ptr as LLVMModuleRef),
184-
// // LLVMRefType::Builder => core::LLVMDisposeBuilder(raw_ptr as LLVMBuilderRef),
185-
// LLVMRefType::ExecutionEngine => execution_engine::LLVMDisposeExecutionEngine(raw_ptr as LLVMExecutionEngineRef),
186-
// LLVMRefType::Value |
187-
// LLVMRefType::BasicBlock |
188-
// LLVMRefType::Type => {},
189-
// _ => {},
190-
// }
191-
// }
192-
// }
193-
// }
179+
unsafe impl Send for SafeLLVMPointer {}
180+
unsafe impl Sync for SafeLLVMPointer {}

jit/src/core.rs

Lines changed: 146 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
extern crate llvm_sys as llvm;
44
use llvm::{core, execution_engine};
5-
use std::{any::Any, ffi::{c_char, CStr, CString}, sync::{Arc, RwLock}};
5+
use std::{any::Any, ffi::{c_char, CStr, CString}, sync::{mpsc, Arc, RwLock}, thread, time::Duration};
66
use slog::Logger;
77
use common::{pointer::{LLVMRef, LLVMRefType, SafeLLVMPointer}, target::{GeneralTargetConfigurator, TargetConfigurator}};
88

@@ -14,122 +14,196 @@ pub struct ExecutionEngine {
1414
}
1515

1616
impl ExecutionEngine {
17-
/// Constructs a new `ExecutionEngine`.
17+
/// Constructs a new `ExecutionEngine` with a timeout.
1818
///
1919
/// This method initializes a new LLVM context and module, configures the general target,
2020
/// and optionally sets up a logger for debugging information based on the `debug_info` parameter.
2121
///
2222
/// # Parameters
2323
/// * `module` - A thread-safe `SafeLLVMPointer` containing an `LLVMModuleRef`.
2424
/// * `debug_info` - If true, initializes a logger to record debugging information.
25+
/// * `timeout` - The maximum duration to wait for the initialization.
2526
///
2627
/// # Returns
2728
/// A new instance of `ExecutionEngine`.
28-
pub fn new(module: Arc<RwLock<SafeLLVMPointer>>, debug_info: bool) -> Self {
29-
GeneralTargetConfigurator.configure();
30-
31-
let mut engine_ref: execution_engine::LLVMExecutionEngineRef = std::ptr::null_mut();
32-
let mut out_error: *mut c_char = std::ptr::null_mut();
33-
let engine_ptr = &mut engine_ref;
34-
35-
module.read().unwrap().read(LLVMRefType::Module, |module_ref| {
36-
if let LLVMRef::Module(module_ptr) = module_ref {
37-
unsafe {
38-
if execution_engine::LLVMCreateExecutionEngineForModule(engine_ptr, *module_ptr, &mut out_error) != 0 {
39-
if !out_error.is_null() {
40-
let error_str = CStr::from_ptr(out_error).to_str().unwrap_or("Unknown error");
41-
eprintln!("{}", error_str);
42-
core::LLVMDisposeMessage(out_error);
43-
panic!("Failed to create execution engine");
44-
} else {
45-
panic!("Failed to create execution engine with unknown error.");
29+
pub fn new(module: Arc<RwLock<SafeLLVMPointer>>, debug_info: bool, timeout: Duration) -> Result<Self, String> {
30+
let (sender, receiver) = mpsc::channel();
31+
let logger = if debug_info {
32+
Some(logging::core::init_logger())
33+
} else {
34+
None
35+
};
36+
37+
let logger_clone = logger.clone();
38+
39+
thread::spawn(move || {
40+
GeneralTargetConfigurator.configure();
41+
42+
let mut engine_ref: execution_engine::LLVMExecutionEngineRef = std::ptr::null_mut();
43+
let mut out_error: *mut c_char = std::ptr::null_mut();
44+
let engine_ptr = &mut engine_ref;
45+
46+
let result = module.read().unwrap().read(LLVMRefType::Module, |module_ref| {
47+
if let LLVMRef::Module(module_ptr) = module_ref {
48+
unsafe {
49+
if execution_engine::LLVMCreateExecutionEngineForModule(engine_ptr, *module_ptr, &mut out_error) != 0 {
50+
if !out_error.is_null() {
51+
let error_str = CStr::from_ptr(out_error).to_str().unwrap_or("Unknown error");
52+
core::LLVMDisposeMessage(out_error);
53+
return Err(format!("Failed to create execution engine: {}", error_str));
54+
} else {
55+
return Err("Failed to create execution engine with unknown error.".to_string());
56+
}
4657
}
4758
}
59+
Ok(())
60+
} else {
61+
Err("Module pointer is not correctly retrieved.".to_string())
4862
}
49-
} else {
50-
panic!("Module pointer is not correctly retrieved.");
63+
});
64+
65+
if let Err(e) = result {
66+
if let Some(logger) = &logger_clone {
67+
logging::core::log_error(logger, &e);
68+
}
69+
sender.send(Err(e)).unwrap();
70+
return;
5171
}
52-
});
5372

54-
let engine_cptr = SafeLLVMPointer::new(LLVMRef::ExecutionEngine(engine_ref), LLVMRefType::ExecutionEngine).expect("Engine cannot be null");
73+
let engine_cptr = SafeLLVMPointer::new(LLVMRef::ExecutionEngine(engine_ref), LLVMRefType::ExecutionEngine).expect("Engine cannot be null");
5574

56-
let logger = if debug_info {
57-
Some(logging::core::init_logger())
58-
} else {
59-
None
60-
};
75+
sender.send(Ok(Self {
76+
engine: Arc::new(RwLock::new(engine_cptr)),
77+
logger: logger_clone,
78+
})).unwrap();
79+
});
6180

62-
Self {
63-
engine: Arc::new(RwLock::new(engine_cptr)),
64-
logger,
81+
match receiver.recv_timeout(timeout) {
82+
Ok(result) => result,
83+
Err(_) => {
84+
if let Some(logger) = &logger {
85+
logging::core::log_error(&logger, "Initialization timed out.");
86+
}
87+
Err("Initialization timed out.".to_string())
88+
}
6589
}
6690
}
6791

68-
/// Configures the LLVM execution engine using a specified target configurator.
92+
/// Configures the LLVM execution engine using a specified target configurator with a timeout.
6993
///
7094
/// # Parameters
7195
/// * `target_configurator` - The target configurator to setup necessary LLVM targets.
96+
/// * `timeout` - The maximum duration to wait for the configuration.
7297
///
7398
/// # Returns
7499
/// Returns `Ok(())` on successful configuration and initialization, or `Err(String)` on failure,
75100
/// including detailed error messages.
76-
pub fn initialize_target<T: TargetConfigurator>(&mut self, target_configurator: T) -> Result<(), String> {
77-
target_configurator.configure();
78-
if let Some(logger) = &self.logger {
79-
logging::core::log_info(&logger, "Target configured.");
101+
pub fn initialize_target<T>(&mut self, target_configurator: T, timeout: Duration) -> Result<(), String>
102+
where
103+
T: TargetConfigurator + Send + 'static,
104+
{
105+
let (sender, receiver) = mpsc::channel();
106+
let logger = self.logger.clone();
107+
108+
thread::spawn(move || {
109+
target_configurator.configure();
110+
if let Some(logger) = &logger {
111+
logging::core::log_info(&logger, "Target configured.");
112+
}
113+
sender.send(Ok(())).unwrap();
114+
});
115+
116+
match receiver.recv_timeout(timeout) {
117+
Ok(result) => result,
118+
Err(_) => {
119+
if let Some(logger) = &self.logger {
120+
logging::core::log_error(logger, "Target configuration timed out.");
121+
}
122+
Err("Target configuration timed out.".to_string())
123+
}
80124
}
81-
Ok(())
82125
}
83126

84-
/// Executes a specified function within the module.
127+
/// Executes a specified function within the module with a timeout.
85128
///
86129
/// # Parameters
87130
/// * `function_name` - The name of the function to be executed.
131+
/// * `args` - The arguments to be passed to the function.
132+
/// * `timeout` - The maximum duration to wait for the function to execute.
88133
///
89134
/// # Returns
90135
/// Returns `Ok(())` if the function is executed successfully, or `Err(String)` if an error occurs,
91-
/// which could include the function not being found or an execution error.
92-
/// Executes a specified function.
93-
pub fn execute<ReturnType, ArgType>(&mut self, function_name: &str, args: ArgType) -> Result<ReturnType, String>
136+
/// which could include the function not being found, an execution error, or a timeout.
137+
pub fn execute<ReturnType, ArgType>(&mut self, function_name: &str, args: ArgType, timeout: Duration) -> Result<ReturnType, String>
94138
where
95-
ReturnType: 'static,
96-
ArgType: Any + Send + Sync,
139+
ReturnType: 'static + Send,
140+
ArgType: Any + Send + Sync + 'static,
97141
{
98-
let engine_lock = self.engine.read().map_err(|e| format!("Failed to obtain read lock on engine: {}", e))?;
99-
let result = engine_lock.read(LLVMRefType::ExecutionEngine, |engine_ref| {
100-
if let LLVMRef::ExecutionEngine(engine_ptr) = engine_ref {
101-
let function_name_c = CString::new(function_name).map_err(|_| "Failed to create CString for function name.")?;
102-
let function_address = unsafe { execution_engine::LLVMGetFunctionAddress(*engine_ptr, function_name_c.as_ptr()) };
103-
104-
if function_address == 0 {
105-
if let Some(logger) = &self.logger {
106-
logging::core::log_warning(&logger, &format!("Function \"{}\" not found.", function_name));
107-
}
108-
return Err("Function not found in given module.".to_string());
109-
}
142+
let (sender, receiver) = mpsc::channel();
143+
let engine_lock = self.engine.clone();
144+
let function_name = function_name.to_string();
110145

111-
unsafe {
112-
let func: extern "C" fn(ArgType) -> ReturnType = std::mem::transmute(function_address);
113-
Ok(func(args))
114-
}
115-
} else {
116-
Err("Invalid engine pointer.".to_string())
117-
}
146+
thread::spawn(move || {
147+
let result = engine_lock.read().map_err(|e| format!("Failed to obtain read lock on engine: {}", e))
148+
.and_then(|engine| {
149+
engine.read(LLVMRefType::ExecutionEngine, |engine_ref| {
150+
if let LLVMRef::ExecutionEngine(engine_ptr) = engine_ref {
151+
let function_name_c = CString::new(function_name.clone()).map_err(|_| "Failed to create CString for function name.")?;
152+
let function_address = unsafe { execution_engine::LLVMGetFunctionAddress(*engine_ptr, function_name_c.as_ptr()) };
153+
154+
if function_address == 0 {
155+
return Err("Function not found in given module.".to_string());
156+
}
157+
158+
unsafe {
159+
let func: extern "C" fn(ArgType) -> ReturnType = std::mem::transmute(function_address);
160+
Ok(func(args))
161+
}
162+
} else {
163+
Err("Invalid engine pointer.".to_string())
164+
}
165+
})
166+
});
167+
168+
sender.send(result).unwrap_or_else(|e| eprintln!("Failed to send result: {}", e));
118169
});
119170

120-
match result {
121-
Ok(value) => {
122-
if let Some(logger) = &self.logger {
123-
logging::core::log_info(&logger, &format!("Function '{}' executed successfully.", function_name));
171+
match receiver.recv_timeout(timeout) {
172+
Ok(result) => {
173+
match result {
174+
Ok(value) => {
175+
if let Some(logger) = &self.logger {
176+
logging::core::log_info(logger, &format!("Function executed successfully."));
177+
}
178+
Ok(value)
179+
},
180+
Err(e) => Err(e),
124181
}
125-
Ok(value)
126182
},
127-
Err(e) => {
183+
Err(_) => {
128184
if let Some(logger) = &self.logger {
129-
logging::core::log_error(&logger, &format!("Execution error: {}", e));
185+
logging::core::log_error(logger, &format!("Execution of function timed out."));
130186
}
131-
Err(e)
187+
Err("Execution timed out.".to_string())
132188
}
133189
}
134190
}
135-
}
191+
}
192+
193+
impl Drop for ExecutionEngine {
194+
fn drop(&mut self) {
195+
if let Ok(engine_lock) = self.engine.write() {
196+
engine_lock.write(LLVMRefType::ExecutionEngine, |engine_ref| {
197+
if let LLVMRef::ExecutionEngine(engine_ptr) = engine_ref {
198+
unsafe {
199+
execution_engine::LLVMDisposeExecutionEngine(*engine_ptr);
200+
}
201+
}
202+
});
203+
}
204+
205+
if let Some(logger) = &self.logger {
206+
logging::core::log_info(logger, "Execution engine disposed.");
207+
}
208+
}
209+
}

0 commit comments

Comments
 (0)