@@ -44,10 +44,11 @@ assert!(nums[0] == "2");
44
44
45
45
#![ warn( missing_docs) ]
46
46
47
+ use std:: convert:: TryFrom ;
47
48
use std:: error:: Error ;
48
49
use std:: fmt;
49
- use std:: mem;
50
50
use std:: os:: raw:: c_void;
51
+ use std:: panic:: AssertUnwindSafe ;
51
52
use std:: time:: Duration ;
52
53
53
54
use crate :: ffi:: * ;
@@ -79,68 +80,83 @@ impl fmt::Display for WaitTimeout {
79
80
impl Error for WaitTimeout { }
80
81
81
82
fn time_after_delay ( delay : Duration ) -> dispatch_time_t {
82
- delay
83
- . as_secs ( )
84
- . checked_mul ( 1_000_000_000 )
85
- . and_then ( |i| i. checked_add ( delay. subsec_nanos ( ) as u64 ) )
86
- . and_then ( |i| {
87
- if i < ( i64:: max_value ( ) as u64 ) {
88
- Some ( i as i64 )
89
- } else {
90
- None
91
- }
92
- } )
93
- . map_or ( DISPATCH_TIME_FOREVER , |i| unsafe {
94
- dispatch_time ( DISPATCH_TIME_NOW , i)
95
- } )
83
+ i64:: try_from ( delay. as_nanos ( ) ) . map_or ( DISPATCH_TIME_FOREVER , |i| unsafe {
84
+ dispatch_time ( DISPATCH_TIME_NOW , i)
85
+ } )
96
86
}
97
87
98
88
fn context_and_function < F > ( closure : F ) -> ( * mut c_void , dispatch_function_t )
99
89
where
100
- F : FnOnce ( ) ,
90
+ F : ' static + FnOnce ( ) ,
101
91
{
102
- extern "C" fn work_execute_closure < F > ( context : Box < F > )
92
+ extern "C" fn work_execute_closure < F > ( context : * mut c_void )
103
93
where
104
94
F : FnOnce ( ) ,
105
95
{
106
- ( * context) ( ) ;
96
+ let closure: Box < F > = unsafe { Box :: from_raw ( context as * mut _ ) } ;
97
+ if std:: panic:: catch_unwind ( AssertUnwindSafe ( closure) ) . is_err ( ) {
98
+ // Abort to prevent unwinding across FFI
99
+ std:: process:: abort ( ) ;
100
+ }
107
101
}
108
102
109
103
let closure = Box :: new ( closure) ;
110
- let func: extern "C" fn ( Box < F > ) = work_execute_closure :: < F > ;
111
- unsafe { ( mem :: transmute ( closure) , mem :: transmute ( func) ) }
104
+ let func: dispatch_function_t = work_execute_closure :: < F > ;
105
+ ( Box :: into_raw ( closure) as * mut c_void , func)
112
106
}
113
107
114
- fn context_and_sync_function < F > ( closure : & mut Option < F > ) -> ( * mut c_void , dispatch_function_t )
108
+ fn with_context_and_sync_function < F , T > (
109
+ closure : F ,
110
+ wrapper : impl FnOnce ( * mut c_void , dispatch_function_t ) ,
111
+ ) -> Option < T >
115
112
where
116
- F : FnOnce ( ) ,
113
+ F : FnOnce ( ) -> T ,
117
114
{
118
- extern "C" fn work_read_closure < F > ( context : & mut Option < F > )
115
+ #[ derive( Debug ) ]
116
+ struct SyncContext < F , T > {
117
+ closure : * mut F ,
118
+ result : Option < std:: thread:: Result < T > > ,
119
+ }
120
+
121
+ extern "C" fn work_execute_closure < F , T > ( context : * mut c_void )
119
122
where
120
- F : FnOnce ( ) ,
123
+ F : FnOnce ( ) -> T ,
121
124
{
122
- // This is always passed Some, so it's safe to unwrap
123
- let closure = context . take ( ) . unwrap ( ) ;
124
- closure ( ) ;
125
+ let sync_context : & mut SyncContext < F , T > = unsafe { & mut * ( context as * mut _ ) } ;
126
+ let closure = unsafe { Box :: from_raw ( sync_context . closure ) } ;
127
+ sync_context . result = Some ( std :: panic :: catch_unwind ( AssertUnwindSafe ( closure ) ) ) ;
125
128
}
126
129
127
- let context: * mut Option < F > = closure;
128
- let func: extern "C" fn ( & mut Option < F > ) = work_read_closure :: < F > ;
129
- unsafe { ( context as * mut c_void , mem:: transmute ( func) ) }
130
+ let mut sync_context: SyncContext < F , T > = SyncContext {
131
+ closure : Box :: into_raw ( Box :: new ( closure) ) ,
132
+ result : None ,
133
+ } ;
134
+ let func: dispatch_function_t = work_execute_closure :: < F , T > ;
135
+ wrapper ( & mut sync_context as * mut _ as * mut c_void , func) ;
136
+
137
+ // If the closure panicked, resume unwinding
138
+ match sync_context. result . transpose ( ) {
139
+ Ok ( res) => res,
140
+ Err ( unwind_payload) => std:: panic:: resume_unwind ( unwind_payload) ,
141
+ }
130
142
}
131
143
132
144
fn context_and_apply_function < F > ( closure : & F ) -> ( * mut c_void , extern "C" fn ( * mut c_void , usize ) )
133
145
where
134
146
F : Fn ( usize ) ,
135
147
{
136
- extern "C" fn work_apply_closure < F > ( context : & F , iter : usize )
148
+ extern "C" fn work_apply_closure < F > ( context : * mut c_void , iter : usize )
137
149
where
138
150
F : Fn ( usize ) ,
139
151
{
140
- context ( iter) ;
152
+ let context: & F = unsafe { & * ( context as * const _ ) } ;
153
+ if std:: panic:: catch_unwind ( AssertUnwindSafe ( || context ( iter) ) ) . is_err ( ) {
154
+ // Abort to prevent unwinding across FFI
155
+ std:: process:: abort ( ) ;
156
+ }
141
157
}
142
158
143
159
let context: * const F = closure;
144
- let func: extern "C" fn ( & F , usize ) = work_apply_closure :: < F > ;
145
- unsafe { ( context as * mut c_void , mem :: transmute ( func) ) }
160
+ let func: extern "C" fn ( * mut c_void , usize ) = work_apply_closure :: < F > ;
161
+ ( context as * mut c_void , func)
146
162
}
0 commit comments