2
2
3
3
extern crate llvm_sys as llvm;
4
4
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 } ;
6
6
use slog:: Logger ;
7
7
use common:: { pointer:: { LLVMRef , LLVMRefType , SafeLLVMPointer } , target:: { GeneralTargetConfigurator , TargetConfigurator } } ;
8
8
@@ -14,122 +14,196 @@ pub struct ExecutionEngine {
14
14
}
15
15
16
16
impl ExecutionEngine {
17
- /// Constructs a new `ExecutionEngine`.
17
+ /// Constructs a new `ExecutionEngine` with a timeout .
18
18
///
19
19
/// This method initializes a new LLVM context and module, configures the general target,
20
20
/// and optionally sets up a logger for debugging information based on the `debug_info` parameter.
21
21
///
22
22
/// # Parameters
23
23
/// * `module` - A thread-safe `SafeLLVMPointer` containing an `LLVMModuleRef`.
24
24
/// * `debug_info` - If true, initializes a logger to record debugging information.
25
+ /// * `timeout` - The maximum duration to wait for the initialization.
25
26
///
26
27
/// # Returns
27
28
/// 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
+ }
46
57
}
47
58
}
59
+ Ok ( ( ) )
60
+ } else {
61
+ Err ( "Module pointer is not correctly retrieved." . to_string ( ) )
48
62
}
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 ;
51
71
}
52
- } ) ;
53
72
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" ) ;
55
74
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
+ } ) ;
61
80
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
+ }
65
89
}
66
90
}
67
91
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 .
69
93
///
70
94
/// # Parameters
71
95
/// * `target_configurator` - The target configurator to setup necessary LLVM targets.
96
+ /// * `timeout` - The maximum duration to wait for the configuration.
72
97
///
73
98
/// # Returns
74
99
/// Returns `Ok(())` on successful configuration and initialization, or `Err(String)` on failure,
75
100
/// 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
+ }
80
124
}
81
- Ok ( ( ) )
82
125
}
83
126
84
- /// Executes a specified function within the module.
127
+ /// Executes a specified function within the module with a timeout .
85
128
///
86
129
/// # Parameters
87
130
/// * `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.
88
133
///
89
134
/// # Returns
90
135
/// 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 >
94
138
where
95
- ReturnType : ' static ,
96
- ArgType : Any + Send + Sync ,
139
+ ReturnType : ' static + Send ,
140
+ ArgType : Any + Send + Sync + ' static ,
97
141
{
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 ( ) ;
110
145
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) ) ;
118
169
} ) ;
119
170
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) ,
124
181
}
125
- Ok ( value)
126
182
} ,
127
- Err ( e ) => {
183
+ Err ( _ ) => {
128
184
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." ) ) ;
130
186
}
131
- Err ( e )
187
+ Err ( "Execution timed out." . to_string ( ) )
132
188
}
133
189
}
134
190
}
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