itsi-scheduler 0.2.22-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +8 -0
  3. data/Cargo.lock +997 -0
  4. data/Cargo.toml +7 -0
  5. data/Rakefile +39 -0
  6. data/ext/itsi_acme/Cargo.toml +86 -0
  7. data/ext/itsi_acme/examples/high_level.rs +63 -0
  8. data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
  9. data/ext/itsi_acme/examples/low_level.rs +87 -0
  10. data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
  11. data/ext/itsi_acme/src/acceptor.rs +81 -0
  12. data/ext/itsi_acme/src/acme.rs +354 -0
  13. data/ext/itsi_acme/src/axum.rs +86 -0
  14. data/ext/itsi_acme/src/cache.rs +39 -0
  15. data/ext/itsi_acme/src/caches/boxed.rs +80 -0
  16. data/ext/itsi_acme/src/caches/composite.rs +69 -0
  17. data/ext/itsi_acme/src/caches/dir.rs +106 -0
  18. data/ext/itsi_acme/src/caches/mod.rs +11 -0
  19. data/ext/itsi_acme/src/caches/no.rs +78 -0
  20. data/ext/itsi_acme/src/caches/test.rs +136 -0
  21. data/ext/itsi_acme/src/config.rs +172 -0
  22. data/ext/itsi_acme/src/https_helper.rs +69 -0
  23. data/ext/itsi_acme/src/incoming.rs +142 -0
  24. data/ext/itsi_acme/src/jose.rs +161 -0
  25. data/ext/itsi_acme/src/lib.rs +142 -0
  26. data/ext/itsi_acme/src/resolver.rs +59 -0
  27. data/ext/itsi_acme/src/state.rs +424 -0
  28. data/ext/itsi_error/Cargo.lock +368 -0
  29. data/ext/itsi_error/Cargo.toml +12 -0
  30. data/ext/itsi_error/src/lib.rs +140 -0
  31. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  32. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  33. data/ext/itsi_rb_helpers/Cargo.lock +355 -0
  34. data/ext/itsi_rb_helpers/Cargo.toml +11 -0
  35. data/ext/itsi_rb_helpers/src/heap_value.rs +139 -0
  36. data/ext/itsi_rb_helpers/src/lib.rs +232 -0
  37. data/ext/itsi_scheduler/Cargo.toml +24 -0
  38. data/ext/itsi_scheduler/extconf.rb +11 -0
  39. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  40. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  41. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  42. data/ext/itsi_scheduler/src/itsi_scheduler.rs +320 -0
  43. data/ext/itsi_scheduler/src/lib.rs +39 -0
  44. data/ext/itsi_server/Cargo.lock +2956 -0
  45. data/ext/itsi_server/Cargo.toml +94 -0
  46. data/ext/itsi_server/src/default_responses/mod.rs +14 -0
  47. data/ext/itsi_server/src/env.rs +43 -0
  48. data/ext/itsi_server/src/lib.rs +154 -0
  49. data/ext/itsi_server/src/prelude.rs +2 -0
  50. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/big_bytes.rs +116 -0
  51. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +149 -0
  52. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +346 -0
  53. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +265 -0
  54. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +399 -0
  55. data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +447 -0
  56. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +545 -0
  57. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +650 -0
  58. data/ext/itsi_server/src/ruby_types/itsi_server.rs +102 -0
  59. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  60. data/ext/itsi_server/src/server/binds/bind.rs +204 -0
  61. data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
  62. data/ext/itsi_server/src/server/binds/listener.rs +485 -0
  63. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  64. data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +132 -0
  65. data/ext/itsi_server/src/server/binds/tls.rs +278 -0
  66. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  67. data/ext/itsi_server/src/server/frame_stream.rs +143 -0
  68. data/ext/itsi_server/src/server/http_message_types.rs +230 -0
  69. data/ext/itsi_server/src/server/io_stream.rs +128 -0
  70. data/ext/itsi_server/src/server/lifecycle_event.rs +12 -0
  71. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  72. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  73. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  74. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +93 -0
  75. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  76. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  77. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +329 -0
  78. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +300 -0
  79. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  80. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  81. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +188 -0
  82. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +168 -0
  83. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +183 -0
  84. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  85. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  86. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +133 -0
  87. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  88. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +122 -0
  89. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +407 -0
  90. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +155 -0
  91. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +54 -0
  92. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  93. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  94. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +138 -0
  95. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +269 -0
  96. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +62 -0
  97. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +218 -0
  98. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  99. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  100. data/ext/itsi_server/src/server/mod.rs +14 -0
  101. data/ext/itsi_server/src/server/process_worker.rs +247 -0
  102. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  103. data/ext/itsi_server/src/server/request_job.rs +11 -0
  104. data/ext/itsi_server/src/server/serve_strategy/acceptor.rs +100 -0
  105. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +411 -0
  106. data/ext/itsi_server/src/server/serve_strategy/mod.rs +31 -0
  107. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +449 -0
  108. data/ext/itsi_server/src/server/signal.rs +129 -0
  109. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  110. data/ext/itsi_server/src/server/thread_worker.rs +504 -0
  111. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  112. data/ext/itsi_server/src/services/itsi_http_service.rs +270 -0
  113. data/ext/itsi_server/src/services/mime_types.rs +2896 -0
  114. data/ext/itsi_server/src/services/mod.rs +6 -0
  115. data/ext/itsi_server/src/services/password_hasher.rs +89 -0
  116. data/ext/itsi_server/src/services/rate_limiter.rs +609 -0
  117. data/ext/itsi_server/src/services/static_file_server.rs +1400 -0
  118. data/ext/itsi_tracing/Cargo.lock +274 -0
  119. data/ext/itsi_tracing/Cargo.toml +17 -0
  120. data/ext/itsi_tracing/src/lib.rs +370 -0
  121. data/itsi-scheduler-100.png +0 -0
  122. data/lib/itsi/schedule_refinement.rb +96 -0
  123. data/lib/itsi/scheduler/3.1/itsi_scheduler.so +0 -0
  124. data/lib/itsi/scheduler/3.2/itsi_scheduler.so +0 -0
  125. data/lib/itsi/scheduler/3.3/itsi_scheduler.so +0 -0
  126. data/lib/itsi/scheduler/3.4/itsi_scheduler.so +0 -0
  127. data/lib/itsi/scheduler/4.0/itsi_scheduler.so +0 -0
  128. data/lib/itsi/scheduler/native_extension.rb +34 -0
  129. data/lib/itsi/scheduler/version.rb +7 -0
  130. data/lib/itsi/scheduler.rb +153 -0
  131. data/vendor/rb-sys-build/.cargo-ok +1 -0
  132. data/vendor/rb-sys-build/.cargo_vcs_info.json +6 -0
  133. data/vendor/rb-sys-build/Cargo.lock +294 -0
  134. data/vendor/rb-sys-build/Cargo.toml +71 -0
  135. data/vendor/rb-sys-build/Cargo.toml.orig +32 -0
  136. data/vendor/rb-sys-build/LICENSE-APACHE +190 -0
  137. data/vendor/rb-sys-build/LICENSE-MIT +21 -0
  138. data/vendor/rb-sys-build/src/bindings/sanitizer.rs +185 -0
  139. data/vendor/rb-sys-build/src/bindings/stable_api.rs +247 -0
  140. data/vendor/rb-sys-build/src/bindings/wrapper.h +71 -0
  141. data/vendor/rb-sys-build/src/bindings.rs +280 -0
  142. data/vendor/rb-sys-build/src/cc.rs +421 -0
  143. data/vendor/rb-sys-build/src/lib.rs +12 -0
  144. data/vendor/rb-sys-build/src/rb_config/flags.rs +101 -0
  145. data/vendor/rb-sys-build/src/rb_config/library.rs +132 -0
  146. data/vendor/rb-sys-build/src/rb_config/search_path.rs +57 -0
  147. data/vendor/rb-sys-build/src/rb_config.rs +906 -0
  148. data/vendor/rb-sys-build/src/utils.rs +53 -0
  149. metadata +210 -0
@@ -0,0 +1,232 @@
1
+ use std::{ffi::c_int, os::raw::c_void, ptr::null_mut};
2
+
3
+ use magnus::{
4
+ block::Proc,
5
+ rb_sys::{protect, AsRawId, FromRawValue},
6
+ value::{IntoId, LazyId, ReprValue},
7
+ ArgList, RArray, Ruby, Thread, Value,
8
+ };
9
+ use rb_sys::{
10
+ rb_funcallv, rb_thread_call_with_gvl, rb_thread_call_without_gvl, rb_thread_create,
11
+ rb_thread_schedule, rb_thread_wakeup, VALUE,
12
+ };
13
+
14
+ mod heap_value;
15
+ pub use heap_value::{HeapVal, HeapValue};
16
+ static ID_FORK: LazyId = LazyId::new("fork");
17
+ static ID_LIST: LazyId = LazyId::new("list");
18
+ static ID_EQ: LazyId = LazyId::new("==");
19
+ static ID_ALIVE: LazyId = LazyId::new("alive?");
20
+ static ID_THREAD_VARIABLE_GET: LazyId = LazyId::new("thread_variable_get");
21
+ static ID_BACKTRACE: LazyId = LazyId::new("backtrace");
22
+
23
+ pub fn schedule_thread() {
24
+ unsafe {
25
+ rb_thread_schedule();
26
+ };
27
+ }
28
+ pub fn create_ruby_thread<F>(f: F) -> Option<Thread>
29
+ where
30
+ F: FnOnce() + Send + 'static,
31
+ {
32
+ extern "C" fn trampoline<F>(ptr: *mut c_void) -> u64
33
+ where
34
+ F: FnOnce(),
35
+ {
36
+ // Reconstruct the boxed Option<F> that holds our closure.
37
+ let boxed_closure: Box<Option<F>> = unsafe { Box::from_raw(ptr as *mut Option<F>) };
38
+ // Extract the closure. (The Option should be Some; panic otherwise.)
39
+ let closure = (*boxed_closure).expect("Closure already taken");
40
+ // Call the closure and return its result.
41
+ closure();
42
+ 0
43
+ }
44
+
45
+ // Box the closure (wrapped in an Option) to create a stable pointer.
46
+ let boxed_closure = Box::new(Some(f));
47
+ let ptr = Box::into_raw(boxed_closure) as *mut c_void;
48
+
49
+ // Call rb_thread_create with our trampoline and boxed closure.
50
+ unsafe {
51
+ let thread = rb_thread_create(Some(trampoline::<F>), ptr);
52
+ rb_thread_wakeup(thread);
53
+ rb_thread_schedule();
54
+ Thread::from_value(Value::from_raw(thread))
55
+ }
56
+ }
57
+
58
+ pub fn call_without_gvl<F, R>(f: F) -> R
59
+ where
60
+ F: FnOnce() -> R,
61
+ {
62
+ // This is the function that Ruby calls “in the background” with the GVL released.
63
+ extern "C" fn trampoline<F, R>(arg: *mut c_void) -> *mut c_void
64
+ where
65
+ F: FnOnce() -> R,
66
+ {
67
+ // 1) Reconstruct the Box that holds our closure
68
+ let closure_ptr = arg as *mut Option<F>;
69
+ let closure = unsafe { (*closure_ptr).take().expect("Closure already taken") };
70
+
71
+ // 2) Call the user’s closure
72
+ let result = closure();
73
+
74
+ // 3) Box up the result so we can return a pointer to it
75
+ let boxed_result = Box::new(result);
76
+ Box::into_raw(boxed_result) as *mut c_void
77
+ }
78
+
79
+ // Box up the closure so we have a stable pointer
80
+ let mut closure_opt = Some(f);
81
+ let closure_ptr = &mut closure_opt as *mut Option<F> as *mut c_void;
82
+
83
+ // 4) Actually call `rb_thread_call_without_gvl`
84
+ let raw_result_ptr = unsafe {
85
+ rb_thread_call_without_gvl(Some(trampoline::<F, R>), closure_ptr, None, null_mut())
86
+ };
87
+
88
+ // 5) Convert the returned pointer back into R
89
+ let result_box = unsafe { Box::from_raw(raw_result_ptr as *mut R) };
90
+ *result_box
91
+ }
92
+
93
+ pub fn call_with_gvl<F, R>(f: F) -> R
94
+ where
95
+ F: FnOnce(Ruby) -> R,
96
+ {
97
+ extern "C" fn trampoline<F, R>(arg: *mut c_void) -> *mut c_void
98
+ where
99
+ F: FnOnce(Ruby) -> R,
100
+ {
101
+ // 1) Reconstruct the Box that holds our closure
102
+ let closure_ptr = arg as *mut Option<F>;
103
+ let closure = unsafe { (*closure_ptr).take().expect("Closure already taken") };
104
+
105
+ // 2) Call the user’s closure
106
+ let result = closure(Ruby::get().unwrap());
107
+
108
+ // 3) Box up the result so we can return a pointer to it
109
+ let boxed_result = Box::new(result);
110
+ Box::into_raw(boxed_result) as *mut c_void
111
+ }
112
+
113
+ // Box up the closure so we have a stable pointer
114
+ let mut closure_opt = Some(f);
115
+ let closure_ptr = &mut closure_opt as *mut Option<F> as *mut c_void;
116
+
117
+ // 4) Actually call `rb_thread_call_without_gvl`
118
+ let raw_result_ptr = unsafe { rb_thread_call_with_gvl(Some(trampoline::<F, R>), closure_ptr) };
119
+
120
+ // 5) Convert the returned pointer back into R
121
+ let result_box = unsafe { Box::from_raw(raw_result_ptr as *mut R) };
122
+ *result_box
123
+ }
124
+
125
+ pub fn fork(after_fork: Option<HeapValue<Proc>>) -> Option<i32> {
126
+ let ruby = Ruby::get().unwrap();
127
+ let fork_result = ruby
128
+ .module_kernel()
129
+ .funcall::<_, _, Option<i32>>(*ID_FORK, ())
130
+ .ok()
131
+ .flatten();
132
+ if fork_result.is_none() {
133
+ if let Some(proc) = after_fork {
134
+ call_proc_and_log_errors(proc)
135
+ }
136
+ }
137
+ fork_result
138
+ }
139
+
140
+ pub fn call_proc_and_log_errors(proc: HeapValue<Proc>) {
141
+ if let Err(e) = proc.call::<_, Value>(()) {
142
+ if let Some(value) = e.value() {
143
+ print_rb_backtrace(value);
144
+ } else {
145
+ eprintln!("Error occurred {:?}", e);
146
+ }
147
+ }
148
+ }
149
+
150
+ pub fn kill_threads<T>(threads: Vec<T>)
151
+ where
152
+ T: ReprValue,
153
+ {
154
+ for thr in &threads {
155
+ let alive: bool = thr
156
+ .funcall(*ID_ALIVE, ())
157
+ .expect("Failed to check if thread is alive");
158
+ if !alive {
159
+ eprintln!("Thread killed");
160
+ break;
161
+ }
162
+ thr.funcall::<_, _, Value>("terminate", ())
163
+ .expect("Failed to kill thread");
164
+ }
165
+ }
166
+
167
+ pub fn terminate_non_fork_safe_threads() {
168
+ let ruby = Ruby::get().unwrap();
169
+ let thread_class = ruby.class_thread();
170
+ let current: Thread = ruby.thread_current();
171
+ let threads: RArray = thread_class
172
+ .funcall(*ID_LIST, ())
173
+ .expect("Failed to list Ruby threads");
174
+
175
+ let non_fork_safe_threads = threads
176
+ .into_iter()
177
+ .filter_map(|v| {
178
+ let v_thread = Thread::from_value(v).unwrap();
179
+ let non_fork_safe = !v_thread
180
+ .funcall::<_, _, bool>(*ID_EQ, (current,))
181
+ .unwrap_or(false)
182
+ && !v_thread
183
+ .funcall::<_, _, bool>(*ID_THREAD_VARIABLE_GET, (ruby.sym_new("fork_safe"),))
184
+ .unwrap_or(false);
185
+ if non_fork_safe {
186
+ Some(v_thread)
187
+ } else {
188
+ None
189
+ }
190
+ })
191
+ .collect::<Vec<_>>();
192
+
193
+ kill_threads(non_fork_safe_threads);
194
+ }
195
+
196
+ pub fn print_rb_backtrace(rb_err: Value) {
197
+ let backtrace = rb_err
198
+ .funcall::<_, _, Vec<String>>(*ID_BACKTRACE, ())
199
+ .unwrap_or_default();
200
+ let rust_backtrace = std::backtrace::Backtrace::capture().to_string();
201
+ eprintln!("Ruby exception {:?}", rb_err);
202
+ for line in backtrace {
203
+ eprintln!("{}", line);
204
+ }
205
+ for line in rust_backtrace.lines() {
206
+ eprintln!("{}", line);
207
+ }
208
+ }
209
+
210
+ pub fn funcall_no_ret<T, M, A>(target: T, method: M, args: A) -> magnus::error::Result<()>
211
+ where
212
+ T: ReprValue,
213
+ M: IntoId,
214
+ A: ArgList,
215
+ {
216
+ protect(|| {
217
+ let handle = Ruby::get().unwrap();
218
+ let method = method.into_id_with(&handle);
219
+ let args = args.into_arg_list_with(&handle);
220
+ let slice = args.as_ref();
221
+ unsafe {
222
+ rb_funcallv(
223
+ target.as_rb_value(),
224
+ method.as_raw(),
225
+ slice.len() as c_int,
226
+ slice.as_ptr() as *const VALUE,
227
+ );
228
+ }
229
+ 0
230
+ })?;
231
+ Ok(())
232
+ }
@@ -0,0 +1,24 @@
1
+ [package]
2
+ name = "itsi-scheduler"
3
+ version = "0.2.22"
4
+ edition = "2021"
5
+ authors = ["Wouter Coppieters <wc@pico.net.nz>"]
6
+ license = "MIT"
7
+ publish = false
8
+
9
+ [lib]
10
+ crate-type = ["cdylib"]
11
+
12
+ [dependencies]
13
+ magnus = { version = "0.8.2", features = ["rb-sys", "bytes"] }
14
+ derive_more = { version = "2.0.1", features = ["debug"] }
15
+ itsi_tracing = { path = "../itsi_tracing" }
16
+ itsi_rb_helpers = { path = "../itsi_rb_helpers" }
17
+ itsi_error = { path = "../itsi_error" }
18
+ itsi_instrument_entry = { path = "../itsi_instrument_entry" }
19
+ parking_lot = "0.12.3"
20
+ mio = { version = "1.0.3", features = ["os-poll", "os-ext"] }
21
+ rb-sys = "0.9.117"
22
+ bytes = "1.10.1"
23
+ nix = "0.29.0"
24
+ tracing = "0.1.41"
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+ require 'rb_sys/mkmf'
5
+
6
+ create_rust_makefile('itsi/scheduler/itsi_scheduler') do |r|
7
+ r.extra_rustflags = []
8
+ r.env = {
9
+ 'BINDGEN_EXTRA_CLANG_ARGS' => '-include stdbool.h -std=c99'
10
+ }
11
+ end
@@ -0,0 +1,56 @@
1
+ use std::os::fd::RawFd;
2
+
3
+ use itsi_error::{ItsiError, Result};
4
+ use mio::Interest;
5
+ use nix::libc::{fcntl, poll, pollfd, F_GETFL, F_SETFL, O_NONBLOCK};
6
+
7
+ use super::Readiness;
8
+
9
+ pub fn set_nonblocking(fd: RawFd) -> itsi_error::Result<()> {
10
+ unsafe {
11
+ let flags = fcntl(fd, F_GETFL);
12
+ if flags < 0 {
13
+ return Err(ItsiError::ArgumentError(format!(
14
+ "fcntl(F_GETFL) error for fd {}: {}",
15
+ fd,
16
+ std::io::Error::last_os_error()
17
+ )));
18
+ }
19
+ let new_flags = flags | O_NONBLOCK;
20
+ if fcntl(fd, F_SETFL, new_flags) < 0 {
21
+ return Err(ItsiError::ArgumentError(format!(
22
+ "fcntl(F_SETFL) error for fd {}: {}",
23
+ fd,
24
+ std::io::Error::last_os_error()
25
+ )));
26
+ }
27
+ }
28
+ Ok(())
29
+ }
30
+
31
+ pub fn poll_readiness(fd: RawFd, events: i16) -> Option<Readiness> {
32
+ let mut pfd = pollfd {
33
+ fd,
34
+ events,
35
+ revents: 0,
36
+ };
37
+ let ret = unsafe { poll(&mut pfd as *mut pollfd, 1, 0) };
38
+ if ret > 0 {
39
+ return Some(Readiness(pfd.revents));
40
+ }
41
+ None
42
+ }
43
+
44
+ pub fn build_interest(events: i16) -> Result<Interest> {
45
+ let mut interest_opt = None;
46
+ if events & 1 != 0 {
47
+ interest_opt = Some(Interest::READABLE);
48
+ }
49
+ if events & 4 != 0 {
50
+ interest_opt = Some(match interest_opt {
51
+ Some(i) => i | Interest::WRITABLE,
52
+ None => Interest::WRITABLE,
53
+ });
54
+ }
55
+ interest_opt.ok_or_else(|| ItsiError::ArgumentError("No valid event specified".to_owned()))
56
+ }
@@ -0,0 +1,44 @@
1
+ use derive_more::Debug;
2
+ use mio::{event::Source, unix::SourceFd, Interest, Token};
3
+ use std::os::fd::RawFd;
4
+
5
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
6
+ pub struct IoWaiter {
7
+ pub fd: RawFd,
8
+ pub readiness: i16,
9
+ pub token: Token,
10
+ }
11
+
12
+ impl IoWaiter {
13
+ pub fn new(fd: RawFd, readiness: i16, token: Token) -> Self {
14
+ Self {
15
+ fd,
16
+ readiness,
17
+ token,
18
+ }
19
+ }
20
+ }
21
+
22
+ impl Source for IoWaiter {
23
+ fn register(
24
+ &mut self,
25
+ registry: &mio::Registry,
26
+ token: Token,
27
+ interests: Interest,
28
+ ) -> std::io::Result<()> {
29
+ SourceFd(&self.fd).register(registry, token, interests)
30
+ }
31
+
32
+ fn reregister(
33
+ &mut self,
34
+ registry: &mio::Registry,
35
+ token: Token,
36
+ interests: Interest,
37
+ ) -> std::io::Result<()> {
38
+ SourceFd(&self.fd).reregister(registry, token, interests)
39
+ }
40
+
41
+ fn deregister(&mut self, registry: &mio::Registry) -> std::io::Result<()> {
42
+ SourceFd(&self.fd).deregister(registry)
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ use std::{
2
+ cmp::Ordering,
3
+ time::{Duration, Instant},
4
+ };
5
+
6
+ use mio::Token;
7
+
8
+ #[derive(Debug, Clone, PartialEq, Eq)]
9
+ pub struct Timer {
10
+ pub wake_time: Instant,
11
+ pub token: Token,
12
+ }
13
+ impl PartialOrd for Timer {
14
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
15
+ Some(self.cmp(other))
16
+ }
17
+ }
18
+
19
+ impl Ord for Timer {
20
+ fn cmp(&self, other: &Self) -> Ordering {
21
+ // Reverse the order: a timer with an earlier wake_time should be considered greater.
22
+ other
23
+ .wake_time
24
+ .cmp(&self.wake_time)
25
+ .then_with(|| other.token.cmp(&self.token))
26
+ }
27
+ }
28
+
29
+ impl Timer {
30
+ pub fn new(wake_in: Duration, token: Token) -> Self {
31
+ Self {
32
+ wake_time: Instant::now() + wake_in,
33
+ token,
34
+ }
35
+ }
36
+
37
+ pub fn is_due(&self) -> bool {
38
+ self.wake_time <= Instant::now()
39
+ }
40
+
41
+ pub(crate) fn duration(&self) -> Option<Duration> {
42
+ self.wake_time.checked_duration_since(Instant::now())
43
+ }
44
+ }