1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use std::{
ffi::c_void,
sync::atomic::{AtomicPtr, Ordering},
};
use core_foundation::{
base::TCFType,
date::CFAbsoluteTimeGetCurrent,
runloop::{
CFRunLoopGetCurrent, CFRunLoopRef, CFRunLoopTimerRef, __CFRunLoop, kCFRunLoopDefaultMode,
CFRunLoopAddTimer, CFRunLoopRun, CFRunLoopTimer, CFRunLoopWakeUp,
},
};
// use tracing::*;
static HTTP_THREAD_LOOP: AtomicPtr<__CFRunLoop> = AtomicPtr::new(std::ptr::null_mut());
pub fn get_or_spawn_http_thread() -> CFRunLoopRef {
let thread_loop = HTTP_THREAD_LOOP.load(Ordering::SeqCst);
if thread_loop.is_null() {
let (sx, rx) = std::sync::mpsc::sync_channel::<()>(1);
std::thread::spawn(move || {
unsafe {
let run_loop = CFRunLoopGetCurrent();
HTTP_THREAD_LOOP.swap(run_loop, Ordering::SeqCst);
sx.send(()).unwrap();
extern "C" fn timer_noop(_: CFRunLoopTimerRef, _: *mut c_void) {}
// extern "C" fn observer_callback(
// observer: CFRunLoopObserverRef,
// activity: CFRunLoopActivity,
// info: *mut c_void,
// ) {
// // #[allow(non_upper_case_globals)]
// // match activity {
// // kCFRunLoopEntry => debug!("http run loop observer with kCFRunLoopEntry"),
// // kCFRunLoopBeforeTimers => {
// // debug!("http run loop observer with kCFRunLoopBeforeTimers")
// // }
// // kCFRunLoopBeforeSources => {
// // debug!("http run loop observer with kCFRunLoopBeforeSources")
// // }
// // kCFRunLoopBeforeWaiting => {
// // debug!("http run loop observer with kCFRunLoopBeforeWaiting (sleeping)")
// // }
// // kCFRunLoopAfterWaiting => {
// // debug!("http run loop observer with kCFRunLoopAfterWaiting (wakeup)")
// // }
// // kCFRunLoopExit => debug!("http run loop observer with kCFRunLoopExit"),
// // other => {
// // debug!("http run loop observer with {other}");
// // }
// // }
// }
// let observer = CFRunLoopObserverCreate(
// core::ptr::null_mut(),
// kCFRunLoopAllActivities,
// true as _,
// 0,
// observer_callback,
// core::ptr::null_mut(),
// );
// Wait for task, or the run loop will exit immediately
let await_timer = CFRunLoopTimer::new(
CFAbsoluteTimeGetCurrent() + 5.,
1.,
0,
0,
timer_noop,
std::ptr::null_mut(),
);
CFRunLoopAddTimer(
run_loop,
await_timer.as_concrete_TypeRef(),
kCFRunLoopDefaultMode,
);
// CFRunLoopAddObserver(run_loop, observer, kCFRunLoopDefaultMode);
CFRunLoopRun();
HTTP_THREAD_LOOP.swap(std::ptr::null_mut(), Ordering::SeqCst);
}
});
rx.recv().unwrap();
let thread_loop = HTTP_THREAD_LOOP.load(Ordering::SeqCst);
debug_assert!(!thread_loop.is_null());
thread_loop
} else {
thread_loop
}
}
pub fn wakeup_http_thread() {
unsafe {
CFRunLoopWakeUp(get_or_spawn_http_thread());
}
}